Merge.
Merge.
--- a/Makefile.in
+++ b/Makefile.in
@@ -171,43 +171,47 @@ endif
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
endif
ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
MAKE_SYM_STORE_ARGS := --vcs-info
DUMP_SYMS_BIN ?= $(DIST)/host/bin/dump_syms
MAKE_SYM_STORE_PATH := $(DIST)/bin
endif
+SYM_STORE_SOURCE_DIRS := $(topsrcdir)
+
+include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
+
ifdef MOZ_SYMBOLS_EXTRA_BUILDID
EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID)
endif
-SYMBOL_ARCHIVE_BASENAME = \
- $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_ARCH)-$(BUILDID)$(EXTRA_BUILDID)
+SYMBOL_INDEX_NAME = \
+ $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_ARCH)-$(BUILDID)$(EXTRA_BUILDID)-symbols.txt
buildsymbols:
ifdef MOZ_CRASHREPORTER
echo building symbol store
mkdir -p $(DIST)/crashreporter-symbols/$(BUILDID)
- $(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
- $(MAKE_SYM_STORE_ARGS) -s $(topsrcdir) $(DUMP_SYMS_BIN) \
- $(DIST)/crashreporter-symbols/$(BUILDID) \
- $(MAKE_SYM_STORE_PATH) > \
- $(DIST)/crashreporter-symbols/$(BUILDID)/$(SYMBOL_ARCHIVE_BASENAME)-symbols.txt
+ $(PYTHON) $(topsrcdir)/toolkit/crashreporter/tools/symbolstore.py \
+ $(MAKE_SYM_STORE_ARGS) \
+ $(foreach dir,$(SYM_STORE_SOURCE_DIRS),-s $(dir)) \
+ $(DUMP_SYMS_BIN) \
+ $(DIST)/crashreporter-symbols/$(BUILDID) \
+ $(MAKE_SYM_STORE_PATH) > \
+ $(DIST)/crashreporter-symbols/$(BUILDID)/$(SYMBOL_INDEX_NAME)
echo packing symbols
mkdir -p $(topsrcdir)/../$(BUILDID)
cd $(DIST)/crashreporter-symbols/$(BUILDID) && \
- zip -r9D ../crashreporter-symbols-$(SYMBOL_ARCHIVE_BASENAME).zip .
- mv $(DIST)/crashreporter-symbols/crashreporter-symbols-$(SYMBOL_ARCHIVE_BASENAME).zip \
- $(topsrcdir)/../$(BUILDID)
+ zip -r9D ../../$(SYMBOL_ARCHIVE_BASENAME).zip .
endif # MOZ_CRASHREPORTER
uploadsymbols:
ifdef MOZ_CRASHREPORTER
- $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(topsrcdir)/../$(BUILDID)/crashreporter-symbols-$(SYMBOL_ARCHIVE_BASENAME).zip
+ $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(DIST)/$(SYMBOL_ARCHIVE_BASENAME).zip
endif
ifeq ($(OS_ARCH),WINNT)
signnss:
ifdef MOZILLA_OFFICIAL
echo signing NSS libs
cd $(DIST)/bin; ./shlibsign.exe -v -i softokn3.dll
cd $(DIST)/bin; ./shlibsign.exe -v -i freebl3.dll
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -76,29 +76,29 @@ CPPSRCS = \
nsAccessNode.cpp \
nsAccessibleEventData.cpp \
nsARIAMap.cpp \
nsDocAccessible.cpp \
nsOuterDocAccessible.cpp \
nsAccessibilityAtoms.cpp \
nsCoreUtils.cpp \
nsAccUtils.cpp \
- nsNameUtils.cpp \
nsRelUtils.cpp \
nsAccessibilityService.cpp \
nsAccessible.cpp \
nsAccessibleRelation.cpp \
nsAccessibleTreeWalker.cpp \
nsBaseWidgetAccessible.cpp \
nsFormControlAccessible.cpp \
nsRootAccessible.cpp \
nsApplicationAccessible.cpp \
nsCaretAccessible.cpp \
nsTextAccessible.cpp \
- nsTextUtils.cpp \
+ nsTextEquivUtils.cpp \
+ nsTextAttrs.cpp \
$(NULL)
EXPORTS = \
nsRootAccessible.h \
nsAccessibleEventData.h \
nsAccessNode.h \
$(NULL)
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -60,470 +60,548 @@ static const nsStateMapEntry kEndEntry =
nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
{
{
"alert",
nsIAccessibleRole::ROLE_ALERT,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"alertdialog",
nsIAccessibleRole::ROLE_DIALOG,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"application",
nsIAccessibleRole::ROLE_APPLICATION,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"article",
nsIAccessibleRole::ROLE_DOCUMENT,
eNoValue,
eNoAction,
- kNoReqStates,
+ eNoLiveAttr,
+ nsIAccessibleStates::STATE_READONLY,
kEndEntry
},
{
"button",
nsIAccessibleRole::ROLE_PUSHBUTTON,
eNoValue,
eClickAction,
+ eNoLiveAttr,
kNoReqStates,
- {&nsAccessibilityAtoms::aria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED},
- {&nsAccessibilityAtoms::aria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED},
+ {&nsAccessibilityAtoms::aria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED | nsIAccessibleStates::STATE_CHECKABLE},
+ {&nsAccessibilityAtoms::aria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
kEndEntry
},
{
"checkbox",
nsIAccessibleRole::ROLE_CHECKBUTTON,
eNoValue,
eCheckUncheckAction,
+ eNoLiveAttr,
nsIAccessibleStates::STATE_CHECKABLE,
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
{&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED},
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
"columnheader",
nsIAccessibleRole::ROLE_COLUMNHEADER,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
"combobox",
nsIAccessibleRole::ROLE_COMBOBOX,
eHasValueMinMax,
eOpenCloseAction,
+ eNoLiveAttr,
nsIAccessibleStates::STATE_COLLAPSED | nsIAccessibleStates::STATE_HASPOPUP,
// Manually map EXT_STATE_SUPPORTS_AUTOCOMPLETION aria-autocomplete
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
"dialog",
nsIAccessibleRole::ROLE_DIALOG,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"document",
nsIAccessibleRole::ROLE_DOCUMENT,
eNoValue,
eNoAction,
- kNoReqStates,
+ eNoLiveAttr,
+ nsIAccessibleStates::STATE_READONLY,
kEndEntry
},
{
"grid",
nsIAccessibleRole::ROLE_TABLE,
eNoValue,
eNoAction,
+ eNoLiveAttr,
nsIAccessibleStates::STATE_FOCUSABLE,
{&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
"gridcell",
nsIAccessibleRole::ROLE_GRID_CELL,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
"group",
nsIAccessibleRole::ROLE_GROUPING,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"heading",
nsIAccessibleRole::ROLE_HEADING,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"img",
nsIAccessibleRole::ROLE_GRAPHIC,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"label",
nsIAccessibleRole::ROLE_LABEL,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"link",
nsIAccessibleRole::ROLE_LINK,
eNoValue,
eJumpAction,
+ eNoLiveAttr,
nsIAccessibleStates::STATE_LINKED,
kEndEntry
},
{
"list",
nsIAccessibleRole::ROLE_LIST,
eNoValue,
eNoAction,
+ eNoLiveAttr,
nsIAccessibleStates::STATE_READONLY,
{&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
kEndEntry
},
{
"listbox",
nsIAccessibleRole::ROLE_LISTBOX,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
{&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
kEndEntry
},
{
"listitem",
nsIAccessibleRole::ROLE_LISTITEM,
eNoValue,
eNoAction, // XXX: should depend on state, parent accessible
+ eNoLiveAttr,
nsIAccessibleStates::STATE_READONLY,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
{&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
{&nsAccessibilityAtoms::aria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},
kEndEntry
},
{
+ "log",
+ nsIAccessibleRole::ROLE_NOTHING,
+ eNoValue,
+ eNoAction,
+ ePoliteLiveAttr,
+ kNoReqStates,
+ kEndEntry
+ },
+ {
+ "marquee",
+ nsIAccessibleRole::ROLE_NOTHING,
+ eNoValue,
+ eNoAction,
+ eOffLiveAttr,
+ kNoReqStates,
+ kEndEntry
+ },
+ {
"math",
nsIAccessibleRole::ROLE_FLAT_EQUATION,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"menu",
nsIAccessibleRole::ROLE_MENUPOPUP,
eNoValue,
eNoAction, // XXX: technically accessibles of menupopup role haven't
// any action, but menu can be open or close.
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"menubar",
nsIAccessibleRole::ROLE_MENUBAR,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"menuitem",
nsIAccessibleRole::ROLE_MENUITEM,
eNoValue,
eClickAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
{&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
{&nsAccessibilityAtoms::aria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},
kEndEntry
},
{
"menuitemcheckbox",
nsIAccessibleRole::ROLE_CHECK_MENU_ITEM,
eNoValue,
eClickAction,
+ eNoLiveAttr,
nsIAccessibleStates::STATE_CHECKABLE,
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED },
{&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED},
kEndEntry
},
{
"menuitemradio",
nsIAccessibleRole::ROLE_RADIO_MENU_ITEM,
eNoValue,
eClickAction,
+ eNoLiveAttr,
nsIAccessibleStates::STATE_CHECKABLE,
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED },
kEndEntry
},
{
"option",
nsIAccessibleRole::ROLE_OPTION,
eNoValue,
eSelectAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
{&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
{&nsAccessibilityAtoms::aria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},
kEndEntry
},
{
"presentation",
nsIAccessibleRole::ROLE_NOTHING,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"progressbar",
nsIAccessibleRole::ROLE_PROGRESSBAR,
eHasValueMinMax,
eNoAction,
+ eNoLiveAttr,
nsIAccessibleStates::STATE_READONLY,
kEndEntry
},
{
"radio",
nsIAccessibleRole::ROLE_RADIOBUTTON,
eNoValue,
eSelectAction,
- kNoReqStates,
+ eNoLiveAttr,
+ nsIAccessibleStates::STATE_CHECKABLE,
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
kEndEntry
},
{
"radiogroup",
nsIAccessibleRole::ROLE_GROUPING,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"region",
nsIAccessibleRole::ROLE_PANE,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"row",
nsIAccessibleRole::ROLE_ROW,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
kEndEntry
},
{
"rowheader",
nsIAccessibleRole::ROLE_ROWHEADER,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
"section",
nsIAccessibleRole::ROLE_SECTION,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"separator",
nsIAccessibleRole::ROLE_SEPARATOR,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"slider",
nsIAccessibleRole::ROLE_SLIDER,
eHasValueMinMax,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
"spinbutton",
nsIAccessibleRole::ROLE_SPINBUTTON,
eHasValueMinMax,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
"status",
nsIAccessibleRole::ROLE_STATUSBAR,
eNoValue,
eNoAction,
+ ePoliteLiveAttr,
kNoReqStates,
kEndEntry
},
{
"tab",
nsIAccessibleRole::ROLE_PAGETAB,
eNoValue,
eSwitchAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"tablist",
nsIAccessibleRole::ROLE_PAGETABLIST,
eNoValue,
eNoAction,
+ ePoliteLiveAttr,
kNoReqStates,
kEndEntry
},
{
"tabpanel",
nsIAccessibleRole::ROLE_PROPERTYPAGE,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"textbox",
nsIAccessibleRole::ROLE_ENTRY,
eNoValue,
eActivateAction,
+ eNoLiveAttr,
kNoReqStates,
// Manually map EXT_STATE_SINGLE_LINE and EXT_STATE_MULTI_LINE FROM aria-multiline
// Manually map EXT_STATE_SUPPORTS_AUTOCOMPLETION aria-autocomplete
{&nsAccessibilityAtoms::aria_autocomplete, "list", nsIAccessibleStates::STATE_HASPOPUP},
{&nsAccessibilityAtoms::aria_autocomplete, "both", nsIAccessibleStates::STATE_HASPOPUP},
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
kEndEntry
},
{
+ "timer",
+ nsIAccessibleRole::ROLE_NOTHING,
+ eNoValue,
+ eNoAction,
+ eOffLiveAttr,
+ kNoReqStates,
+ kEndEntry
+ },
+ {
"toolbar",
nsIAccessibleRole::ROLE_TOOLBAR,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"tooltip",
nsIAccessibleRole::ROLE_TOOLTIP,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
},
{
"tree",
nsIAccessibleRole::ROLE_OUTLINE,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
{&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
kEndEntry
},
{
"treegrid",
nsIAccessibleRole::ROLE_TREE_TABLE,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
{&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
kEndEntry
},
{
"treeitem",
nsIAccessibleRole::ROLE_OUTLINEITEM,
eNoValue,
eActivateAction, // XXX: should expose second 'expand/collapse' action based
// on states
+ eNoLiveAttr,
kNoReqStates,
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED | nsIAccessibleStates::STATE_CHECKABLE},
{&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED | nsIAccessibleStates::STATE_CHECKABLE},
{&nsAccessibilityAtoms::aria_checked, "false", nsIAccessibleStates::STATE_CHECKABLE},
- },
+ kEndEntry
+ }
};
PRUint32 nsARIAMap::gWAIRoleMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIRoleMap);
nsRoleMapEntry nsARIAMap::gLandmarkRoleMap = {
"",
nsIAccessibleRole::ROLE_NOTHING,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
};
nsRoleMapEntry nsARIAMap::gEmptyRoleMap = {
"",
nsIAccessibleRole::ROLE_NOTHING,
eNoValue,
eNoAction,
+ eNoLiveAttr,
kNoReqStates,
kEndEntry
};
/**
* Universal states:
* The following state rules are applied to any accessible element,
* whether there is an ARIA role or not:
@@ -535,8 +613,46 @@ nsStateMapEntry nsARIAMap::gWAIUnivState
{&nsAccessibilityAtoms::aria_busy, "true", nsIAccessibleStates::STATE_BUSY},
{&nsAccessibilityAtoms::aria_busy, "error", nsIAccessibleStates::STATE_INVALID},
{&nsAccessibilityAtoms::aria_disabled, kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
{&nsAccessibilityAtoms::aria_expanded, kBoolState, nsIAccessibleStates::STATE_EXPANDED},
{&nsAccessibilityAtoms::aria_expanded, "false", nsIAccessibleStates::STATE_COLLAPSED},
kEndEntry
};
+
+/**
+ * ARIA attribute map for attribute characteristics
+ *
+ * @note ARIA attributes that don't have any flags are not included here
+ */
+nsAttributeCharacteristics nsARIAMap::gWAIUnivAttrMap[] = {
+ {&nsAccessibilityAtoms::aria_activedescendant, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_atomic, ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_busy, ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_checked, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_controls, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_describedby, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_disabled, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_dropeffect, ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_expanded, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_flowto, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_grabbed, ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_haspopup, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_invalid, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_labelledby, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_live, ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_multiline, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_multiselectable, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_owns, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_pressed, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_readonly, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_relevant, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_required, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_selected, ATTR_EXPOSEOBJ | ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_sort, ATTR_VALTOKEN },
+ {&nsAccessibilityAtoms::aria_valuenow, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_valuemin, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_valuemax, ATTR_EXPOSEOBJ },
+ {&nsAccessibilityAtoms::aria_valuetext, ATTR_EXPOSEOBJ }
+};
+
+PRUint32 nsARIAMap::gWAIUnivAttrMapLength = NS_ARRAY_LENGTH(nsARIAMap::gWAIUnivAttrMap);
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -58,46 +58,79 @@ enum EActionRule
eClickAction,
eCheckUncheckAction,
eJumpAction,
eOpenCloseAction,
eSelectAction,
eSwitchAction
};
+enum ELiveAttrRule
+{
+ eNoLiveAttr,
+ eOffLiveAttr,
+ ePoliteLiveAttr
+};
+
+// ARIA attribute characteristic masks, grow as needed
+
+/**
+ * This mask indicates the attribute should be exposed as an object attribute,
+ * used to expose semantics not traditionally found in a11y APIs.
+ * (See for example usage in nsAccessible::GetAttributes)
+ */
+const PRUint8 ATTR_EXPOSEOBJ = 0x0001;
+
+/**
+ * This mask indicates the attribute is expected to have an NMTOKEN or bool value.
+ * (See for example usage in nsAccessible::GetAttributes)
+ */
+const PRUint8 ATTR_VALTOKEN = 0x0010;
+
// Used for an nsStateMapEntry if a given state attribute supports "true" and "false"
#define kBoolState 0
// Used in nsRoleMapEntry.state if no nsIAccessibleStates are automatic for a given role
#define kNoReqStates 0
// For this name and value pair, what is the nsIAccessibleStates mapping.
// nsStateMapEntry.state
struct nsStateMapEntry
{
nsIAtom** attributeName; // nsnull indicates last entry in map
const char* attributeValue; // magic value of kBoolState (0) means supports "true" and "false"
PRUint32 state; // If match, this is the nsIAccessibleStates to map to
};
+// Small footprint storage of persistent aria attribute characteristics
+struct nsAttributeCharacteristics
+{
+ nsIAtom** attributeName;
+ const PRUint8 characteristics;
+};
+
// For each ARIA role, this maps the nsIAccessible information
struct nsRoleMapEntry
{
// ARIA role: string representation such as "button"
const char *roleString;
// Role mapping rule: maps to this nsIAccessibleRole
PRUint32 role;
// Value mapping rule: how to compute nsIAccessible value
EValueRule valueRule;
// Action mapping rule, how to expose nsIAccessible action
EActionRule actionRule;
+ // 'live' and 'container-live' object attributes mapping rule: how to expose
+ // these object attributes if ARIA 'live' attribute is missed.
+ ELiveAttrRule liveAttRule;
+
// Automatic state mapping rule: always include in nsIAccessibleStates
PRUint32 state; // or kNoReqStates if no nsIAccessibleStates are automatic for this role.
// ARIA properties supported for this role
// (in other words, the aria-foo attribute to nsIAccessibleStates mapping rules)
// Currently you cannot have unlimited mappings, because
// a variable sized array would not allow the use of
// C++'s struct initialization feature.
@@ -137,11 +170,17 @@ struct nsARIAMap
*/
static nsRoleMapEntry gEmptyRoleMap;
/**
* State map of ARIA states applied to any accessible not depending on
* the role.
*/
static nsStateMapEntry gWAIUnivStateMap[];
+
+ /**
+ * Map of attribute to attribute characteristics.
+ */
+ static nsAttributeCharacteristics gWAIUnivAttrMap[];
+ static PRUint32 gWAIUnivAttrMapLength;
};
#endif
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -267,73 +267,63 @@ nsAccUtils::SetAccAttrsForXULContainerIt
void
nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
nsIContent *aStartContent,
nsIContent *aTopContent)
{
nsAutoString atomic, live, relevant, busy;
nsIContent *ancestor = aStartContent;
while (ancestor) {
+
+ // container-relevant attribute
if (relevant.IsEmpty() &&
nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_relevant) &&
ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_relevant, relevant))
SetAccAttr(aAttributes, nsAccessibilityAtoms::containerRelevant, relevant);
- if (live.IsEmpty() &&
- nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_live) &&
- ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live, live))
- SetAccAttr(aAttributes, nsAccessibilityAtoms::containerLive, live);
+ // container-live attribute
+ if (live.IsEmpty()) {
+ if (nsAccUtils::HasDefinedARIAToken(ancestor,
+ nsAccessibilityAtoms::aria_live)) {
+ ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_live,
+ live);
+ SetAccAttr(aAttributes, nsAccessibilityAtoms::containerLive, live);
+ } else {
+ nsCOMPtr<nsIDOMNode> node(do_QueryInterface(ancestor));
+ nsRoleMapEntry *role = GetRoleMapEntry(node);
+ if (role) {
+ nsAutoString live;
+ GetLiveAttrValue(role->liveAttRule, live);
+ SetAccAttr(aAttributes, nsAccessibilityAtoms::containerLive, live);
+ }
+ }
+ }
+ // container-atomic attribute
if (atomic.IsEmpty() &&
nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_atomic) &&
ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_atomic, atomic))
SetAccAttr(aAttributes, nsAccessibilityAtoms::containerAtomic, atomic);
+ // container-busy attribute
if (busy.IsEmpty() &&
nsAccUtils::HasDefinedARIAToken(ancestor, nsAccessibilityAtoms::aria_busy) &&
ancestor->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_busy, busy))
SetAccAttr(aAttributes, nsAccessibilityAtoms::containerBusy, busy);
if (ancestor == aTopContent)
break;
ancestor = ancestor->GetParent();
if (!ancestor)
ancestor = aTopContent; // Use <body>/<frameset>
}
}
PRBool
-nsAccUtils::IsARIAPropForObjectAttr(nsIAtom *aAtom)
-{
- return aAtom != nsAccessibilityAtoms::aria_activedescendant &&
- aAtom != nsAccessibilityAtoms::aria_checked &&
- aAtom != nsAccessibilityAtoms::aria_controls &&
- aAtom != nsAccessibilityAtoms::aria_describedby &&
- aAtom != nsAccessibilityAtoms::aria_disabled &&
- aAtom != nsAccessibilityAtoms::aria_expanded &&
- aAtom != nsAccessibilityAtoms::aria_flowto &&
- aAtom != nsAccessibilityAtoms::aria_invalid &&
- aAtom != nsAccessibilityAtoms::aria_haspopup &&
- aAtom != nsAccessibilityAtoms::aria_labelledby &&
- aAtom != nsAccessibilityAtoms::aria_multiline &&
- aAtom != nsAccessibilityAtoms::aria_multiselectable &&
- aAtom != nsAccessibilityAtoms::aria_owns &&
- aAtom != nsAccessibilityAtoms::aria_pressed &&
- aAtom != nsAccessibilityAtoms::aria_readonly &&
- aAtom != nsAccessibilityAtoms::aria_relevant &&
- aAtom != nsAccessibilityAtoms::aria_required &&
- aAtom != nsAccessibilityAtoms::aria_selected &&
- aAtom != nsAccessibilityAtoms::aria_valuemax &&
- aAtom != nsAccessibilityAtoms::aria_valuemin &&
- aAtom != nsAccessibilityAtoms::aria_valuenow &&
- aAtom != nsAccessibilityAtoms::aria_valuetext;
-}
-
-PRBool
nsAccUtils::HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom)
{
if (!aContent->HasAttr(kNameSpaceID_None, aAtom) ||
aContent->AttrValueIs(kNameSpaceID_None, aAtom,
nsAccessibilityAtoms::_empty, eCaseMatters) ||
aContent->AttrValueIs(kNameSpaceID_None, aAtom,
nsAccessibilityAtoms::_undefined, eCaseMatters)) {
return PR_FALSE;
@@ -681,16 +671,38 @@ nsAccUtils::GetRoleMapEntry(nsIDOMNode *
}
}
// Always use some entry if there is a role string
// To ensure an accessible object is created
return &nsARIAMap::gLandmarkRoleMap;
}
+PRUint8
+nsAccUtils::GetAttributeCharacteristics(nsIAtom* aAtom)
+{
+ for (PRUint32 i = 0; i < nsARIAMap::gWAIUnivAttrMapLength; i++)
+ if (*nsARIAMap::gWAIUnivAttrMap[i].attributeName == aAtom)
+ return nsARIAMap::gWAIUnivAttrMap[i].characteristics;
+
+ return 0;
+}
+
+void
+nsAccUtils::GetLiveAttrValue(PRUint32 aRule, nsAString& aValue)
+{
+ switch (aRule) {
+ case eOffLiveAttr:
+ aValue = NS_LITERAL_STRING("off");
+ break;
+ case ePoliteLiveAttr:
+ aValue = NS_LITERAL_STRING("polite");
+ break;
+ }
+}
#ifdef DEBUG_A11Y
PRBool
nsAccUtils::IsTextInterfaceSupportCorrect(nsIAccessible *aAccessible)
{
PRBool foundText = PR_FALSE;
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -126,22 +126,16 @@ public:
* @param aStartContent node to start from
* @param aTopContent node to end at
*/
static void SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
nsIContent *aStartContent,
nsIContent *aTopContent);
/**
- * Return PR_TRUE if the ARIA property should always be exposed as an object
- * attribute.
- */
- static PRBool IsARIAPropForObjectAttr(nsIAtom *aAtom);
-
- /**
* Any ARIA property of type boolean or NMTOKEN is undefined if the ARIA
* property is not present, or is "" or "undefined". Do not call
* this method for properties of type string, decimal, IDREF or IDREFS.
*
* Return PR_TRUE if the ARIA property is defined, otherwise PR_FALSE
*/
static PRBool HasDefinedARIAToken(nsIContent *aContent, nsIAtom *aAtom);
@@ -263,16 +257,31 @@ public:
PRUint32 state = 0;
if (aAcc)
aAcc->GetState(&state, nsnull);
return state;
}
/**
+ * Get the ARIA attribute characteristics for a given ARIA attribute.
+ *
+ * @param aAtom ARIA attribute
+ * @return A bitflag representing the attribute characteristics
+ * (see nsARIAMap.h for possible bit masks, prefixed "ARIA_")
+ */
+ static PRUint8 GetAttributeCharacteristics(nsIAtom* aAtom);
+
+ /**
+ * Return the 'live' or 'container-live' object attribute value from the given
+ * ELiveAttrRule constant.
+ */
+ static void GetLiveAttrValue(PRUint32 aRule, nsAString& aValue);
+
+ /**
* Query nsAccessNode from the given nsIAccessible.
*/
static already_AddRefed<nsAccessNode>
QueryAccessNode(nsIAccessible *aAccessible)
{
nsAccessNode* accessNode = nsnull;
if (aAccessible)
CallQueryInterface(aAccessible, &accessNode);
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -183,25 +183,33 @@ ACCESSIBILITY_ATOM(selected, "selected")
ACCESSIBILITY_ATOM(summary, "summary")
ACCESSIBILITY_ATOM(tabindex, "tabindex")
ACCESSIBILITY_ATOM(title, "title")
ACCESSIBILITY_ATOM(tooltiptext, "tooltiptext")
ACCESSIBILITY_ATOM(type, "type")
ACCESSIBILITY_ATOM(value, "value")
// Alphabetical list of object attributes
+ACCESSIBILITY_ATOM(checkable, "checkable")
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")
@@ -244,11 +252,12 @@ ACCESSIBILITY_ATOM(defaultLabel, "defaul
// Object attributes
ACCESSIBILITY_ATOM(tableCellIndex, "table-cell-index")
ACCESSIBILITY_ATOM(containerAtomic, "container-atomic")
ACCESSIBILITY_ATOM(containerBusy, "container-busy")
ACCESSIBILITY_ATOM(containerLive, "container-live")
ACCESSIBILITY_ATOM(containerRelevant, "container-relevant")
ACCESSIBILITY_ATOM(level, "level")
+ACCESSIBILITY_ATOM(live, "live")
ACCESSIBILITY_ATOM(lineNumber, "line-number")
ACCESSIBILITY_ATOM(posinset, "posinset")
ACCESSIBILITY_ATOM(setsize, "setsize")
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -35,17 +35,16 @@
* 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 "nsAccessible.h"
#include "nsAccessibleRelation.h"
#include "nsHyperTextAccessibleWrap.h"
-#include "nsNameUtils.h"
#include "nsIAccessibleDocument.h"
#include "nsIAccessibleHyperText.h"
#include "nsAccessibleTreeWalker.h"
#include "nsIDOMElement.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentXBL.h"
@@ -324,29 +323,32 @@ NS_IMETHODIMP nsAccessible::GetDescripti
// 3. it doesn't have an accName; or
// 4. its title attribute already equals to its accName nsAutoString name;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (!content) {
return NS_ERROR_FAILURE; // Node shut down
}
if (!content->IsNodeOfType(nsINode::eTEXT)) {
nsAutoString description;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
+ nsresult rv = nsTextEquivUtils::
+ GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
+ description);
if (NS_FAILED(rv)) {
PRBool isXUL = content->IsNodeOfType(nsINode::eXUL);
if (isXUL) {
// Try XUL <description control="[id]">description text</description>
nsIContent *descriptionContent =
nsCoreUtils::FindNeighbourPointingToNode(content,
nsAccessibilityAtoms::control,
nsAccessibilityAtoms::description);
if (descriptionContent) {
// We have a description content node
- AppendFlatStringFromSubtree(descriptionContent, &description);
+ nsTextEquivUtils::
+ AppendTextEquivFromContent(this, descriptionContent, &description);
}
}
if (description.IsEmpty()) {
nsIAtom *descAtom = isXUL ? nsAccessibilityAtoms::tooltiptext :
nsAccessibilityAtoms::title;
if (content->GetAttr(kNameSpaceID_None, descAtom, description)) {
nsAutoString name;
GetName(name);
@@ -1451,330 +1453,40 @@ nsAccessible::TakeFocus()
// in order to affect tabbing order
return htmlElement->Focus();
}
content->SetFocus(GetPresContext());
return NS_OK;
}
-nsresult nsAccessible::AppendStringWithSpaces(nsAString *aFlatString, const nsAString& textEquivalent)
-{
- // Insert spaces to insure that words from controls aren't jammed together
- if (!textEquivalent.IsEmpty()) {
- if (!aFlatString->IsEmpty())
- aFlatString->Append(PRUnichar(' '));
- aFlatString->Append(textEquivalent);
- aFlatString->Append(PRUnichar(' '));
- }
- return NS_OK;
-}
-
-nsresult nsAccessible::AppendNameFromAccessibleFor(nsIContent *aContent,
- nsAString *aFlatString,
- PRBool aFromValue)
-{
- nsAutoString textEquivalent, value;
-
- nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(aContent));
- nsCOMPtr<nsIAccessible> accessible;
- if (domNode == mDOMNode) {
- accessible = this;
- if (!aFromValue) {
- // prevent recursive call GetName()
- return NS_OK;
- }
- }
- else {
- nsCOMPtr<nsIAccessibilityService> accService =
- do_GetService("@mozilla.org/accessibilityService;1");
- NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
- accService->GetAccessibleInWeakShell(domNode, mWeakShell, getter_AddRefs(accessible));
- }
- if (accessible) {
- if (aFromValue) {
- accessible->GetValue(textEquivalent);
- }
- else {
- accessible->GetName(textEquivalent);
- }
- }
-
- textEquivalent.CompressWhitespace();
- return AppendStringWithSpaces(aFlatString, textEquivalent);
-}
-
-/*
- * AppendFlatStringFromContentNode and AppendFlatStringFromSubtree
- *
- * This method will glean useful text, in whatever form it exists, from any content node given to it.
- * It is used by any decendant of nsAccessible that needs to get text from a single node, as
- * well as by nsAccessible::AppendFlatStringFromSubtree, which gleans and concatenates text from any node and
- * that node's decendants.
- */
-
-nsresult nsAccessible::AppendFlatStringFromContentNode(nsIContent *aContent, nsAString *aFlatString)
-{
- if (aContent->IsNodeOfType(nsINode::eTEXT)) {
- // If it's a text node, append the text
- PRBool isHTMLBlock = PR_FALSE;
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- if (!shell) {
- return NS_ERROR_FAILURE;
- }
-
- nsIContent *parentContent = aContent->GetParent();
- nsCOMPtr<nsIContent> appendedSubtreeStart(do_QueryInterface(mDOMNode));
- if (parentContent && parentContent != appendedSubtreeStart) {
- nsIFrame *frame = shell->GetPrimaryFrameFor(parentContent);
- if (frame) {
- // If this text is inside a block level frame (as opposed to span level), we need to add spaces around that
- // block's text, so we don't get words jammed together in final name
- // Extra spaces will be trimmed out later
- const nsStyleDisplay* display = frame->GetStyleDisplay();
- if (display->IsBlockOutside() ||
- display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
- isHTMLBlock = PR_TRUE;
- if (!aFlatString->IsEmpty()) {
- aFlatString->Append(PRUnichar(' '));
- }
- }
- }
- }
- if (aContent->TextLength() > 0) {
- nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
- if (frame) {
- nsresult rv = frame->GetRenderedText(aFlatString);
- NS_ENSURE_SUCCESS(rv, rv);
- } else {
- //if aContent is an object that is display: none, we have no a frame
- aContent->AppendTextTo(*aFlatString);
- }
- if (isHTMLBlock && !aFlatString->IsEmpty()) {
- aFlatString->Append(PRUnichar(' '));
- }
- }
- return NS_OK;
- }
-
- nsAutoString textEquivalent;
- if (!aContent->IsNodeOfType(nsINode::eHTML)) {
- if (aContent->IsNodeOfType(nsINode::eXUL)) {
- nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl(do_QueryInterface(aContent));
- if (labeledEl) {
- labeledEl->GetLabel(textEquivalent);
- }
- else {
- if (aContent->NodeInfo()->Equals(nsAccessibilityAtoms::label, kNameSpaceID_XUL)) {
- aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value, textEquivalent);
- }
- if (textEquivalent.IsEmpty()) {
- aContent->GetAttr(kNameSpaceID_None,
- nsAccessibilityAtoms::tooltiptext, textEquivalent);
- }
- }
- AppendNameFromAccessibleFor(aContent, &textEquivalent, PR_TRUE /* use value */);
-
- return AppendStringWithSpaces(aFlatString, textEquivalent);
- }
- return NS_OK; // Not HTML and not XUL -- we don't handle it yet
- }
-
- nsCOMPtr<nsIAtom> tag = aContent->Tag();
- if (tag == nsAccessibilityAtoms::img) {
- return AppendNameFromAccessibleFor(aContent, aFlatString);
- }
-
- if (tag == nsAccessibilityAtoms::input) {
- static nsIContent::AttrValuesArray strings[] =
- {&nsAccessibilityAtoms::button, &nsAccessibilityAtoms::submit,
- &nsAccessibilityAtoms::reset, &nsAccessibilityAtoms::image, nsnull};
- if (aContent->FindAttrValueIn(kNameSpaceID_None, nsAccessibilityAtoms::type,
- strings, eIgnoreCase) >= 0) {
- return AppendNameFromAccessibleFor(aContent, aFlatString);
- }
- }
-
- if (tag == nsAccessibilityAtoms::object && !aContent->GetChildCount()) {
- // If object has no alternative content children, try title
- aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, textEquivalent);
- }
- else if (tag == nsAccessibilityAtoms::br) {
- // If it's a line break, insert a space so that words aren't jammed together
- aFlatString->AppendLiteral("\r\n");
- return NS_OK;
- }
- else if (tag != nsAccessibilityAtoms::a && tag != nsAccessibilityAtoms::area) {
- AppendNameFromAccessibleFor(aContent, aFlatString, PR_TRUE /* use value */);
- }
-
- textEquivalent.CompressWhitespace();
- return AppendStringWithSpaces(aFlatString, textEquivalent);
-}
-
-
-nsresult nsAccessible::AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString)
-{
- static PRBool isAlreadyHere; // Prevent recursion which can cause infinite loops
- if (isAlreadyHere) {
- return NS_OK;
- }
-
- isAlreadyHere = PR_TRUE;
-
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
-
- nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
- PRBool isHidden = (!frame || !frame->GetStyleVisibility()->IsVisible());
- nsresult rv = AppendFlatStringFromSubtreeRecurse(aContent, aFlatString,
- isHidden);
-
- isAlreadyHere = PR_FALSE;
-
- if (NS_SUCCEEDED(rv) && !aFlatString->IsEmpty()) {
- nsAString::const_iterator start, end;
- aFlatString->BeginReading(start);
- aFlatString->EndReading(end);
-
- PRInt32 spacesToTruncate = 0;
- while (-- end != start && *end == ' ')
- ++ spacesToTruncate;
-
- if (spacesToTruncate > 0)
- aFlatString->Truncate(aFlatString->Length() - spacesToTruncate);
- }
-
- return rv;
-}
-
-nsresult
-nsAccessible::AppendFlatStringFromSubtreeRecurse(nsIContent *aContent,
- nsAString *aFlatString,
- PRBool aIsRootHidden)
-{
- // Depth first search for all text nodes that are decendants of content node.
- // Append all the text into one flat string
- PRUint32 numChildren = 0;
- nsCOMPtr<nsIDOMXULSelectControlElement> selectControlEl(do_QueryInterface(aContent));
- nsCOMPtr<nsIAtom> tag = aContent->Tag();
-
- if (!selectControlEl &&
- tag != nsAccessibilityAtoms::textarea &&
- tag != nsAccessibilityAtoms::select) {
- // Don't walk children of elements with options, just get label directly.
- // Don't traverse the children of a textarea, we want the value, not the
- // static text node.
- // Don't traverse the children of a select element, we only want the
- // current value.
- numChildren = aContent->GetChildCount();
- }
-
- if (numChildren == 0) {
- // There are no children or they are irrelvant: get the text from the current node
- AppendFlatStringFromContentNode(aContent, aFlatString);
- return NS_OK;
- }
-
- // There are relevant children: use them to get the text.
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
-
- PRUint32 index;
- for (index = 0; index < numChildren; index++) {
- nsCOMPtr<nsIContent> childContent = aContent->GetChildAt(index);
-
- // Walk into hidden subtree if the the root parent is also hidden. This
- // happens when the author explictly uses a hidden label or description.
- if (!aIsRootHidden) {
- nsIFrame *childFrame = shell->GetPrimaryFrameFor(childContent);
- if (!childFrame || !childFrame->GetStyleVisibility()->IsVisible())
- continue;
- }
-
- AppendFlatStringFromSubtreeRecurse(childContent, aFlatString,
- aIsRootHidden);
- }
-
- return NS_OK;
-}
-
-nsresult nsAccessible::GetTextFromRelationID(nsIAtom *aIDProperty, nsString &aName)
-{
- // Get DHTML name from content subtree pointed to by ID attribute
- aName.Truncate();
- NS_ASSERTION(mDOMNode, "Called from shutdown accessible");
-
- nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
- if (!content)
- return NS_OK;
-
- nsCOMPtr<nsIArray> refElms;
- nsCoreUtils::GetElementsByIDRefsAttr(content, aIDProperty,
- getter_AddRefs(refElms));
-
- if (!refElms)
- return NS_OK;
-
- PRUint32 count = 0;
- nsresult rv = refElms->GetLength(&count);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsCOMPtr<nsIContent> refContent;
- for (PRUint32 idx = 0; idx < count; idx++) {
- refContent = do_QueryElementAt(refElms, idx, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!aName.IsEmpty())
- aName += ' '; // Need whitespace between multiple labels or descriptions
-
- rv = AppendFlatStringFromSubtree(refContent, &aName);
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
- aName.CompressWhitespace();
- return NS_OK;
-}
-
nsresult
nsAccessible::GetHTMLName(nsAString& aLabel)
{
nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
if (!content) {
aLabel.SetIsVoid(PR_TRUE);
return NS_OK;
}
nsIContent *labelContent = nsCoreUtils::GetHTMLLabelContent(content);
if (labelContent) {
nsAutoString label;
- nsresult rv = AppendFlatStringFromSubtree(labelContent, &label);
+ nsresult rv =
+ nsTextEquivUtils::AppendTextEquivFromContent(this, labelContent, &label);
NS_ENSURE_SUCCESS(rv, rv);
label.CompressWhitespace();
if (!label.IsEmpty()) {
aLabel = label;
return NS_OK;
}
}
- PRUint32 role = nsAccUtils::Role(this);
- PRUint32 canAggregateName =
- nsNameUtils::gRoleToNameRulesMap[role] & eFromSubtree;
-
- if (canAggregateName) {
- // Don't use AppendFlatStringFromSubtree for container widgets like menulist
- nsresult rv = AppendFlatStringFromSubtree(content, &aLabel);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!aLabel.IsEmpty())
- return NS_OK;
- }
-
- return NS_OK;
+ return nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
}
/**
* 3 main cases for XUL Controls to be labeled
* 1 - control contains label="foo"
* 2 - control has, as a child, a label element
* - label has either value="foo" or children
* 3 - non-child label contains control="controlID"
@@ -1824,17 +1536,17 @@ nsAccessible::GetXULName(nsAString& aLab
nsCoreUtils::FindNeighbourPointingToNode(content, nsAccessibilityAtoms::control,
nsAccessibilityAtoms::label);
nsCOMPtr<nsIDOMXULLabelElement> xulLabel(do_QueryInterface(labelContent));
// Check if label's value attribute is used
if (xulLabel && NS_SUCCEEDED(xulLabel->GetValue(label)) && label.IsEmpty()) {
// If no value attribute, a non-empty label must contain
// children that define its text -- possibly using HTML
- AppendFlatStringFromSubtree(labelContent, &label);
+ nsTextEquivUtils::AppendTextEquivFromContent(this, labelContent, &label);
}
}
// XXX If CompressWhiteSpace worked on nsAString we could avoid a copy
label.CompressWhitespace();
if (!label.IsEmpty()) {
aLabel = label;
return NS_OK;
@@ -1849,22 +1561,17 @@ nsAccessible::GetXULName(nsAString& aLab
parent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::title, label)) {
label.CompressWhitespace();
aLabel = label;
return NS_OK;
}
parent = parent->GetParent();
}
- PRUint32 role = nsAccUtils::Role(this);
- PRUint32 canAggregateName =
- nsNameUtils::gRoleToNameRulesMap[role] & eFromSubtree;
-
- return canAggregateName ?
- AppendFlatStringFromSubtree(content, &aLabel) : NS_OK;
+ return nsTextEquivUtils::GetNameFromSubtree(this, aLabel);
}
NS_IMETHODIMP
nsAccessible::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
{
NS_ENSURE_ARG_POINTER(aEvent);
nsCOMPtr<nsIDOMNode> eventNode;
aEvent->GetDOMNode(getter_AddRefs(eventNode));
@@ -1921,17 +1628,18 @@ NS_IMETHODIMP nsAccessible::GetFinalRole
GetParent(getter_AddRefs(parent));
if (nsAccUtils::Role(parent) == nsIAccessibleRole::ROLE_COMBOBOX_LIST)
*aRole = nsIAccessibleRole::ROLE_COMBOBOX_OPTION;
}
// gLandmarkRoleMap: can use role of accessible class impl
// gEmptyRoleMap and all others: cannot use role of accessible class impl
if (mRoleMapEntry != &nsARIAMap::gLandmarkRoleMap) {
- // We can now expose ROLE_NOTHING when there is a role map entry, which
+ // We can now expose ROLE_NOTHING when there is a role map entry or used
+ // role is nothing, which
// will cause ATK to use ROLE_UNKNOWN and MSAA to use a BSTR role with
// the ARIA role or element's tag. In either case the AT can also use
// the object attributes tag and xml-roles to find out more.
return NS_OK;
}
}
return mDOMNode ? GetRole(aRole) : NS_ERROR_FAILURE; // Node already shut down
}
@@ -1978,64 +1686,63 @@ nsAccessible::GetAttributes(nsIPersisten
// We support values, so expose the string value as well, via the valuetext object attribute
// We test for the value interface because we don't want to expose traditional get_accValue()
// information such as URL's on links and documents, or text in an input
nsAutoString valuetext;
GetValue(valuetext);
attributes->SetStringProperty(NS_LITERAL_CSTRING("valuetext"), valuetext, oldValueUnused);
}
-
- PRUint32 role = nsAccUtils::Role(this);
- if (role == nsIAccessibleRole::ROLE_CHECKBUTTON ||
- role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
- role == nsIAccessibleRole::ROLE_MENUITEM ||
- role == nsIAccessibleRole::ROLE_LISTITEM ||
- role == nsIAccessibleRole::ROLE_OPTION ||
- role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
- role == nsIAccessibleRole::ROLE_RICH_OPTION ||
- role == nsIAccessibleRole::ROLE_OUTLINEITEM ||
- content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_checked)) {
- // Might be checkable -- checking role & ARIA attribute first is faster than getting state
- PRUint32 state = 0;
- GetState(&state, nsnull);
- if (state & nsIAccessibleStates::STATE_CHECKABLE) {
- // No official state for checkable, so use object attribute to expose that
- attributes->SetStringProperty(NS_LITERAL_CSTRING("checkable"), NS_LITERAL_STRING("true"),
- oldValueUnused);
- }
- }
+ // Expose checkable object attribute if the accessible has checkable state
+ if (nsAccUtils::State(this) & nsIAccessibleStates::STATE_CHECKABLE)
+ nsAccUtils::SetAccAttr(attributes, nsAccessibilityAtoms::checkable, NS_LITERAL_STRING("true"));
// Group attributes (level/setsize/posinset)
if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
// Calculate group attributes based on accessible hierarhy if they weren't
// provided by ARIA or by accessible class implementation.
+ PRUint32 role = nsAccUtils::Role(this);
rv = ComputeGroupAttributes(role, attributes);
NS_ENSURE_SUCCESS(rv, rv);
}
- // Expose all ARIA attributes
+ // Expose object attributes from ARIA attributes.
PRUint32 numAttrs = content->GetAttrCount();
for (PRUint32 count = 0; count < numAttrs; count ++) {
const nsAttrName *attr = content->GetAttrNameAt(count);
if (attr && attr->NamespaceEquals(kNameSpaceID_None)) {
nsIAtom *attrAtom = attr->Atom();
const char *attrStr;
attrAtom->GetUTF8String(&attrStr);
if (PL_strncmp(attrStr, "aria-", 5))
continue; // Not ARIA
- if (!nsAccUtils::IsARIAPropForObjectAttr(attrAtom))
+ PRUint8 attrFlags = nsAccUtils::GetAttributeCharacteristics(attrAtom);
+ if (attrFlags & ATTR_EXPOSEOBJ)
continue; // No need to expose obj attribute -- will be exposed some other way
+ if ((attrFlags & ATTR_VALTOKEN) &&
+ !nsAccUtils::HasDefinedARIAToken(content, attrAtom))
+ continue; // only expose token based attributes if they are defined
nsAutoString value;
if (content->GetAttr(kNameSpaceID_None, attrAtom, value)) {
attributes->SetStringProperty(nsDependentCString(attrStr + 5), value, oldValueUnused);
}
}
}
+ // If there is no aria-live attribute then expose default value of 'live'
+ // object attribute used for ARIA role of this accessible.
+ if (mRoleMapEntry) {
+ nsAutoString live;
+ nsAccUtils::GetAccAttr(attributes, nsAccessibilityAtoms::live, live);
+ if (live.IsEmpty()) {
+ nsAccUtils::GetLiveAttrValue(mRoleMapEntry->liveAttRule, live);
+ nsAccUtils::SetAccAttr(attributes, nsAccessibilityAtoms::live, live);
+ }
+ }
+
return NS_OK;
}
nsresult
nsAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
{
// Attributes set by this method will not be used to override attributes on a sub-document accessible
// when there is a <frame>/<iframe> element that spawned the sub-document
@@ -2325,17 +2032,21 @@ nsAccessible::GetState(PRUint32 *aState,
// In XUL all boxes are either vertical or horizontal
if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL) {
*aExtraState |= nsIAccessibleStates::EXT_STATE_VERTICAL;
}
else {
*aExtraState |= nsIAccessibleStates::EXT_STATE_HORIZONTAL;
}
}
-
+
+ // If we are editable, force readonly bit off
+ if (*aExtraState & nsIAccessibleStates::EXT_STATE_EDITABLE)
+ *aState &= ~nsIAccessibleStates::STATE_READONLY;
+
return NS_OK;
}
nsresult
nsAccessible::GetARIAState(PRUint32 *aState)
{
// Test for universal states first
nsIContent *content = nsCoreUtils::GetRoleContent(mDOMNode);
@@ -2344,17 +2055,18 @@ nsAccessible::GetARIAState(PRUint32 *aSt
}
PRUint32 index = 0;
while (MappedAttrState(content, aState, &nsARIAMap::gWAIUnivStateMap[index])) {
++ index;
}
if (mRoleMapEntry) {
- // Once DHTML role is used, we're only readonly if DHTML readonly used
+ // Once an ARIA role is used, default to not-readonly. This can be overridden
+ // by aria-readonly, or if the ARIA role is mapped to readonly by default
*aState &= ~nsIAccessibleStates::STATE_READONLY;
if (content->HasAttr(kNameSpaceID_None, content->GetIDAttributeName())) {
// If has a role & ID and aria-activedescendant on the container, assume focusable
nsIContent *ancestorContent = content;
while ((ancestorContent = ancestorContent->GetParent()) != nsnull) {
if (ancestorContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_activedescendant)) {
// ancestor has activedescendant property, this content could be active
@@ -2376,16 +2088,17 @@ nsAccessible::GetARIAState(PRUint32 *aSt
break;
}
}
}
if (!mRoleMapEntry)
return NS_OK;
+ // Note: the readonly bitflag will be overridden later if content is editable
*aState |= mRoleMapEntry->state;
if (MappedAttrState(content, aState, &mRoleMapEntry->attributeMap1) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap2) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap3) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap4) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap5) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap6) &&
MappedAttrState(content, aState, &mRoleMapEntry->attributeMap7)) {
@@ -3363,24 +3076,28 @@ nsAccessible::GetARIAName(nsAString& aNa
{
nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
if (!content)
return NS_OK;
// First check for label override via aria-label property
nsAutoString label;
if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_label, label)) {
+ label.CompressWhitespace();
aName = label;
return NS_OK;
}
// Second check for label override via aria-labelledby relationship
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_labelledby, label);
- if (NS_SUCCEEDED(rv))
+ nsresult rv = nsTextEquivUtils::
+ GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_labelledby, label);
+ if (NS_SUCCEEDED(rv)) {
+ label.CompressWhitespace();
aName = label;
+ }
return rv;
}
nsresult
nsAccessible::GetNameInternal(nsAString& aName)
{
nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -36,34 +36,35 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef _nsAccessible_H_
#define _nsAccessible_H_
#include "nsAccessNodeWrap.h"
+#include "nsARIAMap.h"
+#include "nsRelUtils.h"
+#include "nsTextEquivUtils.h"
+
#include "nsIAccessible.h"
#include "nsPIAccessible.h"
#include "nsIAccessibleHyperLink.h"
#include "nsIAccessibleSelectable.h"
#include "nsIAccessibleValue.h"
#include "nsIAccessibleRole.h"
#include "nsIAccessibleStates.h"
#include "nsIAccessibleEvent.h"
-#include "nsRelUtils.h"
-
#include "nsIDOMNodeList.h"
#include "nsINameSpaceManager.h"
#include "nsWeakReference.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsIDOMDOMStringList.h"
-#include "nsARIAMap.h"
struct nsRect;
class nsIContent;
class nsIFrame;
class nsIPresShell;
class nsIDOMNode;
class nsIAtom;
class nsIView;
@@ -176,49 +177,29 @@ public:
}
protected:
PRBool MappedAttrState(nsIContent *aContent, PRUint32 *aStateInOut, nsStateMapEntry *aStateMapEntry);
virtual nsIFrame* GetBoundsFrame();
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
PRBool IsVisible(PRBool *aIsOffscreen);
- // Relation helpers
-
- /**
- * For a given ARIA relation, such as labelledby or describedby, get the collated text
- * for the subtree that's pointed to.
- *
- * @param aIDProperty The ARIA relationship property to get the text for
- * @param aName Where to put the text
- * @return error or success code
- */
- nsresult GetTextFromRelationID(nsIAtom *aIDProperty, nsString &aName);
-
//////////////////////////////////////////////////////////////////////////////
// Name helpers.
/**
* Compute the name of HTML node.
*/
nsresult GetHTMLName(nsAString& aName);
/**
* Compute the name for XUL node.
*/
nsresult GetXULName(nsAString& aName);
- // For accessibles that are not lists of choices, the name of the subtree should be the
- // sum of names in the subtree
- nsresult AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString);
- nsresult AppendNameFromAccessibleFor(nsIContent *aContent, nsAString *aFlatString,
- PRBool aFromValue = PR_FALSE);
- nsresult AppendFlatStringFromContentNode(nsIContent *aContent, nsAString *aFlatString);
- nsresult AppendStringWithSpaces(nsAString *aFlatString, const nsAString& textEquivalent);
-
// helper method to verify frames
static nsresult GetFullKeyName(const nsAString& aModifierName, const nsAString& aKeyName, nsAString& aStringOut);
static nsresult GetTranslatedString(const nsAString& aKey, nsAString& aStringOut);
/**
* Walk into subtree and calculate the string which is used as the accessible
* name or description.
*
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -339,17 +339,17 @@ nsCaretAccessible::GetCaretRect(nsIWidge
NS_ENSURE_TRUE(*aOutWidget, nsIntRect());
nsPresContext *presContext = presShell->GetPresContext();
NS_ENSURE_TRUE(presContext, nsIntRect());
rect += offsetFromWidget;
caretRect = nsRect::ToOutsidePixels(rect, presContext->AppUnitsPerDevPixel());
- (*aOutWidget)->WidgetToScreen(caretRect, caretRect);
+ caretRect.MoveBy((*aOutWidget)->WidgetToScreenOffset());
// Correct for character size, so that caret always matches the size of the character
// This is important for font size transitions, and is necessary because the Gecko caret uses the
// previous character's size as the user moves forward in the text by character.
PRInt32 charX, charY, charWidth, charHeight;
if (NS_SUCCEEDED(mLastTextAccessible->GetCharacterExtents(mLastCaretOffset, &charX, &charY,
&charWidth, &charHeight,
nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE))) {
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -258,17 +258,19 @@ NS_IMETHODIMP nsDocAccessible::SetRoleMa
NS_IMETHODIMP
nsDocAccessible::GetDescription(nsAString& aDescription)
{
if (mParent)
mParent->GetDescription(aDescription);
if (aDescription.IsEmpty()) {
nsAutoString description;
- GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
+ nsTextEquivUtils::
+ GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
+ description);
aDescription = description;
}
return NS_OK;
}
nsresult
nsDocAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsTextAttrs.cpp
@@ -0,0 +1,605 @@
+/* -*- 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(static_cast<nsITextAttr*>(&langTextAttr));
+
+ // "color" text attribute
+ nsCSSTextAttr colorTextAttr(0, hyperTextElm, offsetElm);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&colorTextAttr));
+
+ // "font-family" text attribute
+ nsCSSTextAttr fontFamilyTextAttr(1, hyperTextElm, offsetElm);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontFamilyTextAttr));
+
+ // "font-style" text attribute
+ nsCSSTextAttr fontStyleTextAttr(2, hyperTextElm, offsetElm);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontStyleTextAttr));
+
+ // "font-weight" text attribute
+ nsCSSTextAttr fontWeightTextAttr(3, hyperTextElm, offsetElm);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontWeightTextAttr));
+
+ // "text-line-through-style" text attribute
+ nsCSSTextAttr lineThroughTextAttr(4, hyperTextElm, offsetElm);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&lineThroughTextAttr));
+
+ // "text-underline-style" text attribute
+ nsCSSTextAttr underlineTextAttr(5, hyperTextElm, offsetElm);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&underlineTextAttr));
+
+ // "text-position" text attribute
+ nsCSSTextAttr posTextAttr(6, hyperTextElm, offsetElm);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&posTextAttr));
+
+ // "background-color" text attribute
+ nsBGColorTextAttr bgColorTextAttr(rootFrame, frame);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&bgColorTextAttr));
+
+ // "font-size" text attribute
+ nsFontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
+ textAttrArray.AppendElement(static_cast<nsITextAttr*>(&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<nsAutoString>(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<nsAutoString>(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<nscolor>(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 (NS_GET_A(styleBackground->mFallbackBackgroundColor) > 0) {
+ *aColor = styleBackground->mFallbackBackgroundColor;
+ 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<nscoord>(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;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsTextAttrs.h
@@ -0,0 +1,371 @@
+/* -*- 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
rename from accessible/src/base/nsNameUtils.cpp
rename to accessible/src/base/nsTextEquivUtils.cpp
--- a/accessible/src/base/nsNameUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -32,22 +32,361 @@
* 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 "nsNameUtils.h"
+#include "nsTextEquivUtils.h"
+
+#include "nsAccessible.h"
+
+#include "nsIDOMXULLabeledControlEl.h"
+
+#include "nsArrayUtils.h"
+
+#define NS_OK_NO_NAME_CLAUSE_HANDLED \
+NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x24)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsTextEquivUtils. Public.
+
+nsresult
+nsTextEquivUtils::GetNameFromSubtree(nsIAccessible *aAccessible,
+ nsAString& aName)
+{
+ aName.Truncate();
+
+ if (gInitiatorAcc)
+ return NS_OK;
+
+ gInitiatorAcc = aAccessible;
+
+ PRUint32 role = nsAccUtils::Role(aAccessible);
+ PRUint32 nameRule = gRoleToNameRulesMap[role];
+
+ if (nameRule == eFromSubtree) {
+ nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
+
+ nsCOMPtr<nsIDOMNode> DOMNode;
+ accessNode->GetDOMNode(getter_AddRefs(DOMNode));
+ nsCOMPtr<nsIContent> content(do_QueryInterface(DOMNode));
+ if (content) {
+ nsAutoString name;
+ AppendFromAccessibleChildren(aAccessible, &name);
+ name.CompressWhitespace();
+ aName = name;
+ }
+ }
+
+ gInitiatorAcc = nsnull;
+
+ return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::GetTextEquivFromIDRefs(nsIAccessible *aAccessible,
+ nsIAtom *aIDRefsAttr,
+ nsAString& aTextEquiv)
+{
+ aTextEquiv.Truncate();
+
+ nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
+
+ nsCOMPtr<nsIDOMNode> DOMNode;
+ accessNode->GetDOMNode(getter_AddRefs(DOMNode));
+
+ nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(DOMNode);
+ if (!content)
+ return NS_OK;
+
+ nsCOMPtr<nsIArray> refElms;
+ nsCoreUtils::GetElementsByIDRefsAttr(content, aIDRefsAttr,
+ getter_AddRefs(refElms));
+
+ if (!refElms)
+ return NS_OK;
+
+ PRUint32 count = 0;
+ nsresult rv = refElms->GetLength(&count);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIContent> refContent;
+ for (PRUint32 idx = 0; idx < count; idx++) {
+ refContent = do_QueryElementAt(refElms, idx, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!aTextEquiv.IsEmpty())
+ aTextEquiv += ' ';
+
+ rv = AppendTextEquivFromContent(aAccessible, refContent, &aTextEquiv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::AppendTextEquivFromContent(nsIAccessible *aInitiatorAcc,
+ nsIContent *aContent,
+ nsAString *aString)
+{
+ // Prevent recursion which can cause infinite loops.
+ if (gInitiatorAcc)
+ return NS_OK;
+
+ gInitiatorAcc = aInitiatorAcc;
+
+ nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(aContent));
+ nsCOMPtr<nsIPresShell> shell = nsCoreUtils::GetPresShellFor(DOMNode);
+ if (!shell) {
+ NS_ASSERTION(PR_TRUE, "There is no presshell!");
+ gInitiatorAcc = nsnull;
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ // If the given content is not visible or isn't accessible then go down
+ // through the DOM subtree otherwise go down through accessible subtree and
+ // calculate the flat string.
+ nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
+ PRBool isVisible = frame && frame->GetStyleVisibility()->IsVisible();
+
+ nsresult rv;
+ PRBool goThroughDOMSubtree = PR_TRUE;
+
+ if (isVisible) {
+ nsCOMPtr<nsIAccessible> accessible;
+ rv = nsAccessNode::GetAccService()->
+ GetAccessibleInShell(DOMNode, shell, getter_AddRefs(accessible));
+ if (NS_SUCCEEDED(rv) && accessible) {
+ rv = AppendFromAccessible(accessible, aString);
+ goThroughDOMSubtree = PR_FALSE;
+ }
+ }
+
+ if (goThroughDOMSubtree)
+ rv = AppendFromDOMNode(aContent, aString);
+
+ gInitiatorAcc = nsnull;
+ return rv;
+}
+
+nsresult
+nsTextEquivUtils::AppendTextEquivFromTextContent(nsIContent *aContent,
+ nsAString *aString)
+{
+ if (aContent->IsNodeOfType(nsINode::eTEXT)) {
+
+ nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(aContent));
+
+ PRBool isHTMLBlock = PR_FALSE;
+ nsCOMPtr<nsIPresShell> shell = nsCoreUtils::GetPresShellFor(DOMNode);
+ NS_ENSURE_STATE(shell);
+
+ nsIContent *parentContent = aContent->GetParent();
+ if (parentContent) {
+ nsIFrame *frame = shell->GetPrimaryFrameFor(parentContent);
+ if (frame) {
+ // If this text is inside a block level frame (as opposed to span
+ // level), we need to add spaces around that block's text, so we don't
+ // get words jammed together in final name.
+ const nsStyleDisplay* display = frame->GetStyleDisplay();
+ if (display->IsBlockOutside() ||
+ display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
+ isHTMLBlock = PR_TRUE;
+ if (!aString->IsEmpty()) {
+ aString->Append(PRUnichar(' '));
+ }
+ }
+ }
+ }
+
+ if (aContent->TextLength() > 0) {
+ nsIFrame *frame = shell->GetPrimaryFrameFor(aContent);
+ if (frame) {
+ nsresult rv = frame->GetRenderedText(aString);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ // If aContent is an object that is display: none, we have no a frame.
+ aContent->AppendTextTo(*aString);
+ }
+ if (isHTMLBlock && !aString->IsEmpty()) {
+ aString->Append(PRUnichar(' '));
+ }
+ }
+
+ return NS_OK;
+ }
+
+ if (aContent->IsNodeOfType(nsINode::eHTML) &&
+ aContent->NodeInfo()->Equals(nsAccessibilityAtoms::br)) {
+ aString->AppendLiteral("\r\n");
+ return NS_OK;
+ }
+
+ return NS_OK_NO_NAME_CLAUSE_HANDLED;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsTextEquivUtils. Private.
+
+nsCOMPtr<nsIAccessible> nsTextEquivUtils::gInitiatorAcc;
+
+nsresult
+nsTextEquivUtils::AppendFromAccessibleChildren(nsIAccessible *aAccessible,
+ nsAString *aString)
+{
+ nsCOMPtr<nsIAccessible> accChild, accNextChild;
+ aAccessible->GetFirstChild(getter_AddRefs(accChild));
+
+ while (accChild) {
+ nsresult rv = AppendFromAccessible(accChild, aString);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ accChild->GetNextSibling(getter_AddRefs(accNextChild));
+ accChild.swap(accNextChild);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::AppendFromAccessible(nsIAccessible *aAccessible,
+ nsAString *aString)
+{
+ nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
+
+ nsCOMPtr<nsIDOMNode> DOMNode;
+ accessNode->GetDOMNode(getter_AddRefs(DOMNode));
+ nsCOMPtr<nsIContent> content(do_QueryInterface(DOMNode));
+ NS_ASSERTION(content, "There is no content!");
+
+ if (content) {
+ nsresult rv = AppendTextEquivFromTextContent(content, aString);
+ if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED)
+ return rv;
+ }
+
+ nsAutoString text;
+ nsresult rv = aAccessible->GetName(text);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ AppendString(aString, text);
+
+ PRUint32 role = nsAccUtils::Role(aAccessible);
+ PRUint32 nameRule = gRoleToNameRulesMap[role];
+
+ if (nameRule == eFromValue) {
+ // Implementation of step f) of text equivalent computation. If the given
+ // accessible is not root accessible (the accessible the text equivalent is
+ // computed for in the end) then append accessible value. Otherwise append
+ // value if and only if the given accessible is in the middle of its parent.
+
+ if (aAccessible != gInitiatorAcc) {
+ rv = aAccessible->GetValue(text);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ AppendString(aString, text);
+ } else {
+ nsCOMPtr<nsIAccessible> nextSibling;
+ aAccessible->GetNextSibling(getter_AddRefs(nextSibling));
+ if (nextSibling) {
+ nsCOMPtr<nsIAccessible> parent;
+ aAccessible->GetParent(getter_AddRefs(parent));
+ if (parent) {
+ nsCOMPtr<nsIAccessible> firstChild;
+ parent->GetFirstChild(getter_AddRefs(firstChild));
+ if (firstChild && firstChild != aAccessible) {
+ rv = aAccessible->GetValue(text);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ AppendString(aString, text);
+ }
+ }
+ }
+ }
+ }
+
+ // Implementation of g) step of text equivalent computation guide. Go down
+ // into subtree if accessible allows "text equivalent from subtree rule" or
+ // it's not root and not control.
+ if (text.IsEmpty() && (nameRule & eFromSubtreeIfRec))
+ return AppendFromAccessibleChildren(aAccessible, aString);
+
+ return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::AppendFromDOMChildren(nsIContent *aContent,
+ nsAString *aString)
+{
+ PRUint32 childCount = aContent->GetChildCount();
+ for (PRUint32 childIdx = 0; childIdx < childCount; childIdx++) {
+ nsCOMPtr<nsIContent> childContent = aContent->GetChildAt(childIdx);
+
+ nsresult rv = AppendFromDOMNode(childContent, aString);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsTextEquivUtils::AppendFromDOMNode(nsIContent *aContent, nsAString *aString)
+{
+ nsresult rv = AppendTextEquivFromTextContent(aContent, aString);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED)
+ return NS_OK;
+
+ if (aContent->IsNodeOfType(nsINode::eXUL)) {
+ nsAutoString textEquivalent;
+ nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl =
+ do_QueryInterface(aContent);
+
+ if (labeledEl) {
+ labeledEl->GetLabel(textEquivalent);
+ } else {
+ if (aContent->NodeInfo()->Equals(nsAccessibilityAtoms::label,
+ kNameSpaceID_XUL))
+ aContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value,
+ textEquivalent);
+
+ if (textEquivalent.IsEmpty())
+ aContent->GetAttr(kNameSpaceID_None,
+ nsAccessibilityAtoms::tooltiptext, textEquivalent);
+ }
+
+ AppendString(aString, textEquivalent);
+ }
+
+ return AppendFromDOMChildren(aContent, aString);
+}
+
+void
+nsTextEquivUtils::AppendString(nsAString *aString,
+ const nsAString& aTextEquivalent)
+{
+ // Insert spaces to insure that words from controls aren't jammed together.
+ if (aTextEquivalent.IsEmpty())
+ return;
+
+ if (!aString->IsEmpty())
+ aString->Append(PRUnichar(' '));
+
+ aString->Append(aTextEquivalent);
+}
////////////////////////////////////////////////////////////////////////////////
// Name rules to role map.
-PRUint32 nsNameUtils::gRoleToNameRulesMap[] =
+PRUint32 nsTextEquivUtils::gRoleToNameRulesMap[] =
{
eNoRule, // ROLE_NOTHING
eNoRule, // ROLE_TITLEBAR
eNoRule, // ROLE_MENUBAR
eNoRule, // ROLE_SCROLLBAR
eNoRule, // ROLE_GRIP
eNoRule, // ROLE_SOUND
eNoRule, // ROLE_CURSOR
@@ -68,36 +407,36 @@ PRUint32 nsNameUtils::gRoleToNameRulesMa
eNoRule, // ROLE_SEPARATOR
eNoRule, // ROLE_TOOLBAR
eNoRule, // ROLE_STATUSBAR
eNoRule, // ROLE_TABLE
eFromSubtree, // ROLE_COLUMNHEADER
eFromSubtree, // ROLE_ROWHEADER
eFromSubtree, // ROLE_COLUMN
eFromSubtree, // ROLE_ROW
- eNoRule, // ROLE_CELL
+ eFromSubtreeIfRec, // ROLE_CELL
eFromSubtree, // ROLE_LINK
eFromSubtree, // ROLE_HELPBALLOON
eNoRule, // ROLE_CHARACTER
- eNoRule, // ROLE_LIST
+ eFromSubtreeIfRec, // ROLE_LIST
eFromSubtree, // ROLE_LISTITEM
eNoRule, // ROLE_OUTLINE
eFromSubtree, // ROLE_OUTLINEITEM
eFromSubtree, // ROLE_PAGETAB
eNoRule, // ROLE_PROPERTYPAGE
eNoRule, // ROLE_INDICATOR
eNoRule, // ROLE_GRAPHIC
eNoRule, // ROLE_STATICTEXT
eNoRule, // ROLE_TEXT_LEAF
eFromSubtree, // ROLE_PUSHBUTTON
eFromSubtree, // ROLE_CHECKBUTTON
eFromSubtree, // ROLE_RADIOBUTTON
- eNoRule, // ROLE_COMBOBOX
+ eFromValue, // ROLE_COMBOBOX
eNoRule, // ROLE_DROPLIST
- eNoRule, // ROLE_PROGRESSBAR
+ eFromValue, // ROLE_PROGRESSBAR
eNoRule, // ROLE_DIAL
eNoRule, // ROLE_HOTKEYFIELD
eNoRule, // ROLE_SLIDER
eNoRule, // ROLE_SPINBUTTON
eNoRule, // ROLE_DIAGRAM
eNoRule, // ROLE_ANIMATION
eNoRule, // ROLE_EQUATION
eFromSubtree, // ROLE_BUTTONDROPDOWN
@@ -116,47 +455,47 @@ PRUint32 nsNameUtils::gRoleToNameRulesMa
eNoRule, // ROLE_DATE_EDITOR
eNoRule, // ROLE_DESKTOP_ICON
eNoRule, // ROLE_DESKTOP_FRAME
eNoRule, // ROLE_DIRECTORY_PANE
eNoRule, // ROLE_FILE_CHOOSER
eNoRule, // ROLE_FONT_CHOOSER
eNoRule, // ROLE_CHROME_WINDOW
eNoRule, // ROLE_GLASS_PANE
- eNoRule, // ROLE_HTML_CONTAINER
+ eFromSubtreeIfRec, // ROLE_HTML_CONTAINER
eNoRule, // ROLE_ICON
- eNoRule, // ROLE_LABEL
+ eFromSubtree, // ROLE_LABEL
eNoRule, // ROLE_LAYERED_PANE
eNoRule, // ROLE_OPTION_PANE
eNoRule, // ROLE_PASSWORD_TEXT
eNoRule, // ROLE_POPUP_MENU
eFromSubtree, // ROLE_RADIO_MENU_ITEM
eNoRule, // ROLE_ROOT_PANE
eNoRule, // ROLE_SCROLL_PANE
eNoRule, // ROLE_SPLIT_PANE
eFromSubtree, // ROLE_TABLE_COLUMN_HEADER
eFromSubtree, // ROLE_TABLE_ROW_HEADER
eFromSubtree, // ROLE_TEAR_OFF_MENU_ITEM
eNoRule, // ROLE_TERMINAL
- eNoRule, // ROLE_TEXT_CONTAINER
+ eFromSubtreeIfRec, // ROLE_TEXT_CONTAINER
eFromSubtree, // ROLE_TOGGLE_BUTTON
eNoRule, // ROLE_TREE_TABLE
eNoRule, // ROLE_VIEWPORT
eNoRule, // ROLE_HEADER
eNoRule, // ROLE_FOOTER
- eNoRule, // ROLE_PARAGRAPH
+ eFromSubtreeIfRec, // ROLE_PARAGRAPH
eNoRule, // ROLE_RULER
eNoRule, // ROLE_AUTOCOMPLETE
eNoRule, // ROLE_EDITBAR
- eNoRule, // ROLE_ENTRY
+ eFromValue, // ROLE_ENTRY
eNoRule, // ROLE_CAPTION
eNoRule, // ROLE_DOCUMENT_FRAME
eNoRule, // ROLE_HEADING
eNoRule, // ROLE_PAGE
- eNoRule, // ROLE_SECTION
+ eFromSubtreeIfRec, // ROLE_SECTION
eNoRule, // ROLE_REDUNDANT_OBJECT
eNoRule, // ROLE_FORM
eNoRule, // ROLE_IME
eNoRule, // ROLE_APP_ROOT
eFromSubtree, // ROLE_PARENT_MENUITEM
eNoRule, // ROLE_CALENDAR
eNoRule, // ROLE_COMBOBOX_LIST
eFromSubtree, // ROLE_COMBOBOX_OPTION
rename from accessible/src/base/nsNameUtils.h
rename to accessible/src/base/nsTextEquivUtils.h
--- a/accessible/src/base/nsNameUtils.h
+++ b/accessible/src/base/nsTextEquivUtils.h
@@ -32,40 +32,137 @@
* 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 _nsNameUtils_H_
-#define _nsNameUtils_H_
+#ifndef _nsTextEquivUtils_H_
+#define _nsTextEquivUtils_H_
-#include "prtypes.h"
+#include "nsIAccessible.h"
+
+#include "nsIContent.h"
+#include "nsIStringBundle.h"
/**
- * Name from subtree calculation rules.
+ * Text equivalent computation rules (see nsTextEquivUtils::gRoleToNameRulesMap)
*/
-enum ENameFromSubtreeRule
+enum ETextEquivRule
{
- // do not walk into subtree to compute the name
+ // No rule.
eNoRule = 0x00,
-
- // compute the name from the subtree
- eFromSubtree = 0x01
+
+ // Walk into subtree only if the currently navigated accessible is not root
+ // accessible (i.e. if the accessible is part of text equivalent computation).
+ eFromSubtreeIfRec = 0x01,
+
+ // Text equivalent computation from subtree is allowed.
+ eFromSubtree = 0x03,
+
+ // The accessible allows to append its value to text equivalent.
+ // XXX: This is temporary solution. Once we move accessible value of links
+ // and linkable accessibles to MSAA part we can remove this.
+ eFromValue = 0x04
};
/**
* The class provides utils methods to compute the accessible name and
* description.
*/
-class nsNameUtils
+class nsTextEquivUtils
{
public:
/**
- * Map array from roles to name rules (bit state of ENameFromSubtreeRule).
+ * Calculates the name from accessible subtree if allowed.
+ *
+ * @param aAccessible [in] the given accessible
+ * @param aName [out] accessible name
+ */
+ static nsresult GetNameFromSubtree(nsIAccessible *aAccessible,
+ nsAString& aName);
+
+ /**
+ * Calculates text equivalent for the given accessible from its IDRefs
+ * attribute (like aria-labelledby or aria-describedby).
+ *
+ * @param aAccessible [in] the accessible text equivalent is computed for
+ * @param aIDRefsAttr [in] IDRefs attribute on DOM node of the accessible
+ * @param aTextEquiv [out] result text equivalent
+ */
+ static nsresult GetTextEquivFromIDRefs(nsIAccessible *aAccessible,
+ nsIAtom *aIDRefsAttr,
+ nsAString& aTextEquiv);
+
+ /**
+ * Calculates the text equivalent from the given content and its subtree if
+ * allowed and appends it to the given string.
+ *
+ * @param aInitiatorAcc [in] the accessible text equivalent is computed for
+ * in the end (root accessible of text equivalent
+ * calculation recursion)
+ * @param aContent [in] the given content the text equivalent is
+ * computed from
+ * @param aString [in, out] the string
+ */
+ static nsresult AppendTextEquivFromContent(nsIAccessible *aInitiatorAcc,
+ nsIContent *aContent,
+ nsAString *aString);
+
+ /**
+ * Calculates the text equivalent from the given text content (may be text
+ * node or html:br) and appends it to the given string.
+ *
+ * @param aContent [in] the text content
+ * @param aString [in, out] the string
+ */
+ static nsresult AppendTextEquivFromTextContent(nsIContent *aContent,
+ nsAString *aString);
+
+private:
+ /**
+ * Iterates accessible children and calculates text equivalent from each
+ * child.
+ */
+ static nsresult AppendFromAccessibleChildren(nsIAccessible *aAccessible,
+ nsAString *aString);
+
+ /**
+ * Calculates text equivalent from the given accessible and its subtree if
+ * allowed.
+ */
+ static nsresult AppendFromAccessible(nsIAccessible *aAccessible,
+ nsAString *aString);
+
+ /**
+ * Iterates DOM children and calculates text equivalent from each child node.
+ */
+ static nsresult AppendFromDOMChildren(nsIContent *aContent,
+ nsAString *aString);
+
+ /**
+ * Calculates text equivalent from the given DOM node and its subtree if
+ * allowed.
+ */
+ static nsresult AppendFromDOMNode(nsIContent *aContent, nsAString *aString);
+
+ /**
+ * Concatenates strings and appends space between them.
+ */
+ static void AppendString(nsAString *aString, const nsAString& aTextEquivalent);
+
+ /**
+ * Map array from roles to name rules (constants of ETextEquivRule).
*/
static PRUint32 gRoleToNameRulesMap[];
+
+ /**
+ * The accessible for which we are computing a text equivalent. It is useful
+ * for bailing out during recursive text computation, or for special cases
+ * like step f. of the ARIA implementation guide.
+ */
+ static nsCOMPtr<nsIAccessible> gInitiatorAcc;
};
#endif
deleted file mode 100644
--- a/accessible/src/base/nsTextUtils.cpp
+++ /dev/null
@@ -1,298 +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 "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;
-}
deleted file mode 100644
--- a/accessible/src/base/nsTextUtils.h
+++ /dev/null
@@ -1,190 +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 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/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -622,17 +622,18 @@ nsHTMLGroupboxAccessible::GetNameInterna
nsresult rv = nsAccessible::GetNameInternal(aName);
NS_ENSURE_SUCCESS(rv, rv);
if (!aName.IsEmpty())
return NS_OK;
nsIContent *legendContent = GetLegend();
if (legendContent) {
- return AppendFlatStringFromSubtree(legendContent, &aName);
+ return nsTextEquivUtils::
+ AppendTextEquivFromContent(this, legendContent, &aName);
}
return NS_OK;
}
NS_IMETHODIMP
nsHTMLGroupboxAccessible::GetRelationByType(PRUint32 aRelationType,
nsIAccessibleRelation **aRelation)
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -521,17 +521,18 @@ nsHTMLSelectOptionAccessible::GetNameInt
// CASE #2 -- no label parameter, get the first child,
// use it if it is a text node
nsCOMPtr<nsIContent> text = content->GetChildAt(0);
if (!text)
return NS_OK;
if (text->IsNodeOfType(nsINode::eTEXT)) {
nsAutoString txtValue;
- nsresult rv = AppendFlatStringFromContentNode(text, &txtValue);
+ nsresult rv = nsTextEquivUtils::
+ AppendTextEquivFromTextContent(text, &txtValue);
NS_ENSURE_SUCCESS(rv, rv);
// Temp var (txtValue) needed until CompressWhitespace built for nsAString
txtValue.CompressWhitespace();
aName.Assign(txtValue);
return NS_OK;
}
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -962,17 +962,18 @@ NS_IMETHODIMP nsHTMLTableAccessible::Get
nsCOMPtr<nsIAccessible> captionAccessible;
GetCaption(getter_AddRefs(captionAccessible));
nsCOMPtr<nsIAccessNode> captionAccessNode = do_QueryInterface(captionAccessible);
if (captionAccessNode) {
nsCOMPtr<nsIDOMNode> captionNode;
captionAccessNode->GetDOMNode(getter_AddRefs(captionNode));
nsCOMPtr<nsIContent> captionContent = do_QueryInterface(captionNode);
if (captionContent) {
- AppendFlatStringFromSubtree(captionContent, &aDescription);
+ nsTextEquivUtils::
+ AppendTextEquivFromContent(this, captionContent, &aDescription);
}
}
#ifdef SHOW_LAYOUT_HEURISTIC
if (aDescription.IsEmpty()) {
PRBool isProbablyForLayout;
IsProbablyForLayout(&isProbablyForLayout);
aDescription = mLayoutHeuristic;
}
--- a/accessible/src/html/nsHTMLTextAccessible.cpp
+++ b/accessible/src/html/nsHTMLTextAccessible.cpp
@@ -164,32 +164,19 @@ nsHTMLBRAccessible::GetNameInternal(nsAS
NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLabelAccessible, nsLinkableAccessible)
nsHTMLLabelAccessible::nsHTMLLabelAccessible(nsIDOMNode* aDomNode, nsIWeakReference* aShell):
nsTextAccessible(aDomNode, aShell)
{
}
nsresult
-nsHTMLLabelAccessible::GetNameInternal(nsAString& aReturn)
-{
- nsresult rv = NS_ERROR_FAILURE;
- nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-
- nsAutoString name;
- if (content)
- rv = AppendFlatStringFromSubtree(content, &name);
-
- if (NS_SUCCEEDED(rv)) {
- // Temp var needed until CompressWhitespace built for nsAString
- name.CompressWhitespace();
- aReturn = name;
- }
-
- return rv;
+nsHTMLLabelAccessible::GetNameInternal(nsAString& aName)
+{
+ return nsTextEquivUtils::GetNameFromSubtree(this, aName);
}
NS_IMETHODIMP nsHTMLLabelAccessible::GetRole(PRUint32 *aRole)
{
*aRole = nsIAccessibleRole::ROLE_LABEL;
return NS_OK;
}
--- 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 "nsTextUtils.h"
+#include "nsTextAttrs.h"
#include "nsIClipboard.h"
#include "nsContentCID.h"
#include "nsIDOMAbstractView.h"
#include "nsIDOMCharacterData.h"
#include "nsIDOMDocument.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMDocumentView.h"
@@ -1169,27 +1169,18 @@ 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;
- // 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;
+ nsTextAttrsMgr textAttrsMgr(this, mDOMNode, aIncludeDefAttrs, node);
+ return textAttrsMgr.GetAttributes(*aAttributes, aStartOffset, aEndOffset);
}
// nsIPersistentProperties
// nsIAccessibleText::defaultTextAttributes
NS_IMETHODIMP
nsHyperTextAccessible::GetDefaultTextAttributes(nsIPersistentProperties **aAttributes)
{
NS_ENSURE_ARG_POINTER(aAttributes);
@@ -1199,45 +1190,18 @@ 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;
- 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;
+ nsTextAttrsMgr textAttrsMgr(this, mDOMNode, PR_TRUE, nsnull);
+ return textAttrsMgr.GetAttributes(*aAttributes);
}
nsresult
nsHyperTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
{
if (!mDOMNode) {
return NS_ERROR_FAILURE; // Node already shut down
}
@@ -2315,280 +2279,8 @@ 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 "nsTextUtils.h"
+#include "nsTextAttrs.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,97 +288,15 @@ 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/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -229,17 +229,19 @@ nsXFormsAccessible::GetNameInternal(nsAS
// search the xforms:label element
return GetBoundChildElementValue(NS_LITERAL_STRING("label"), aName);
}
NS_IMETHODIMP
nsXFormsAccessible::GetDescription(nsAString& aDescription)
{
nsAutoString description;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
+ nsresult rv = nsTextEquivUtils::
+ GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
+ description);
if (NS_SUCCEEDED(rv) && !description.IsEmpty()) {
aDescription = description;
return NS_OK;
}
// search the xforms:hint element
return GetBoundChildElementValue(NS_LITERAL_STRING("hint"), aDescription);
--- a/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsFormControlsAccessible.cpp
@@ -61,17 +61,19 @@ nsXFormsLabelAccessible::GetNameInternal
// XXX Correct name calculation for this, see bug 453594.
return NS_OK;
}
NS_IMETHODIMP
nsXFormsLabelAccessible::GetDescription(nsAString& aDescription)
{
nsAutoString description;
- nsresult rv = GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
+ nsresult rv = nsTextEquivUtils::
+ GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
+ description);
aDescription = description;
return rv;
}
// nsXFormsOutputAccessible
nsXFormsOutputAccessible::
nsXFormsOutputAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell):
--- a/accessible/src/xul/nsXULMenuAccessible.h
+++ b/accessible/src/xul/nsXULMenuAccessible.h
@@ -56,18 +56,16 @@ public:
nsXULSelectableAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell);
virtual ~nsXULSelectableAccessible() {}
// nsAccessNode
virtual nsresult Shutdown();
protected:
nsresult ChangeSelection(PRInt32 aIndex, PRUint8 aMethod, PRBool *aSelState);
- nsresult AppendFlatStringFromSubtree(nsIContent *aContent, nsAString *aFlatString)
- { return NS_OK; } // Overrides base impl in nsAccessible
// nsIDOMXULMultiSelectControlElement inherits from this, so we'll always have
// one of these if the widget is valid and not defunct
nsCOMPtr<nsIDOMXULSelectControlElement> mSelectControl;
};
/* Accessible for supporting XUL menus
*/
--- a/accessible/src/xul/nsXULTextAccessible.cpp
+++ b/accessible/src/xul/nsXULTextAccessible.cpp
@@ -160,22 +160,25 @@ nsXULLinkAccessible::GetValue(nsAString&
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::href, aValue);
return NS_OK;
}
nsresult
nsXULLinkAccessible::GetNameInternal(nsAString& aName)
{
+ if (IsDefunct())
+ return NS_ERROR_FAILURE;
+
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::value, aName);
if (!aName.IsEmpty())
return NS_OK;
- return AppendFlatStringFromSubtree(content, &aName);
+ return nsTextEquivUtils::GetNameFromSubtree(this, aName);
}
NS_IMETHODIMP
nsXULLinkAccessible::GetRole(PRUint32 *aRole)
{
NS_ENSURE_ARG_POINTER(aRole);
*aRole = nsIAccessibleRole::ROLE_LINK;
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -73,44 +73,51 @@ include $(topsrcdir)/config/rules.mk
test_groupattrs.xul \
test_groupattrs.html \
test_name_markup.html \
$(warning test_table_indexes.html temporarily disabled) \
test_nsIAccessible_actions.html \
$(warning test_nsIAccessible_actions.xul temporarily disabled) \
test_nsIAccessible_applicationAccessible.html \
test_nsIAccessible_comboboxes.xul \
- test_nsIAccessible_editablebody.html \
- test_nsIAccessible_editabledoc.html \
test_nsIAccessible_name.html \
test_nsIAccessible_name_button.html \
test_nsIAccessible_name_link.html \
- $(warning test_nsIAccessible_name.xul temporarily disabled) \
+ test_nsIAccessible_name.xul \
test_nsIAccessible_selects.html \
test_nsIAccessible_focus.html \
test_nsIAccessibleDocument.html \
test_nsIAccessibleEditableText.html \
test_nsIAccessibleHyperLink.html \
$(warning test_nsIAccessibleHyperLink.xul temporarily disabled) \
test_nsIAccessibleHyperText.html \
test_nsIAccessibleImage.html \
test_nsIAccessibleTable_1.html \
test_nsIAccessibleTable_2.html \
test_nsIAccessibleTable_3.html \
test_nsIAccessibleTable_4.html \
$(warning test_nsIAccessibleTable_listboxes.xul temporarily disabled) \
test_nsIAccessNode_utils.html \
test_nsOuterDocAccessible.html \
+ test_objectattrs.html \
test_relations.html \
test_relations.xul \
test_role_nsHyperTextAcc.html \
test_role_table_cells.html \
test_states.html \
+ test_states_editablebody.html \
+ test_states_doc.html \
+ test_states_docarticle.html \
+ test_states_frames.html \
test_textattrs.html \
test_textboxes.html \
test_textboxes.xul \
testTextboxes.js \
test_bug429285.html \
test_bug434464.html \
+ z_states_frame.html \
+ z_states_framearticle.html \
+ z_states_framecheckbox.html \
+ z_states_frametextbox.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
--- a/accessible/tests/mochitest/attributes.js
+++ b/accessible/tests/mochitest/attributes.js
@@ -1,162 +1,198 @@
-////////////////////////////////////////////////////////////////////////////////
-// Object attributes.
-
-/**
- * Test object attributes.
- *
- * @param aAccOrElmOrID [in] the ID, DOM node or accessible
- * @param aAttrs [in] the map of expected object attributes
- * (name/value pairs)
- * @param aSkipUnexpectedAttrs [in] points this function doesn't fail if
- * unexpected attribute is encountered
- */
-function testAttrs(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs)
-{
- var accessible = getAccessible(aAccOrElmOrID);
- if (!accessible)
- return;
-
- var attrs = null;
- try {
- attrs = accessible.attributes;
- } catch (e) { }
-
- if (!attrs) {
- ok(false, "Can't get object attributes for " + aAccOrElmOrID);
- return;
- }
-
- var errorMsg = " for " + aAccOrElmOrID;
- compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
-}
-
-/**
- * Test group object attributes (posinset, setsize and level)
- *
- * @param aAccOrElmOrID [in] the ID, DOM node or accessible
- * @param aPosInSet [in] the value of 'posinset' attribute
- * @param aSetSize [in] the value of 'setsize' attribute
- * @param aLevel [in, optional] the value of 'level' attribute
- */
-function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
-{
- var attrs = {
- "posinset": String(aPosInSet),
- "setsize": String(aSetSize)
- };
-
- if (aLevel)
- attrs["level"] = String(aLevel);
-
- testAttrs(aAccOrElmOrID, attrs, true);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Text attributes.
-
-/**
- * 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)
- * @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, 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) {
- }
-
- 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);
-}
-
-/**
- * Test default text attributes.
- *
- * @param aID [in] the ID of DOM element having text
- * accessible
- * @param aDefAttrs [in] the map of expected text attributes
- * (name/value pairs)
- * @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
- * unexpected attribute is encountered
- */
-function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs)
-{
- var accessible = getAccessible(aID, [nsIAccessibleText]);
- if (!accessible)
- return;
-
- var defAttrs = null;
- try{
- defAttrs = accessible.defaultTextAttributes;
- } catch (e) {
- }
-
- if (!defAttrs) {
- ok(false, "Can't get default text attributes for " + aID);
- return;
- }
-
- var errorMsg = ". Getting default text attributes for " + aID;
- compareAttrs(errorMsg, defAttrs, aDefAttrs, aSkipUnexpectedAttrs);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private.
-
-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)
- ok(false, "Unexpected attribute '" + prop.key + "' having '" +
- prop.value + "'" + aErrorMsg);
- } else {
- is(prop.value, aExpectedAttrs[prop.key],
- "Attribute '" + prop.key + " 'has wrong value" + aErrorMsg);
- }
- }
-
- for (var name in aExpectedAttrs) {
- var value = "";
- try {
- value = aAttrs.getStringProperty(name);
- } catch(e) { }
-
- if (!value)
- ok(false,
- "There is no expected attribute '" + name + "' " + aErrorMsg);
- }
-}
+////////////////////////////////////////////////////////////////////////////////
+// Object attributes.
+
+/**
+ * Test object attributes.
+ *
+ * @param aAccOrElmOrID [in] the ID, DOM node or accessible
+ * @param aAttrs [in] the map of expected object attributes
+ * (name/value pairs)
+ * @param aSkipUnexpectedAttrs [in] points this function doesn't fail if
+ * unexpected attribute is encountered
+ */
+function testAttrs(aAccOrElmOrID, aAttrs, aSkipUnexpectedAttrs)
+{
+ var accessible = getAccessible(aAccOrElmOrID);
+ if (!accessible)
+ return;
+
+ var attrs = null;
+ try {
+ attrs = accessible.attributes;
+ } catch (e) { }
+
+ if (!attrs) {
+ ok(false, "Can't get object attributes for " + aAccOrElmOrID);
+ return;
+ }
+
+ var errorMsg = " for " + aAccOrElmOrID;
+ compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
+}
+
+/**
+ * Test group object attributes (posinset, setsize and level)
+ *
+ * @param aAccOrElmOrID [in] the ID, DOM node or accessible
+ * @param aPosInSet [in] the value of 'posinset' attribute
+ * @param aSetSize [in] the value of 'setsize' attribute
+ * @param aLevel [in, optional] the value of 'level' attribute
+ */
+function testGroupAttrs(aAccOrElmOrID, aPosInSet, aSetSize, aLevel)
+{
+ var attrs = {
+ "posinset": String(aPosInSet),
+ "setsize": String(aSetSize)
+ };
+
+ if (aLevel)
+ attrs["level"] = String(aLevel);
+
+ testAttrs(aAccOrElmOrID, attrs, true);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Text attributes.
+
+/**
+ * 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
+ * @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)
+{
+ var accessible = getAccessible(aID, [nsIAccessibleText]);
+ if (!accessible)
+ return;
+
+ var startOffset = { value: -1 };
+ var endOffset = { value: -1 };
+
+ // do not include attributes exposed on hyper text accessbile
+ var attrs = getTextAttributes(aID, accessible, false, aOffset,
+ startOffset, endOffset);
+
+ if (!attrs)
+ 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
+ * (name/value pairs)
+ * @param aSkipUnexpectedAttrs [in] points the function doesn't fail if
+ * unexpected attribute is encountered
+ */
+function testDefaultTextAttrs(aID, aDefAttrs, aSkipUnexpectedAttrs)
+{
+ var accessible = getAccessible(aID, [nsIAccessibleText]);
+ if (!accessible)
+ return;
+
+ var defAttrs = null;
+ try{
+ defAttrs = accessible.defaultTextAttributes;
+ } catch (e) {
+ }
+
+ if (!defAttrs) {
+ ok(false, "Can't get default text attributes for " + aID);
+ return;
+ }
+
+ 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)
+ ok(false, "Unexpected attribute '" + prop.key + "' having '" +
+ prop.value + "'" + aErrorMsg);
+ } else {
+ is(prop.value, aExpectedAttrs[prop.key],
+ "Attribute '" + prop.key + " 'has wrong value" + aErrorMsg);
+ }
+ }
+
+ for (var name in aExpectedAttrs) {
+ var value = "";
+ try {
+ value = aAttrs.getStringProperty(name);
+ } catch(e) { }
+
+ if (!value)
+ ok(false,
+ "There is no expected attribute '" + name + "' " + aErrorMsg);
+ }
+}
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -173,16 +173,19 @@ function getNode(aNodeOrID)
* to query it/them from obtained accessible
* @param aElmObj [out, optional] object to store DOM element which
* accessible is obtained for
* @param aDoNotFailIfNoAcc [in, optional] no error if the given identifier is
* not accessible
*/
function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIfNoAcc)
{
+ if (!aAccOrElmOrID)
+ return;
+
var elm = null;
if (aAccOrElmOrID instanceof nsIAccessible) {
aAccOrElmOrID.QueryInterface(nsIAccessNode);
elm = aAccOrElmOrID.DOMNode;
} else if (aAccOrElmOrID instanceof nsIDOMNode) {
elm = aAccOrElmOrID;
@@ -242,16 +245,37 @@ function getAccessible(aAccOrElmOrID, aI
* Return true if the given identifier has an accessible.
*/
function isAccessible(aAccOrElmOrID)
{
return getAccessible(aAccOrElmOrID, null, null, true) ? true : false;
}
/**
+ * Run through accessible tree of the given identifier so that we ensure
+ * accessible tree is created.
+ */
+function ensureAccessibleTree(aAccOrElmOrID)
+{
+ var acc = getAccessible(aAccOrElmOrID);
+ if (!acc)
+ return;
+
+ var child = acc.firstChild;
+ while (child) {
+ ensureAccessibleTree(child);
+ try {
+ child = child.nextSibling;
+ } catch (e) {
+ child = null;
+ }
+ }
+}
+
+/**
* Convert role to human readable string.
*/
function roleToString(aRole)
{
return gAccRetrieval.getStringRole(aRole);
}
/**
--- a/accessible/tests/mochitest/events.js
+++ b/accessible/tests/mochitest/events.js
@@ -1,17 +1,55 @@
+////////////////////////////////////////////////////////////////////////////////
+// Constants
+
+const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
+const EVENT_DOM_DESTROY = nsIAccessibleEvent.EVENT_DOM_DESTROY;
+
////////////////////////////////////////////////////////////////////////////////
// General
/**
* Set up this variable to dump events into DOM.
*/
var gA11yEventDumpID = "";
/**
+ * Executes the function when requested event is handled.
+ *
+ * @param aEventType [in] event type
+ * @param aTarget [in] event target
+ * @param aFunc [in] function to call when event is handled
+ * @param aContext [in, optional] object in which context the function is
+ * called
+ * @param aArg1 [in, optional] argument passed into the function
+ * @param aArg2 [in, optional] argument passed into the function
+ */
+function waitForEvent(aEventType, aTarget, aFunc, aContext, aArg1, aArg2)
+{
+ var handler = {
+ handleEvent: function handleEvent(aEvent) {
+ if (!aTarget || aTarget == aEvent.DOMNode) {
+ unregisterA11yEventListener(aEventType, this);
+
+ window.setTimeout(
+ function ()
+ {
+ aFunc.call(aContext, aArg1, aArg2);
+ },
+ 0
+ );
+ }
+ }
+ };
+
+ registerA11yEventListener(aEventType, handler);
+}
+
+/**
* Register accessibility event listener.
*
* @param aEventType the accessible event type (see nsIAccessibleEvent for
* available constants).
* @param aEventHandler event listener object, when accessible event of the
* given type is handled then 'handleEvent' method of
* this object is invoked with nsIAccessibleEvent object
* as the first argument.
@@ -381,13 +419,16 @@ function removeA11yEventListener(aEventT
delete gA11yEventListeners[aEventType];
}
return true;
}
function dumpInfoToDOM(aInfo)
{
+ if (!gA11yEventDumpID)
+ return;
+
var dumpElm = document.getElementById(gA11yEventDumpID);
var div = document.createElement("div");
div.textContent = aInfo;
dumpElm.appendChild(div);
}
--- a/accessible/tests/mochitest/namerules.xml
+++ b/accessible/tests/mochitest/namerules.xml
@@ -114,16 +114,17 @@
</ruleset>
<ruleset id="htmloption">
<ruleset ref="aria"/>
<rule attr="label" type="string"/>
<rule fromsubtree="true"/>
<rule attr="title" type="string"/>
</ruleset>
+
</ruledfn>
<rulesample>
<markup ref="html:button" ruleset="htmlctrl">
<html:span id="l1" a11yname="test2">test2</html:span>
<html:span id="l2" a11yname="test3">test3</html:span>
<html:label for="btn" a11yname="test4">test4</html:label>
@@ -188,22 +189,23 @@
<html:span id="l2" a11yname="test3">test3</html:span>
<html:label for="gc" a11yname="test4">test4</html:label>
<html:table>
<html:tr>
<html:td id="gc"
role="gridcell"
aria-label="test1"
aria-labelledby="l1 l2"
- a11yname=" This is a paragraph This is a link This is a list"
+ a11yname="This is a paragraph This is a link • Listitem1 • Listitem2"
title="This is a paragraph This is a link This is a list">
<html:p>This is a paragraph</html:p>
<html:a href="#">This is a link</html:a>
<html:ul>
- <html:li>This is a list</html:li>
+ <html:li>Listitem1</html:li>
+ <html:li>Listitem2</html:li>
</html:ul>
</html:td>
</html:tr>
</html:table>
</markup>
</rulesample>
--- a/accessible/tests/mochitest/nsIAccessible_name.js
+++ b/accessible/tests/mochitest/nsIAccessible_name.js
@@ -1,207 +1,284 @@
-function testName(aAccOrElmOrID, aName, aMsg)
-{
- var msg = aMsg ? aMsg : "";
-
- var acc = getAccessible(aAccOrElmOrID);
- if (!acc) {
- ok(false, msg + "No accessible for " + aAccOrElmOrID + "!");
- }
-
- try {
- is(acc.name, aName, msg + "Wrong name of the accessible for " + aAccOrElmOrID);
- } catch (e) {
- ok(false, msg + "Can't get name of the accessible for " + aAccOrElmOrID);
- }
- return acc;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Name tests described by "namerules.xml" file.
-
-var gNameRulesFileURL =
- "chrome://mochikit/content/a11y/accessible/namerules.xml";
-
-var gRuleDoc = null;
-
-/**
- * Start name tests. Run through markup elements and test names for test
- * element (see namerules.xml for details).
- */
-function testNames()
-{
- var request = new XMLHttpRequest();
- request.open("get", gNameRulesFileURL, false);
- request.send();
-
- gRuleDoc = request.responseXML;
-
- var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup");
- for (var idx = 0; idx < markupElms.length; idx++)
- testNamesForMarkup(markupElms[idx]);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private section.
-
-/**
- * Process every 'markup' element and test names for it. Used by testNames
- * function.
- */
-function testNamesForMarkup(aMarkupElm)
-{
- var div = document.createElement("div");
- div.setAttribute("test", "test");
-
- var child = aMarkupElm.firstChild;
- while (child) {
- var newChild = document.importNode(child, true);
- div.appendChild(newChild);
- child = child.nextSibling;
- }
- document.body.appendChild(div);
-
- var serializer = new XMLSerializer();
-
- var expr = "//html/body/div[@test='test']/" + aMarkupElm.getAttribute("ref");
- var elms = evaluateXPath(document, expr, htmlDocResolver);
-
- var ruleId = aMarkupElm.getAttribute("ruleset");
- var ruleElms = getRuleElmsByRulesetId(ruleId);
-
- for (var idx = 0; idx < ruleElms.length; idx++)
- testNameForRule(elms[0], ruleElms[idx]);
-
- document.body.removeChild(div);
-}
-
-/**
- * Test name for current rule and current 'markup' element. Used by
- * testNamesForMarkup function.
- */
-function testNameForRule(aElm, aRule)
-{
- var attr = aRule.getAttribute("attr");
- if (attr) {
- var name = "";
- var attrValue = aElm.getAttribute(attr);
-
- var type = aRule.getAttribute("type");
- if (type == "string") {
- name = attrValue;
-
- } else if (type == "ref") {
- var ids = attrValue.split(/\s+/);///\,\s*/);
- for (var idx = 0; idx < ids.length; idx++) {
- var labelElm = getNode(ids[idx]);
- if (name != "")
- name += " ";
-
- name += labelElm.getAttribute("a11yname");
- }
- }
-
- var msg = "Attribute '" + attr + "' test. ";
- testName(aElm, name, msg);
- aElm.removeAttribute(attr);
- return;
- }
-
- var elm = aRule.getAttribute("elm");
- var elmattr = aRule.getAttribute("elmattr");
- if (elm && elmattr) {
- var filter = {
- acceptNode: function filter_acceptNode(aNode)
- {
- if (aNode.localName == this.mLocalName &&
- aNode.getAttribute(this.mAttrName) == this.mAttrValue)
- return NodeFilter.FILTER_ACCEPT;
-
- return NodeFilter.FILTER_SKIP;
- },
-
- mLocalName: elm,
- mAttrName: elmattr,
- mAttrValue: aElm.getAttribute("id")
- };
-
- var treeWalker = document.createTreeWalker(document.body,
- NodeFilter.SHOW_ELEMENT,
- filter, false);
- var labelElm = treeWalker.nextNode();
- var msg = "Element '" + elm + "' test.";
- testName(aElm, labelElm.getAttribute("a11yname"), msg);
- labelElm.parentNode.removeChild(labelElm);
- return;
- }
-
- var fromSubtree = aRule.getAttribute("fromsubtree");
- if (fromSubtree == "true") {
- var msg = "From subtree test.";
- testName(aElm, aElm.getAttribute("a11yname"), msg);
- while (aElm.firstChild)
- aElm.removeChild(aElm.firstChild);
- return;
- }
-}
-
-/**
- * Return array of 'rule' elements. Used in conjunction with
- * getRuleElmsFromRulesetElm() function.
- */
-function getRuleElmsByRulesetId(aRulesetId)
-{
- var expr = "//rules/ruledfn/ruleset[@id='" + aRulesetId + "']";
- var rulesetElm = evaluateXPath(gRuleDoc, expr);
- return getRuleElmsFromRulesetElm(rulesetElm[0]);
-}
-
-function getRuleElmsFromRulesetElm(aRulesetElm)
-{
- var rulesetId = aRulesetElm.getAttribute("ref");
- if (rulesetId)
- return getRuleElmsByRulesetId(rulesetId);
-
- var ruleElms = [];
-
- var child = aRulesetElm.firstChild;
- while (child) {
- if (child.localName == "ruleset")
- ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child));
- if (child.localName == "rule")
- ruleElms.push(child);
-
- child = child.nextSibling;
- }
-
- return ruleElms;
-}
-
-/**
- * Helper method to evaluate xpath expression.
- */
-function evaluateXPath(aNode, aExpr, aResolver)
-{
- var xpe = new XPathEvaluator();
-
- var resolver = aResolver;
- if (!resolver) {
- var node = aNode.ownerDocument == null ?
- aNode.documentElement : aNode.ownerDocument.documentElement;
- resolver = xpe.createNSResolver(node);
- }
-
- var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
- var found = [];
- var res;
- while (res = result.iterateNext())
- found.push(res);
-
- return found;
-}
-
-function htmlDocResolver(aPrefix) {
- var ns = {
- 'html' : 'http://www.w3.org/1999/xhtml'
- };
- return ns[aPrefix] || null;
-}
+function testName(aAccOrElmOrID, aName, aMsg)
+{
+ var msg = aMsg ? aMsg : "";
+
+ var acc = getAccessible(aAccOrElmOrID);
+ if (!acc)
+ return;
+
+ try {
+ is(acc.name, aName, msg + "Wrong name of the accessible for " + aAccOrElmOrID);
+ } catch (e) {
+ ok(false, msg + "Can't get name of the accessible for " + aAccOrElmOrID);
+ }
+ return acc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Name tests described by "namerules.xml" file.
+
+var gNameRulesFileURL =
+ "chrome://mochikit/content/a11y/accessible/namerules.xml";
+
+var gRuleDoc = null;
+
+/**
+ * Start name tests. Run through markup elements and test names for test
+ * element (see namerules.xml for details).
+ */
+function testNames()
+{
+ var request = new XMLHttpRequest();
+ request.open("get", gNameRulesFileURL, false);
+ request.send();
+
+ gRuleDoc = request.responseXML;
+
+ var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup");
+ gTestIterator.iterateMarkups(markupElms);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Private section.
+
+/**
+ * Helper class to interate through name tests.
+ */
+var gTestIterator =
+{
+ iterateMarkups: function gTestIterator_iterateMarkups(aMarkupElms)
+ {
+ this.markupElms = aMarkupElms;
+
+ this.iterateNext();
+ },
+
+ iterateRules: function gTestIterator_iterateRules(aElm, aContainer, aRuleElms)
+ {
+ this.ruleElms = aRuleElms;
+ this.elm = aElm;
+ this.container = aContainer;
+
+ this.iterateNext();
+ },
+
+ iterateNext: function gTestIterator_iterateNext()
+ {
+ if (this.markupIdx == -1) {
+ this.markupIdx++;
+ testNamesForMarkup(this.markupElms[this.markupIdx]);
+ return;
+ }
+
+ this.ruleIdx++;
+ if (this.ruleIdx == this.ruleElms.length) {
+ this.markupIdx++;
+ if (this.markupIdx == this.markupElms.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ document.body.removeChild(this.container);
+
+ this.ruleIdx = -1;
+ testNamesForMarkup(this.markupElms[this.markupIdx]);
+ return;
+ }
+
+ testNameForRule(this.elm, this.ruleElms[this.ruleIdx]);
+ },
+
+ markupElms: null,
+ markupIdx: -1,
+ ruleElms: null,
+ ruleIdx: -1,
+ elm: null,
+ container: null
+};
+
+/**
+ * Process every 'markup' element and test names for it. Used by testNames
+ * function.
+ */
+function testNamesForMarkup(aMarkupElm)
+{
+ var div = document.createElement("div");
+ div.setAttribute("id", "test");
+
+ var child = aMarkupElm.firstChild;
+ while (child) {
+ var newChild = document.importNode(child, true);
+ div.appendChild(newChild);
+ child = child.nextSibling;
+ }
+
+ waitForEvent(EVENT_REORDER, document, testNamesForMarkupRules,
+ null, aMarkupElm, div);
+
+ document.body.appendChild(div);
+}
+
+function testNamesForMarkupRules(aMarkupElm, aContainer)
+{
+ ensureAccessibleTree(aContainer);
+
+ var serializer = new XMLSerializer();
+
+ var expr = "//html/body/div[@id='test']/" + aMarkupElm.getAttribute("ref");
+ var elms = evaluateXPath(document, expr, htmlDocResolver);
+
+ var ruleId = aMarkupElm.getAttribute("ruleset");
+ var ruleElms = getRuleElmsByRulesetId(ruleId);
+
+ gTestIterator.iterateRules(elms[0], aContainer, ruleElms);
+}
+
+/**
+ * Test name for current rule and current 'markup' element. Used by
+ * testNamesForMarkup function.
+ */
+function testNameForRule(aElm, aRuleElm)
+{
+ if (aRuleElm.hasAttribute("attr"))
+ testNameForAttrRule(aElm, aRuleElm);
+ else if (aRuleElm.hasAttribute("elm") && aRuleElm.hasAttribute("elmattr"))
+ testNameForElmRule(aElm, aRuleElm);
+ else if (aRuleElm.getAttribute("fromsubtree") == "true")
+ testNameForSubtreeRule(aElm, aRuleElm);
+}
+
+function testNameForAttrRule(aElm, aRule)
+{
+ var name = "";
+
+ var attr = aRule.getAttribute("attr");
+ var attrValue = aElm.getAttribute(attr);
+
+ var type = aRule.getAttribute("type");
+ if (type == "string") {
+ name = attrValue;
+
+ } else if (type == "ref") {
+ var ids = attrValue.split(/\s+/);
+ for (var idx = 0; idx < ids.length; idx++) {
+ var labelElm = getNode(ids[idx]);
+ if (name != "")
+ name += " ";
+
+ name += labelElm.getAttribute("a11yname");
+ }
+ }
+
+ var msg = "Attribute '" + attr + "' test. ";
+ testName(aElm, name, msg);
+ aElm.removeAttribute(attr);
+
+ gTestIterator.iterateNext();
+}
+
+function testNameForElmRule(aElm, aRule)
+{
+ var elm = aRule.getAttribute("elm");
+ var elmattr = aRule.getAttribute("elmattr");
+
+ var filter = {
+ acceptNode: function filter_acceptNode(aNode)
+ {
+ if (aNode.localName == this.mLocalName &&
+ aNode.getAttribute(this.mAttrName) == this.mAttrValue)
+ return NodeFilter.FILTER_ACCEPT;
+
+ return NodeFilter.FILTER_SKIP;
+ },
+
+ mLocalName: elm,
+ mAttrName: elmattr,
+ mAttrValue: aElm.getAttribute("id")
+ };
+
+ var treeWalker = document.createTreeWalker(document.body,
+ NodeFilter.SHOW_ELEMENT,
+ filter, false);
+ var labelElm = treeWalker.nextNode();
+ var msg = "Element '" + elm + "' test.";
+ testName(aElm, labelElm.getAttribute("a11yname"), msg);
+
+ var parentNode = labelElm.parentNode;
+ waitForEvent(EVENT_REORDER, parentNode,
+ gTestIterator.iterateNext, gTestIterator);
+
+ parentNode.removeChild(labelElm);
+}
+
+function testNameForSubtreeRule(aElm, aRule)
+{
+ var msg = "From subtree test.";
+ testName(aElm, aElm.getAttribute("a11yname"), msg);
+
+ waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
+
+ while (aElm.firstChild)
+ aElm.removeChild(aElm.firstChild);
+}
+
+/**
+ * Return array of 'rule' elements. Used in conjunction with
+ * getRuleElmsFromRulesetElm() function.
+ */
+function getRuleElmsByRulesetId(aRulesetId)
+{
+ var expr = "//rules/ruledfn/ruleset[@id='" + aRulesetId + "']";
+ var rulesetElm = evaluateXPath(gRuleDoc, expr);
+ return getRuleElmsFromRulesetElm(rulesetElm[0]);
+}
+
+function getRuleElmsFromRulesetElm(aRulesetElm)
+{
+ var rulesetId = aRulesetElm.getAttribute("ref");
+ if (rulesetId)
+ return getRuleElmsByRulesetId(rulesetId);
+
+ var ruleElms = [];
+
+ var child = aRulesetElm.firstChild;
+ while (child) {
+ if (child.localName == "ruleset")
+ ruleElms = ruleElms.concat(getRuleElmsFromRulesetElm(child));
+ if (child.localName == "rule")
+ ruleElms.push(child);
+
+ child = child.nextSibling;
+ }
+
+ return ruleElms;
+}
+
+/**
+ * Helper method to evaluate xpath expression.
+ */
+function evaluateXPath(aNode, aExpr, aResolver)
+{
+ var xpe = new XPathEvaluator();
+
+ var resolver = aResolver;
+ if (!resolver) {
+ var node = aNode.ownerDocument == null ?
+ aNode.documentElement : aNode.ownerDocument.documentElement;
+ resolver = xpe.createNSResolver(node);
+ }
+
+ var result = xpe.evaluate(aExpr, aNode, resolver, 0, null);
+ var found = [];
+ var res;
+ while (res = result.iterateNext())
+ found.push(res);
+
+ return found;
+}
+
+function htmlDocResolver(aPrefix) {
+ var ns = {
+ 'html' : 'http://www.w3.org/1999/xhtml'
+ };
+ return ns[aPrefix] || null;
+}
--- a/accessible/tests/mochitest/test_aria_token_attrs.html
+++ b/accessible/tests/mochitest/test_aria_token_attrs.html
@@ -50,21 +50,21 @@ https://bugzilla.mozilla.org/show_bug.cg
testStates("native_checkbox_nativeunchecked_ariatrue", STATE_CHECKABLE, 0, STATE_CHECKED);
testStates("native_checkbox_nativeunchecked_ariafalse", STATE_CHECKABLE, 0, STATE_CHECKED);
testStates("native_checkbox_nativeunchecked_ariaempty", STATE_CHECKABLE, 0, STATE_CHECKED);
testStates("native_checkbox_nativeunchecked_ariaundefined", STATE_CHECKABLE, 0, STATE_CHECKED);
testStates("native_checkbox_nativeunchecked_ariaabsent", STATE_CHECKABLE, 0, STATE_CHECKED);
// test button aria-pressed states
- testStates("button_pressed_true", STATE_PRESSED);
- testStates("button_pressed_false", 0, 0, STATE_PRESSED);
- testStates("button_pressed_empty", 0, 0, STATE_PRESSED);
- testStates("button_pressed_undefined", 0, 0, STATE_PRESSED);
- testStates("button_pressed_absent", 0, 0, STATE_PRESSED);
+ testStates("button_pressed_true", STATE_PRESSED | STATE_CHECKABLE);
+ testStates("button_pressed_false", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
+ testStates("button_pressed_empty", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
+ testStates("button_pressed_undefined", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
+ testStates("button_pressed_absent", 0, 0, STATE_PRESSED | STATE_CHECKABLE);
// test aria-pressed state mapping to roles PUSHBUTTON vs TOGGLEBUTTON
var aButton = getAccessible("button_pressed_true");
if (aButton)
is(aButton.finalRole, ROLE_TOGGLE_BUTTON, "Wrong role for togglebutton!");
aButton = getAccessible("button_pressed_false");
if (aButton)
is(aButton.finalRole, ROLE_TOGGLE_BUTTON, "Wrong role for togglebutton!");
--- a/accessible/tests/mochitest/test_bug420863.html
+++ b/accessible/tests/mochitest/test_bug420863.html
@@ -1,138 +1,138 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=420863
--->
-<head>
- <title>Table indexes chrome tests</title>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-
- <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
- <script type="application/javascript">
- var gAccService = null;
-
- var gTdClickAttr = false;
- var gTdClickEventHandler = false;
- var gClickHandler = null;
-
- var gID = "";
- var gNode = null;
- var gAcc = null;
-
- function doTest()
- {
- const nsIAccessibleRetrieval =
- Components.interfaces.nsIAccessibleRetrieval;
-
- gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
- getService(nsIAccessibleRetrieval);
-
- // Actions should be exposed on any accessible having related DOM node
- // with registered 'click' event handler.
-
- //////////////////////////////////////////////////////////////////////////
- // generic td
- gID = "td1";
- gNode = document.getElementById(gID);
- gAcc = gAccService.getAccessibleFor(gNode);
-
- is(gAcc.numActions, 0, gID + ": shouldn't have actions");
-
- //////////////////////////////////////////////////////////////////////////
- // td with 'onclick' attribute
- gID = "td2";
- gNode = document.getElementById(gID);
- gAcc = gAccService.getAccessibleFor(gNode);
-
- is(gAcc.numActions, 1, gID + ": should have one action");
- is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
- gAcc.doAction(0);
-
- // actions are performed via timeout
- window.setTimeout(doTest2, 0);
- }
-
- function doTest2()
- {
- //////////////////////////////////////////////////////////////////////////
- // td with 'onclick' attribute (sequel, see doTest1())
- ok(gTdClickAttr, gID + ": 'click' action hasn't been performed");
-
- //////////////////////////////////////////////////////////////////////////
- // td with registered 'click' event handler
- gID = "td3";
- gNode = document.getElementById(gID);
- gAcc = gAccService.getAccessibleFor(gNode);
-
- // register 'click' event handler
- gClickHandler = {
- handleEvent: function handleEvent(aEvent)
- {
- gTdClickEventHandler = true;
- }
- };
- gNode.addEventListener("click", gClickHandler, false);
-
- // check actions
- is(gAcc.numActions, 1, gID + ": should have one action");
- is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
- gAcc.doAction(0);
-
- // actions are performed via timeout
- window.setTimeout(doTest3, 0);
- }
-
- function doTest3()
- {
- //////////////////////////////////////////////////////////////////////////
- // td with registered 'click' event handler (sequel, see doTest2())
- ok(gTdClickEventHandler, gID + ": 'click' action hasn't been performed");
-
- // unregister click event handler
- gNode.removeEventListener("click", gClickHandler, false);
-
- // check actions
- // XXX see bug 456347, sometimes after removing the event listener, the
- // accessible is no longer valid. When fixing that bug, remove the
- // try/exception and simply test for the gAcc.numActions value directly.
- var numActions = -1;
- try {
- numActions = gAcc.numActions;
- } catch(e) {}
-
- if (numActions == -1)
- todo(false,
- "gAcc.numActions should not throw after click handler was removed!");
- else
- is(numActions, 0, gID + ": shouldn't have actions");
-
- SimpleTest.finish();
- }
-
- SimpleTest.waitForExplicitFinish();
- addLoadEvent(doTest);
- </script>
-</head>
-<body>
-
- <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=420863"
- title="If an HTML element has an onClick attribute, expose its click action on the element rather than its child text leaf node."
- target="_blank">Mozilla Bug 420863</a>
- <p id="display"></p>
- <div id="content" style="display: none"></div>
- <pre id="test">
- </pre>
-
- <table>
- <tr>
- <td id="td1">Can't click this cell</td>
- <td onclick="gTdClickAttr = true;"
- id="td2">Cell with 'onclick' attribute</td>
- <td id="td3">Cell with registered 'click' event handler</td>
- </tr>
- </table>
-
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=420863
+-->
+<head>
+ <title>Table indexes chrome tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ var gAccService = null;
+
+ var gTdClickAttr = false;
+ var gTdClickEventHandler = false;
+ var gClickHandler = null;
+
+ var gID = "";
+ var gNode = null;
+ var gAcc = null;
+
+ function doTest()
+ {
+ const nsIAccessibleRetrieval =
+ Components.interfaces.nsIAccessibleRetrieval;
+
+ gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+ // Actions should be exposed on any accessible having related DOM node
+ // with registered 'click' event handler.
+
+ //////////////////////////////////////////////////////////////////////////
+ // generic td
+ gID = "td1";
+ gNode = document.getElementById(gID);
+ gAcc = gAccService.getAccessibleFor(gNode);
+
+ is(gAcc.numActions, 0, gID + ": shouldn't have actions");
+
+ //////////////////////////////////////////////////////////////////////////
+ // td with 'onclick' attribute
+ gID = "td2";
+ gNode = document.getElementById(gID);
+ gAcc = gAccService.getAccessibleFor(gNode);
+
+ is(gAcc.numActions, 1, gID + ": should have one action");
+ is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
+ gAcc.doAction(0);
+
+ // actions are performed via timeout
+ window.setTimeout(doTest2, 0);
+ }
+
+ function doTest2()
+ {
+ //////////////////////////////////////////////////////////////////////////
+ // td with 'onclick' attribute (sequel, see doTest1())
+ ok(gTdClickAttr, gID + ": 'click' action hasn't been performed");
+
+ //////////////////////////////////////////////////////////////////////////
+ // td with registered 'click' event handler
+ gID = "td3";
+ gNode = document.getElementById(gID);
+ gAcc = gAccService.getAccessibleFor(gNode);
+
+ // register 'click' event handler
+ gClickHandler = {
+ handleEvent: function handleEvent(aEvent)
+ {
+ gTdClickEventHandler = true;
+ }
+ };
+ gNode.addEventListener("click", gClickHandler, false);
+
+ // check actions
+ is(gAcc.numActions, 1, gID + ": should have one action");
+ is(gAcc.getActionName(0), "click", gID + ": should have 'click' action");
+ gAcc.doAction(0);
+
+ // actions are performed via timeout
+ window.setTimeout(doTest3, 0);
+ }
+
+ function doTest3()
+ {
+ //////////////////////////////////////////////////////////////////////////
+ // td with registered 'click' event handler (sequel, see doTest2())
+ ok(gTdClickEventHandler, gID + ": 'click' action hasn't been performed");
+
+ // unregister click event handler
+ gNode.removeEventListener("click", gClickHandler, false);
+
+ // check actions
+ // XXX see bug 456347, sometimes after removing the event listener, the
+ // accessible is no longer valid. When fixing that bug, remove the
+ // try/exception and simply test for the gAcc.numActions value directly.
+ var numActions = -1;
+ try {
+ numActions = gAcc.numActions;
+ } catch(e) {}
+
+ if (numActions == -1)
+ todo(false,
+ "gAcc.numActions should not throw after click handler was removed!");
+ else
+ is(numActions, 0, gID + ": shouldn't have actions");
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=420863"
+ title="If an HTML element has an onClick attribute, expose its click action on the element rather than its child text leaf node."
+ target="_blank">Mozilla Bug 420863</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <table>
+ <tr>
+ <td id="td1">Can't click this cell</td>
+ <td onclick="gTdClickAttr = true;"
+ id="td2">Cell with 'onclick' attribute</td>
+ <td id="td3">Cell with registered 'click' event handler</td>
+ </tr>
+ </table>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/test_bug434464.html
+++ b/accessible/tests/mochitest/test_bug434464.html
@@ -1,88 +1,88 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=434464
--->
-<head>
- <title>Test NSIAccessNode cache invalidation</title>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-
- <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
- <script type="application/javascript">
- function doTest()
- {
- var accRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
- getService(Components.interfaces.nsIAccessibleRetrieval);
-
- var parentElm = document.getElementById("parent");
- if (!parentElm) {
- ok(false, "no parent element for paragraph!");
- SimpleTest.finish();
- }
-
- var elm = document.getElementById("para");
- if (!elm) {
- ok(false, "no element for paragraph!");
- SimpleTest.finish();
- }
-
- // It's currently hidden. Ask for its parent's nsIAccessNode.
- var parentElmAccNode = null;
- try {
- parentElmAccNode = accRetrieval.getAccessibleFor(parentElm).
- QueryInterface(Components.interfaces.nsIAccessNode);
- } catch(e) {}
-
- if (!parentElmAccNode) {
- ok(false, "No accessNode for parent of hidden paragraph!");
- SimpleTest.finish();
- }
-
- // Get the paragraph's accessNode.
- var elmAccNode = null;
- try {
- elmAccNode = parentElmAccNode.firstChildNode;
- } catch(e) {}
-
- if (!elmAccNode) {
- ok(false, "No accessNode for hidden paragraph!");
- SimpleTest.finish();
- }
-
- // Now make the paragraph visible. This invalidates the just-retrieved
- // AccessNode. An nsIAccessible should then be retrievable.
- elm.style.display = "block";
-
- // Now, get an accessible for it. Use a timeout so the layout engine can
- // catch up.
- window.setTimeout(
- function()
- {
- var elmAcc = null;
- try {
- elmAcc = accRetrieval.getAccessibleFor(elm);
- } catch(e) {}
-
- ok(elmAcc, "No accessible for paragraph after it became visible!");
-
- SimpleTest.finish();
- },
- 200);
- }
-
- SimpleTest.waitForExplicitFinish();
- addLoadEvent(doTest);
- </script>
-</head>
-<body>
-
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=434464">Mozilla Bug 434464</a>
- <p id="display"></p>
- <div id="content" style="display: none"></div>
- <pre id="test">
- </pre>
- <div id="parent"><p style="display: none;" id="para">I'm hidden initially, but then made visible.</p></div>
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=434464
+-->
+<head>
+ <title>Test NSIAccessNode cache invalidation</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ function doTest()
+ {
+ var accRetrieval = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(Components.interfaces.nsIAccessibleRetrieval);
+
+ var parentElm = document.getElementById("parent");
+ if (!parentElm) {
+ ok(false, "no parent element for paragraph!");
+ SimpleTest.finish();
+ }
+
+ var elm = document.getElementById("para");
+ if (!elm) {
+ ok(false, "no element for paragraph!");
+ SimpleTest.finish();
+ }
+
+ // It's currently hidden. Ask for its parent's nsIAccessNode.
+ var parentElmAccNode = null;
+ try {
+ parentElmAccNode = accRetrieval.getAccessibleFor(parentElm).
+ QueryInterface(Components.interfaces.nsIAccessNode);
+ } catch(e) {}
+
+ if (!parentElmAccNode) {
+ ok(false, "No accessNode for parent of hidden paragraph!");
+ SimpleTest.finish();
+ }
+
+ // Get the paragraph's accessNode.
+ var elmAccNode = null;
+ try {
+ elmAccNode = parentElmAccNode.firstChildNode;
+ } catch(e) {}
+
+ if (!elmAccNode) {
+ ok(false, "No accessNode for hidden paragraph!");
+ SimpleTest.finish();
+ }
+
+ // Now make the paragraph visible. This invalidates the just-retrieved
+ // AccessNode. An nsIAccessible should then be retrievable.
+ elm.style.display = "block";
+
+ // Now, get an accessible for it. Use a timeout so the layout engine can
+ // catch up.
+ window.setTimeout(
+ function()
+ {
+ var elmAcc = null;
+ try {
+ elmAcc = accRetrieval.getAccessibleFor(elm);
+ } catch(e) {}
+
+ ok(elmAcc, "No accessible for paragraph after it became visible!");
+
+ SimpleTest.finish();
+ },
+ 200);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=434464">Mozilla Bug 434464</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+ <div id="parent"><p style="display: none;" id="para">I'm hidden initially, but then made visible.</p></div>
+</body>
+</html>
--- a/accessible/tests/mochitest/test_name_markup.html
+++ b/accessible/tests/mochitest/test_name_markup.html
@@ -1,44 +1,41 @@
<html>
<head>
- <title>nsIAccessible::name calculation for HTML buttons</title>
+ <title>nsIAccessible::name calculation for elements</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
<script type="application/javascript"
+ src="chrome://mochikit/content/a11y/accessible/events.js"></script>
+ <script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/nsIAccessible_name.js"></script>
<script type="application/javascript">
- function doTest()
- {
- testNames();
-
- SimpleTest.finish();
- }
+ // gA11yEventDumpID = "eventdump";
SimpleTest.waitForExplicitFinish();
- addLoadEvent(doTest);
+ addA11yLoadEvent(testNames);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=459635"
- title="nsIAccessible::name calculation for HTML buttons">
+ title="nsIAccessible::name calculation for elements">
Mozilla Bug 459635
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
-
+ <div id="eventdump"></div>
</body>
</html>
--- a/accessible/tests/mochitest/test_nsIAccessible_name.html
+++ b/accessible/tests/mochitest/test_nsIAccessible_name.html
@@ -30,16 +30,20 @@
// Single relation. The value of 'aria-labelledby' contains the ID of
// an element. Gets the name from text node of that element.
testName("btn_labelledby_text", "text");
// Multiple relations. The value of 'aria-labelledby' contains the IDs
// of elements. Gets the name from text nodes of those elements.
testName("btn_labelledby_texts", "text1 text2");
+ //////////////////////////////////////////////////////////////////////////
+ // Name from named accessible
+
+ testName("input_labelledby_namedacc", "Data");
//////////////////////////////////////////////////////////////////////////
// Name from subtree (single relation labelled_by).
// Gets the name from text nodes contained by nested elements
testName("btn_labelledby_mixed", "nomore text");
// Gets the name from text nodes contained by nested elements, ignores
@@ -124,20 +128,31 @@
// new textarea name should reflect the value change.
var elem = document.getElementById("textareawithchild");
elem.value = "Bar";
testName("textareawithchild", "Story: Bar");
/////////////////////////////////////////////////////////////////////////
- // label with nested combobox
+ // label with nested combobox (test for 'f' item of name computation guide)
+
+ testName("comboinstart", "One day(s).");
+ testName("combo3", "day(s).");
testName("comboinmiddle", "Subscribe to ATOM feed.");
-
+ testName("combo4", "Subscribe to ATOM feed.");
+
+ testName("comboinmiddle2", "Play the Haliluya sound when new mail arrives");
+ testName("combo5", "Play the Haliluya sound when new mail arrives");
+ testName("checkbox", "Play the Haliluya sound when new mail arrives");
+
+ testName("comboinend", "This day was sunny");
+ testName("combo6", "This day was");
+
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
@@ -170,16 +185,22 @@
<!-- aria-labelledby, multiple relations -->
<span id="labelledby_text1">text1</span>
<span id="labelledby_text2">text2</span>
<button id="btn_labelledby_texts"
aria-labelledby="labelledby_text1 labelledby_text2">2</button>
<br/>
+ <!-- name from named accessible -->
+ <input id="labelledby_namedacc" type="checkbox"
+ aria-label="Data" />
+ <input id="input_labelledby_namedacc"
+ aria-labelledby="labelledby_namedacc" />
+
<!-- the name from subtree, mixed content -->
<span id="labelledby_mixed">no<span>more text</span></span>
<button id="btn_labelledby_mixed"
aria-labelledby="labelledby_mixed">3</button>
<br/>
<!-- the name from subtree, mixed/hidden content -->
<span id="labelledby_mixed_hidden_child">
@@ -281,22 +302,45 @@
<!-- A textarea nested in a label with a text child (bug #453371). -->
<form>
<label>Story:
<textarea id="textareawithchild" name="name">Foo</textarea>
</label>
</form>
- <!-- A label with a nested control in the middle -->
+ <!-- a label with a nested control in the start, middle and end -->
<form>
+ <label id="comboinstart"><select id="combo3">
+ <option>One</option>
+ <option>Two</option>
+ </select>
+ day(s).
+ </label>
+
<label id="comboinmiddle">
Subscribe to
- <select id="combo3" name="occupation">
+ <select id="combo4" name="occupation">
<option>ATOM</option>
<option>RSS</option>
</select>
feed.
</label>
+
+ <label id="comboinmiddle2" for="checkbox">Play the
+ <select id="combo5">
+ <option>Haliluya</option>
+ <option>Hurra</option>
+ </select>
+ sound when new mail arrives
+ </label>
+ <input id="checkbox" type="checkbox" />
+
+ <label id="comboinend">
+ This day was
+ <select id="combo6" name="occupation">
+ <option>sunny</option>
+ <option>rainy</option>
+ </select></label>
</form>
</body>
</html>
--- a/accessible/tests/mochitest/test_nsIAccessible_name.xul
+++ b/accessible/tests/mochitest/test_nsIAccessible_name.xul
@@ -35,16 +35,20 @@
// Single relation. The value of 'aria-labelledby' contains the ID of
// an element. Gets the name from text node of that element.
testName("btn_labelledby_text", "text");
// Multiple relations. The value of 'aria-labelledby' contains the IDs
// of elements. Gets the name from text nodes of those elements.
testName("btn_labelledby_texts", "text1 text2");
+ // Trick cases. Self and recursive referencing.
+ testName("rememberHistoryDays", "Remember 3 days");
+ testName("historyDays", "Remember 3 days");
+ testName("rememberAfter", null); // XUL labels doesn't allow name from subtree
//////////////////////////////////////////////////////////////////////////
// Name from subtree (single relation labelled_by).
// Gets the name from text nodes contained by nested elements.
testName("btn_labelledby_mixed", "nomore text");
// Gets the name from text nodes and selected item of menulist
@@ -96,27 +100,27 @@
//////////////////////////////////////////////////////////////////////////
// Name from the label element in anonymous content (see bug 362365).
// Get the name from anonymous label element for anonymous textbox
// (@anonid is used).
var ID = "box_label_anon1";
- var box1Acc = testName(ID, "");
+ var box1Acc = testName(ID, null);
if (box1Acc) {
var textboxAcc = box1Acc.firstChild;
is(textboxAcc.name, "Label",
"Wrong label for anonymous textbox of " + ID);
}
// Get the name from anonymous label element for anonymous textbox
// (@anonid is used). Nested bindings.
ID = "box_label_anon2";
- var box2Acc = testName(ID, "");
+ var box2Acc = testName(ID, null);
if (box2Acc) {
var textboxAcc = box2Acc.firstChild;
is(textboxAcc.name, "Label",
"Wrong label for anonymous textbox of " + ID);
var topTextboxAcc = box2Acc.lastChild;
is(topTextboxAcc.name, "Top textbox",
"Wrong label for anonymous textbox of " + ID);
@@ -190,16 +194,24 @@
aria-labelledby="labelledby_text"/>
<!-- aria-labelledby, multiple relations -->
<description id="labelledby_text1">text1</description>
<description id="labelledby_text2">text2</description>
<button id="btn_labelledby_texts"
aria-labelledby="labelledby_text1 labelledby_text2"/>
+ <!-- trick aria-labelledby -->
+ <checkbox id="rememberHistoryDays"
+ label="Remember "
+ aria-labelledby="rememberHistoryDays historyDays rememberAfter"/>
+ <textbox id="historyDays" type="number" size="3" value="3"
+ aria-labelledby="rememberHistoryDays historyDays rememberAfter"/>
+ <label id="rememberAfter">days</label>
+
<!-- the name from subtree, mixed content -->
<description id="labelledby_mixed">
no<description>more text</description>
</description>
<button id="btn_labelledby_mixed"
aria-labelledby="labelledby_mixed"/>
<!-- the name from subtree, mixed/hidden content -->
--- a/accessible/tests/mochitest/test_nsIAccessible_selects.html
+++ b/accessible/tests/mochitest/test_nsIAccessible_selects.html
@@ -42,18 +42,18 @@
(STATE_SELECTED | STATE_FOCUSED) // second, not currently focused, item
];
testSelect("combo1", names, roles, states, undesiredStates);
// Select nested within label element.
names = [
"Search in: Newsticker", // label
"Search in:", // text leaf
- "Search in: Newsticker", // combobox
- "Search in:", // combobox_list
+ "Search in:", // combobox
+ "Search in: Newsticker", // combobox_list
"Newsticker", // option 1
"Entire site" // Option 2
];
roles = [
ROLE_LABEL, // root
ROLE_TEXT_LEAF, // inner text
ROLE_COMBOBOX, // combobox accessible
ROLE_COMBOBOX_LIST, // list accessible
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_objectattrs.html
@@ -0,0 +1,95 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=475006
+-->
+<head>
+ <title>Group attributes tests</title>
+ <link rel="stylesheet" type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/a11y/accessible/common.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/a11y/accessible/attributes.js"></script>
+
+ <script type="application/javascript">
+ function doTest()
+ {
+ // aria
+ testAttrs("atomic", {"atomic" : "true"}, true);
+ testAttrs("autocomplete", {"autocomplete" : "true"}, true);
+ testAttrs("checkbox", {"checkable" : "true"}, true);
+ testAttrs("checkedCheckbox", {"checkable" : "true"}, true);
+ testAttrs("checkedMenuitem", {"checkable" : "true"}, true);
+ testAttrs("checkedOption", {"checkable" : "true"}, true);
+ testAttrs("checkedRadio", {"checkable" : "true"}, true);
+ testAttrs("checkedTreeitem", {"checkable" : "true"}, true);
+ testAttrs("dropeffect", {"dropeffect" : "copy"}, true);
+
+ // live object attribute
+ testAttrs("live", {"live" : "polite"}, true);
+ testAttrs("live2", {"live" : "polite"}, true);
+ testAttrs("log", {"live" : "polite"}, true);
+ testAttrs("marquee", {"live" : "off"}, true);
+ testAttrs("status", {"live" : "polite"}, true);
+ testAttrs("timer", {"live" : "off"}, true);
+
+ // container-live object attribute
+ testAttrs("liveChild", {"container-live" : "polite"}, true);
+ testAttrs("live2Child", {"container-live" : "polite"}, true);
+ testAttrs("logChild", {"container-live" : "polite"}, true);
+ testAttrs("marqueeChild", {"container-live" : "off"}, true);
+ testAttrs("statusChild", {"container-live" : "polite"}, true);
+ testAttrs("timerChild", {"container-live" : "off"}, true);
+
+ // html
+ testAttrs("radio", {"checkable" : "true"}, true);
+ testAttrs("checkbox", {"checkable" : "true"}, true);
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=475006"
+ title="Extend nsARIAMap to capture ARIA attribute characteristics">
+ Mozilla Bug 475006
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <!-- aria -->
+ <div id="atomic" aria-atomic="true"></div>
+ <div id="autocomplete" role="textbox" aria-autocomplete="true"></div>
+ <div id="checkbox" role="checkbox"></div>
+ <div id="checkedCheckbox" role="checkbox" aria-checked="true"></div>
+ <div id="checkedMenuitem" role="menuitem" aria-checked="true"></div>
+ <div id="checkedOption" role="option" aria-checked="true"></div>
+ <div id="checkedRadio" role="radio" aria-checked="true"></div>
+ <div id="checkedTreeitem" role="treeitem" aria-checked="true"></div>
+ <div id="dropeffect" aria-dropeffect="copy"></div>
+
+ <div id="live" aria-live="polite">excuse <div id="liveChild">me</div></div>
+ <div id="live2" role="marquee" aria-live="polite">excuse <div id="live2Child">me</div></div>
+ <div id="log" role="log">excuse <div id="logChild">me</div></div>
+ <div id="marquee" role="marquee">excuse <div id="marqueeChild">me</div></div>
+ <div id="status" role="status">excuse <div id="statusChild">me</div></div>
+ <div id="timer" role="timer">excuse <div id="timerChild">me</div></div>
+
+ <!-- html -->
+ <input id="radio" type="radio"/>
+ <input id="checkbox" type="checkbox"/>
+</body>
+</html>
rename from accessible/tests/mochitest/test_nsIAccessible_editabledoc.html
rename to accessible/tests/mochitest/test_states_doc.html
--- a/accessible/tests/mochitest/test_nsIAccessible_editabledoc.html
+++ b/accessible/tests/mochitest/test_states_doc.html
@@ -1,48 +1,67 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=454997
+https://bugzilla.mozilla.org/show_bug.cgi?id=467387
-->
<head>
- <title>nsIAccessible states tests of editable document</title>
+ <title>states of document</title>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/nsIAccessible_states.js"></script>
<script type="application/javascript">
function doTest()
{
+ testStates(document, STATE_READONLY);
+ testStates("document", STATE_READONLY);
+ testStates("editable_document", 0, EXT_STATE_EDITABLE);
+
document.designMode = "on";
testStates(document, 0, EXT_STATE_EDITABLE);
testStates("p", 0, EXT_STATE_EDITABLE);
+ testStates("document", 0, EXT_STATE_EDITABLE);
+ testStates("editable_document", 0, EXT_STATE_EDITABLE);
+
+ document.designMode = "off";
+
+ testStates(document, STATE_READONLY);
+ testStates("document", STATE_READONLY);
+ testStates("editable_document", 0, EXT_STATE_EDITABLE);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
-<body id="body">
+<body>
<a target="_blank"
title="nsIAccessible states tests of editable document"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=454997">Mozilla Bug 454997</a>
+ <a target="_blank"
+ title="nsIAccessible states tests of editable document"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=467387">Mozilla Bug 467387</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<p id="p">hello</p>
+
+ <div id="document" role="document">document</div>
+ <div id="editable_document" role="document" contentEditable="true">editable document</doc>
</body>
</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_states_docarticle.html
@@ -0,0 +1,62 @@
+<html>
+<head>
+ <title>states of document article</title>
+
+ <link rel="stylesheet" type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/a11y/accessible/common.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/a11y/accessible/nsIAccessible_states.js"></script>
+
+ <script type="application/javascript">
+ function doTest()
+ {
+ var docAcc = getAccessible(document, [nsIAccessibleDocument]);
+ if (docAcc) {
+ testStates(docAcc, STATE_READONLY);
+ testStates("article", STATE_READONLY);
+ testStates("editable_article", 0, EXT_STATE_EDITABLE);
+
+ document.designMode = "on";
+
+ testStates(docAcc, 0, EXT_STATE_EDITABLE);
+ testStates("article", 0, EXT_STATE_EDITABLE);
+ testStates("editable_article", 0, EXT_STATE_EDITABLE);
+
+ document.designMode = "off";
+
+ testStates(docAcc, STATE_READONLY);
+ testStates("article", STATE_READONLY);
+ testStates("editable_article", 0, EXT_STATE_EDITABLE);
+ }
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+
+<body role="article">
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=467387"
+ title="Expose non-editable documents as readonly, regardless of role">
+ Mozilla Bug 467387
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="article" role="article">article</div>
+ <div id="editable_article" role="article" contentEditable="true">editable article</doc>
+</body>
+</html>
rename from accessible/tests/mochitest/test_nsIAccessible_editablebody.html
rename to accessible/tests/mochitest/test_states_editablebody.html
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/test_states_frames.html
@@ -0,0 +1,76 @@
+<html>
+
+<head>
+ <title>frame based document testing</title>
+
+ <link rel="stylesheet" type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/a11y/accessible/common.js"></script>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/a11y/accessible/nsIAccessible_states.js"></script>
+
+ <script type="application/javascript">
+ function doTest()
+ {
+ frameDoc = document.getElementById("frame_doc").contentDocument;
+ frameDocArticle = document.getElementById("frame_doc_article").contentDocument;
+ frameDocCheckbox = document.getElementById("frame_doc_checkbox").contentDocument;
+ frameDocTextbox = document.getElementById("frame_doc_textbox").contentDocument;
+
+ testStates(frameDoc, STATE_READONLY);
+ testStates(frameDocArticle, STATE_READONLY);
+ testStates(frameDocCheckbox, 0, 0, STATE_READONLY);
+
+ var works = true;
+ try {
+ testStates(frameDocTextbox, 0, 0, STATE_READONLY);
+ }
+ catch (e) {
+ works = false;
+ }
+ todo(works, "Checking states of a textbox frame doc should not throw (Bug 478810)");
+
+ frameDoc.designMode = "on";
+ testStates(frameDoc, 0, EXT_STATE_EDITABLE);
+ testStates(frameDocArticle, STATE_READONLY);
+ testStates(frameDocCheckbox, 0, 0, STATE_READONLY);
+
+ frameDocArticle.designMode = "on";
+ testStates(frameDocArticle, 0, EXT_STATE_EDITABLE);
+
+ frameDocCheckbox.designMode = "on";
+ testStates(frameDocCheckbox, 0, 0, STATE_READONLY);
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=467387"
+ title="Expose non-editable documents as readonly, regardless of role">
+ Mozilla Bug 467387
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <iframe id="frame_doc" src="z_states_frame.html"></iframe>
+ <iframe id="frame_doc_article" src="z_states_framearticle.html"></iframe>
+ <iframe id="frame_doc_checkbox" src="z_states_framecheckbox.html"></iframe>
+ <iframe id="frame_doc_textbox" src="z_states_frametextbox.html"></iframe>
+</body>
+</html>
--- a/accessible/tests/mochitest/test_table_indexes.html
+++ b/accessible/tests/mochitest/test_table_indexes.html
@@ -1,262 +1,262 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=410052
--->
-<head>
- <title>Table indexes chrome tests</title>
- <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-
- <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
- <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
- <script type="application/javascript">
- const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
- const nsIAccessibleTable = Components.interfaces.nsIAccessibleTable;
-
- var gAccService = null;
-
- function doTest()
- {
- gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
- getService(nsIAccessibleRetrieval);
-
- //////////////////////////////////////////////////////////////////////////
- // table
- var tRow = new Array(0,0,0,1,1,1,2,2,3,3);
- var tCol = new Array(0,1,2,0,1,2,0,1,1,2);
-
- testTable("table", 10, tRow, tCol);
-
- //////////////////////////////////////////////////////////////////////////
- // tableinsane1
- tRow = [0,0,0,1,1,1,2,2,3,3];
- tCol = [0,1,2,0,1,2,0,1,1,2];
-
- testTable("tableinsane1", 10, tRow, tCol);
-
- //////////////////////////////////////////////////////////////////////////
- // tableinsane2
- tRow = [0,0,0,1,1,1,2,2,3,3,4,4,4];
- tCol = [0,1,2,0,1,2,0,1,1,2,1,3,4];
-
- testTable("tableinsane2", 13, tRow, tCol);
-
- //////////////////////////////////////////////////////////////////////////
- // tableinsane4
- tRow = [0,0,0,1,1,1,2,2,3,4];
- tCol = [0,1,2,0,1,2,0,2,0,0];
-
- testTable("tableinsane4", 10, tRow, tCol);
-
- //////////////////////////////////////////////////////////////////////////
- // tableborder
- tRow = [0,0,0,1,1,1,2,2,3,3];
- tCol = [0,1,2,0,1,2,0,1,1,2];
-
- testTable("tableborder", 10, tRow, tCol);
-
- SimpleTest.finish();
- }
-
- function testTable(aId, aLen, aRowIdxes, aColIdxes)
- {
- var table = document.getElementById(aId);
- var tableAcc = gAccService.getAccessibleFor(table).
- QueryInterface(nsIAccessibleTable);
-
- var row, column, index;
- var cellAcc;
-
- for (var i = 0; i < aLen; i++) {
- row = tableAcc.getRowAtIndex(i);
- column = tableAcc.getColumnAtIndex(i);
- index = tableAcc.getIndexAt(aRowIdxes[i], aColIdxes[i]);
-
- is(row, aRowIdxes[i], aId + ": row for index " + i +" is nor correct");
- is(column, aColIdxes[i],
- aId + ": column for index " + i +"is nor correct");
- is(index, i,
- aId + ": row " + row + " /column " + column + " and index " + index + " aren't inconsistent.");
-
- try {
- cellAcc = null;
- cellAcc = tableAcc.cellRefAt(row, column);
- } catch (e) { }
-
- ok(cellAcc,
- aId + ": Can't get cell accessible at row = " + row + ", column = " + column);
-
- if (cellAcc) {
- var attrs = cellAcc.attributes;
- is (parseInt(attrs.getStringProperty("table-cell-index")), index,
- aId + ": cell index from object attributes of cell accessible isn't corrent.");
- }
- }
- }
-
- SimpleTest.waitForExplicitFinish();
- addLoadEvent(doTest);
- </script>
-</head>
-<body>
-
- <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=410052">Mozilla Bug 410052</a>
- <p id="display"></p>
- <div id="content" style="display: none"></div>
- <pre id="test">
- </pre>
-
- <!--
- If you change the structure of the table please make sure to change
- the indexes count in 'for' statement in the script above.
- -->
- <table border="1" id="table">
- <caption><strong><b><font size="29">this is a caption for this table</font></b></strong></caption>
- <thead>
- <tr>
- <th>col1</th>
- <th>col2</th>
- <th>col3</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td rowspan="0">4</td>
- <td colspan="2">5</td>
- </tr>
- <tr>
- <td>6</td>
- <td>7</td>
- </tr>
- </tbody>
- </table>
-
- <table border="1" id="tableborder" style="border-collapse:collapse">
- <caption><strong><b><font size="29">this is a caption for this bc table</font></b></strong></caption>
- <thead>
- <tr>
- <th>col1</th>
- <th>col2</th>
- <th>col3</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td rowspan="2">4</td>
- <td colspan="2">5</td>
- </tr>
- <tr>
- <td>6</td>
- <td>7</td>
- </tr>
- </tbody>
- </table>
-
- <table border="1" id="tableinsane1">
- <caption>test empty row groups</caption>
- <thead>
- <tr>
- <th>col1</th>
- <th>col2</th>
- <th>col3</th>
- </tr>
- </thead>
- <tbody></tbody>
- <tbody></tbody>
- <tbody></tbody>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td rowspan="2">4</td>
- <td colspan="2">5</td>
- </tr>
- <tr>
- <td>6</td>
- <td>7</td>
- </tr>
- </tbody>
- </table>
-
- <table border="1" id="tableinsane2" >
- <caption>empty rowgroup + empty rows</caption>
- <thead>
- <tr>
- <th>col1</th>
- <th>col2</th>
- <th>col3</th>
- </tr>
- </thead>
- <tbody><tr></tr></tbody>
- <tbody></tbody>
- <tbody></tbody>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td rowspan="0">4</td>
- <td colspan="0">5</td>
- </tr>
- <tr>
- <td>6</td>
- <td rowspan="0">7</td>
- </tr>
- <tr>
- <td>8</td>
- <td>9</td>
- <td>10</td>
- </tr>
-
- </tbody>
-
- <table border="1" id="tableinsane4" >
- <caption>test cellmap holes</caption>
- <thead>
- <tr>
- <th>col1</th>
- <th>col2</th>
- <th>col3</th>
- </tr>
- </thead>
- <tbody><tr></tr></tbody>
- <tbody></tbody>
- <tbody></tbody>
- <tbody>
- <tr>
- <td>1</td>
- <td>2</td>
- <td>3</td>
- </tr>
- <tr>
- <td colspan="2">4</td>
- <td rowspan="2">5</td>
- </tr>
- <tr>
- <td>6</td>
- </tr>
- <tr>
- <td colspan="3">7</td>
- </tr>
-
- </tbody>
- </table>
-
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=410052
+-->
+<head>
+ <title>Table indexes chrome tests</title>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+ <script type="application/javascript">
+ const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+ const nsIAccessibleTable = Components.interfaces.nsIAccessibleTable;
+
+ var gAccService = null;
+
+ function doTest()
+ {
+ gAccService = Components.classes["@mozilla.org/accessibleRetrieval;1"].
+ getService(nsIAccessibleRetrieval);
+
+ //////////////////////////////////////////////////////////////////////////
+ // table
+ var tRow = new Array(0,0,0,1,1,1,2,2,3,3);
+ var tCol = new Array(0,1,2,0,1,2,0,1,1,2);
+
+ testTable("table", 10, tRow, tCol);
+
+ //////////////////////////////////////////////////////////////////////////
+ // tableinsane1
+ tRow = [0,0,0,1,1,1,2,2,3,3];
+ tCol = [0,1,2,0,1,2,0,1,1,2];
+
+ testTable("tableinsane1", 10, tRow, tCol);
+
+ //////////////////////////////////////////////////////////////////////////
+ // tableinsane2
+ tRow = [0,0,0,1,1,1,2,2,3,3,4,4,4];
+ tCol = [0,1,2,0,1,2,0,1,1,2,1,3,4];
+
+ testTable("tableinsane2", 13, tRow, tCol);
+
+ //////////////////////////////////////////////////////////////////////////
+ // tableinsane4
+ tRow = [0,0,0,1,1,1,2,2,3,4];
+ tCol = [0,1,2,0,1,2,0,2,0,0];
+
+ testTable("tableinsane4", 10, tRow, tCol);
+
+ //////////////////////////////////////////////////////////////////////////
+ // tableborder
+ tRow = [0,0,0,1,1,1,2,2,3,3];
+ tCol = [0,1,2,0,1,2,0,1,1,2];
+
+ testTable("tableborder", 10, tRow, tCol);
+
+ SimpleTest.finish();
+ }
+
+ function testTable(aId, aLen, aRowIdxes, aColIdxes)
+ {
+ var table = document.getElementById(aId);
+ var tableAcc = gAccService.getAccessibleFor(table).
+ QueryInterface(nsIAccessibleTable);
+
+ var row, column, index;
+ var cellAcc;
+
+ for (var i = 0; i < aLen; i++) {
+ row = tableAcc.getRowAtIndex(i);
+ column = tableAcc.getColumnAtIndex(i);
+ index = tableAcc.getIndexAt(aRowIdxes[i], aColIdxes[i]);
+
+ is(row, aRowIdxes[i], aId + ": row for index " + i +" is nor correct");
+ is(column, aColIdxes[i],
+ aId + ": column for index " + i +"is nor correct");
+ is(index, i,
+ aId + ": row " + row + " /column " + column + " and index " + index + " aren't inconsistent.");
+
+ try {
+ cellAcc = null;
+ cellAcc = tableAcc.cellRefAt(row, column);
+ } catch (e) { }
+
+ ok(cellAcc,
+ aId + ": Can't get cell accessible at row = " + row + ", column = " + column);
+
+ if (cellAcc) {
+ var attrs = cellAcc.attributes;
+ is (parseInt(attrs.getStringProperty("table-cell-index")), index,
+ aId + ": cell index from object attributes of cell accessible isn't corrent.");
+ }
+ }
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=410052">Mozilla Bug 410052</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <!--
+ If you change the structure of the table please make sure to change
+ the indexes count in 'for' statement in the script above.
+ -->
+ <table border="1" id="table">
+ <caption><strong><b><font size="29">this is a caption for this table</font></b></strong></caption>
+ <thead>
+ <tr>
+ <th>col1</th>
+ <th>col2</th>
+ <th>col3</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td rowspan="0">4</td>
+ <td colspan="2">5</td>
+ </tr>
+ <tr>
+ <td>6</td>
+ <td>7</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <table border="1" id="tableborder" style="border-collapse:collapse">
+ <caption><strong><b><font size="29">this is a caption for this bc table</font></b></strong></caption>
+ <thead>
+ <tr>
+ <th>col1</th>
+ <th>col2</th>
+ <th>col3</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td rowspan="2">4</td>
+ <td colspan="2">5</td>
+ </tr>
+ <tr>
+ <td>6</td>
+ <td>7</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <table border="1" id="tableinsane1">
+ <caption>test empty row groups</caption>
+ <thead>
+ <tr>
+ <th>col1</th>
+ <th>col2</th>
+ <th>col3</th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ <tbody></tbody>
+ <tbody></tbody>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td rowspan="2">4</td>
+ <td colspan="2">5</td>
+ </tr>
+ <tr>
+ <td>6</td>
+ <td>7</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <table border="1" id="tableinsane2" >
+ <caption>empty rowgroup + empty rows</caption>
+ <thead>
+ <tr>
+ <th>col1</th>
+ <th>col2</th>
+ <th>col3</th>
+ </tr>
+ </thead>
+ <tbody><tr></tr></tbody>
+ <tbody></tbody>
+ <tbody></tbody>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td rowspan="0">4</td>
+ <td colspan="0">5</td>
+ </tr>
+ <tr>
+ <td>6</td>
+ <td rowspan="0">7</td>
+ </tr>
+ <tr>
+ <td>8</td>
+ <td>9</td>
+ <td>10</td>
+ </tr>
+
+ </tbody>
+
+ <table border="1" id="tableinsane4" >
+ <caption>test cellmap holes</caption>
+ <thead>
+ <tr>
+ <th>col1</th>
+ <th>col2</th>
+ <th>col3</th>
+ </tr>
+ </thead>
+ <tbody><tr></tr></tbody>
+ <tbody></tbody>
+ <tbody></tbody>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td colspan="2">4</td>
+ <td rowspan="2">5</td>
+ </tr>
+ <tr>
+ <td>6</td>
+ </tr>
+ <tr>
+ <td colspan="3">7</td>
+ </tr>
+
+ </tbody>
+ </table>
+
+</body>
+</html>
--- 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, 0, 11);
- testTextAttrs(ID, 11, misspelledAttrs, 11, 17);
- testTextAttrs(ID, 17, attrs, 17, 18);
- testTextAttrs(ID, 18, misspelledAttrs, 18, 22);
+ 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);
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, 0, 7);
+ testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-weight": gComputedStyle.fontWeight};
- testTextAttrs(ID, 7, attrs, 7, 11);
+ testTextAttrs(ID, 7, attrs, defAttrs, 7, 11);
attrs = {};
- testTextAttrs(ID, 12, attrs, 11, 18);
+ testTextAttrs(ID, 12, attrs, defAttrs, 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, 0, 7);
+ testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-weight": gComputedStyle.fontWeight};
- testTextAttrs(ID, 7, attrs, 7, 12);
+ testTextAttrs(ID, 7, attrs, defAttrs, 7, 12);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-style": gComputedStyle.fontStyle,
"font-weight": gComputedStyle.fontWeight};
- testTextAttrs(ID, 13, attrs, 12, 19);
+ testTextAttrs(ID, 13, attrs, defAttrs, 12, 19);
tempElem = tempElem.parentNode;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"font-weight": "401"};
- testTextAttrs(ID, 20, attrs, 19, 23);
+ testTextAttrs(ID, 20, attrs, defAttrs, 19, 23);
attrs = {};
- testTextAttrs(ID, 24, attrs, 23, 30);
+ testTextAttrs(ID, 24, attrs, defAttrs, 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, 0, 6);
+ testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
- testTextAttrs(ID, 6, attrs, 6, 26);
+ testTextAttrs(ID, 6, attrs, defAttrs, 6, 26);
tempElem = tempElem.parentNode;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
- testTextAttrs(ID, 26, attrs, 26, 27);
+ testTextAttrs(ID, 26, attrs, defAttrs, 26, 27);
tempElem = tempElem.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color,
"background-color": gComputedStyle.backgroundColor};
- testTextAttrs(ID, 27, attrs, 27, 50);
+ testTextAttrs(ID, 27, attrs, defAttrs, 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, 0, 16);
+ testTextAttrs(ID, 0, attrs, defAttrs, 0, 16);
tempElem = tempElem.nextSibling.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
- testTextAttrs(ID, 16, attrs, 16, 33);
+ testTextAttrs(ID, 16, attrs, defAttrs, 16, 33);
tempElem = tempElem.parentNode;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
- testTextAttrs(ID, 34, attrs, 33, 46);
+ testTextAttrs(ID, 34, attrs, defAttrs, 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, 0, 5);
+ testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
attrs = {};
- testTextAttrs(ID, 7, attrs, 5, 8);
+ testTextAttrs(ID, 7, attrs, defAttrs, 5, 8);
tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"color": gComputedStyle.color};
- testTextAttrs(ID, 9, attrs, 8, 11);
+ testTextAttrs(ID, 9, attrs, defAttrs, 8, 11);
attrs = {};
- testTextAttrs(ID, 11, attrs, 11, 18);
+ testTextAttrs(ID, 11, attrs, defAttrs, 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,105 +266,234 @@
"color": gComputedStyle.color,
"font-family": gComputedStyle.fontFamily,
"text-position": gComputedStyle.verticalAlign
};
testDefaultTextAttrs(ID, defAttrs);
attrs = {};
- testTextAttrs(ID, 0, attrs, 0, 5);
+ testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
tempElem = tempElem.firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"text-position": gComputedStyle.verticalAlign,
"font-size": "10pt"};
- testTextAttrs(ID, 5, attrs, 5, 13);
+ testTextAttrs(ID, 5, attrs, defAttrs, 5, 13);
attrs = {};
- testTextAttrs(ID, 13, attrs, 13, 27);
+ testTextAttrs(ID, 13, attrs, defAttrs, 13, 27);
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"text-position": gComputedStyle.verticalAlign};
- testTextAttrs(ID, 27, attrs, 27, 35);
+ testTextAttrs(ID, 27, attrs, defAttrs, 27, 35);
attrs = {};
- testTextAttrs(ID, 35, attrs, 35, 39);
+ testTextAttrs(ID, 35, attrs, defAttrs, 35, 39);
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"text-position": gComputedStyle.verticalAlign,
"font-size": "10pt"};
- testTextAttrs(ID, 39, attrs, 39, 50);
+ testTextAttrs(ID, 39, attrs, defAttrs, 39, 50);
attrs = {};
- testTextAttrs(ID, 50, attrs, 50, 55);
+ testTextAttrs(ID, 50, attrs, defAttrs, 50, 55);
tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = {"text-position": gComputedStyle.verticalAlign};
- testTextAttrs(ID, 55, attrs, 55, 64);
+ testTextAttrs(ID, 55, attrs, defAttrs, 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 = {"language": "ru"};
- testTextAttrs(ID, 0, attrs, 0, 12);
+ attrs = {};
+ testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
- attrs = {"language": "en"};
- testTextAttrs(ID, 12, attrs, 12, 13);
+ attrs = { "font-size": "14pt" };
+ testTextAttrs(ID, 7, attrs, defAttrs, 7, 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 = {"language" :"en",
- "background-color": gComputedStyle.backgroundColor};
- testTextAttrs(ID, 13, attrs, 13, 26);
+ attrs = { "background-color": gComputedStyle.backgroundColor };
+ testTextAttrs(ID, 23, attrs, defAttrs, 22, 37);
+
+ attrs = {};
+ testTextAttrs(ID, 38, attrs, defAttrs, 37, 45);
- 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);
+ // 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, 46, attrs, defAttrs, 45, 62);
attrs = {};
- testTextAttrs(ID, 43, attrs, 43, 50);
+ testTextAttrs(ID, 63, attrs, defAttrs, 62, 70);
- tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
- gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
- attrs = {"color": gComputedStyle.color};
- testTextAttrs(ID, 50, attrs, 50, 57);
-
- tempElem = tempElem.firstChild.nextSibling;
+ // Walk from span with font-style to the one with font-family.
+ tempElem = tempElem.nextSibling.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
- attrs = {"font-weight": gComputedStyle.fontWeight,
- "color": gComputedStyle.color};
- testTextAttrs(ID, 57, attrs, 57, 61);
+ 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);
- tempElem = tempElem.parentNode;
- gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
- attrs = {"color": gComputedStyle.color};
- testTextAttrs(ID, 61, attrs, 61, 68);
+ 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);
//////////////////////////////////////////////////////////////////////////
// test spelling text attributes
testSpellTextAttrs(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
@@ -420,11 +549,27 @@
<span lang="en">
Normal
<span style="color: magenta">Magenta<b>Bold</b>Magenta</span>
</span>
</p>
<input id="area8"/>
- <p id="output"/>
+ <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>
</body>
</html>
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/z_states_frame.html
@@ -0,0 +1,11 @@
+<html>
+<!--
+Auxilliary file used as frame source.
+-->
+<head>
+</head>
+<body>
+<p>Frame source body has no role</p>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/z_states_framearticle.html
@@ -0,0 +1,11 @@
+<html>
+<!--
+Auxilliary file used as frame source.
+-->
+<head>
+</head>
+<body role="article">
+<p>Article</p>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/z_states_framecheckbox.html
@@ -0,0 +1,11 @@
+<html>
+<!--
+Auxilliary file used as frame source.
+-->
+<head>
+</head>
+<body role="checkbox">
+<p>Checkbox</p>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/z_states_frametextbox.html
@@ -0,0 +1,11 @@
+<html>
+<!--
+Auxilliary file used as frame source.
+-->
+<head>
+</head>
+<body role="textbox">
+<p>Texbox</p>
+</body>
+</html>
+
--- a/browser/app/firefox-branding.js
+++ b/browser/app/firefox-branding.js
@@ -1,13 +1,16 @@
pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
// The time interval between checks for a new version (in seconds)
// nightly=8 hours, official=24 hours
pref("app.update.interval", 28800);
+// The time interval between the downloading of mar file chunks in the
+// background (in seconds)
+pref("app.update.download.backgroundInterval", 60);
// URL user can browse to manually if for some reason all update installation
// attempts fail.
pref("app.update.url.manual", "http://www.mozilla.org/products/%APP%/");
// A default value for the "More information about this update" link
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/");
// Release notes URL
--- a/browser/base/Makefile.in
+++ b/browser/base/Makefile.in
@@ -15,16 +15,17 @@
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Netscape Communications Corporation.
# Portions created by the Initial Developer are Copyright (C) 1998
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
+# Robert Strong <robert.bugzilla@gmail.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
@@ -49,19 +50,25 @@ abs_srcdir = $(shell cd $(srcdir) && pwd
CHROME_DEPS += $(abs_srcdir)/content/overrides/app-license.html
ifdef ENABLE_TESTS
DIRS += content/test
endif
include $(topsrcdir)/config/rules.mk
+PRE_RELEASE_SUFFIX = $(shell cat $(srcdir)/../config/version.txt | \
+ sed -e '/pre/s/.*//g' -e '/[ab][0-9]/!s/.*//g' \
+ -e 's/\(.*[0-9]\)a\([0-9]\+\)/ \1 Alpha \2/g' \
+ -e 's/\(.*[0-9]\)b\([0-9]\+\)/ \1 Beta \2/g')
+
DEFINES += \
-DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
-DAPP_LICENSE_BLOCK=$(abs_srcdir)/content/overrides/app-license.html \
+ -DPRE_RELEASE_SUFFIX="$(PRE_RELEASE_SUFFIX)" \
$(NULL)
ifndef MOZ_BRANDING_DIRECTORY
DEFINES += -DMOZ_USE_GENERIC_BRANDING
endif
ifneq (,$(filter windows gtk2 mac cocoa, $(MOZ_WIDGET_TOOLKIT)))
DEFINES += -DHAVE_SHELL_SERVICE=1
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1150,16 +1150,20 @@ function prepareForStartup() {
// hook up UI through progress listener
gBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
gBrowser.addTabsProgressListener(window.TabsProgressListener);
// setup our common DOMLinkAdded listener
gBrowser.addEventListener("DOMLinkAdded", DOMLinkHandler, false);
+ // setup our MozApplicationManifest listener
+ gBrowser.addEventListener("MozApplicationManifest",
+ OfflineApps, false);
+
// setup simple gestures support
gGestureSupport.init(true);
}
function delayedStartup(isLoadingBlank, mustLoadSidebar) {
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
os.addObserver(gXPInstallObserver, "xpinstall-install-blocked", false);
@@ -2898,29 +2902,32 @@ const DOMLinkHandler = {
}
const BrowserSearch = {
addEngine: function(engine, targetDoc) {
if (!this.searchBar)
return;
var browser = gBrowser.getBrowserForDocument(targetDoc);
+ // ignore search engines from subframes (see bug 479408)
+ if (!browser)
+ return;
// Check to see whether we've already added an engine with this title
if (browser.engines) {
if (browser.engines.some(function (e) e.title == engine.title))
return;
}
// Append the URI and an appropriate title to the browser data.
// Use documentURIObject in the check for shouldLoadFavIcon so that we
// do the right thing with about:-style error pages. Bug 453442
var iconURL = null;
- if (gBrowser.shouldLoadFavIcon(browser.contentDocument.documentURIObject))
- iconURL = browser.currentURI.prePath + "/favicon.ico";
+ if (gBrowser.shouldLoadFavIcon(targetDoc.documentURIObject))
+ iconURL = targetDoc.documentURIObject.prePath + "/favicon.ico";
var hidden = false;
// If this engine (identified by title) is already in the list, add it
// to the list of hidden engines rather than to the main list.
// XXX This will need to be changed when engines are identified by URL;
// see bug 335102.
var searchService = Cc["@mozilla.org/browser/search-service;1"].
getService(Ci.nsIBrowserSearchService);
@@ -3867,20 +3874,16 @@ var XULBrowserWindow = {
}
else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK) {
if (aWebProgress.DOMWindow == content) {
if (aRequest)
this.endDocumentLoad(aRequest, aStatus);
if (!gBrowser.mTabbedMode && !gBrowser.mCurrentBrowser.mIconURL)
gBrowser.useDefaultIcon(gBrowser.mCurrentTab);
-
- if (Components.isSuccessCode(aStatus) &&
- content.document.documentElement.getAttribute("manifest"))
- OfflineApps.offlineAppRequested(content);
}
}
// This (thanks to the filter) is a network stop or the last
// request stop outside of loading the document, stop throbbers
// and progress bars and such
if (aRequest) {
let msg = "";
@@ -4904,17 +4907,17 @@ function middleMousePaste(event)
var contentAreaDNDObserver = {
onDrop: function (aEvent, aXferData, aDragSession)
{
if (aEvent.getPreventDefault())
return;
var dragType = aXferData.flavour.contentType;
var dragData = aXferData.data;
- if (dragType == "application/x-moz-tabbrowser-tab") {
+ if (dragType == TAB_DROP_TYPE) {
// If the tab was dragged from some other tab bar, its own dragend
// handler will take care of detaching the tab
if (dragData instanceof XULElement && dragData.localName == "tab" &&
dragData.ownerDocument.defaultView == window) {
// Detach only if the mouse pointer was released a little
// bit down in the content area (to be precise, by half the height
// of a tab)
if (aEvent.screenY > gBrowser.mPanelContainer.boxObject.screenY +
@@ -4953,17 +4956,17 @@ var contentAreaDNDObserver = {
// keep the event from being handled by the dragDrop listeners
// built-in to gecko if they happen to be above us.
aEvent.preventDefault();
},
getSupportedFlavours: function ()
{
var flavourSet = new FlavourSet();
- flavourSet.appendFlavour("application/x-moz-tabbrowser-tab");
+ flavourSet.appendFlavour(TAB_DROP_TYPE);
flavourSet.appendFlavour("text/x-moz-url");
flavourSet.appendFlavour("text/plain");
flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
return flavourSet;
}
};
@@ -5326,16 +5329,22 @@ var OfflineApps = {
uninit: function ()
{
var obs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
obs.removeObserver(this, "dom-storage-warn-quota-exceeded");
obs.removeObserver(this, "offline-cache-update-completed");
},
+ handleEvent: function(event) {
+ if (event.type == "MozApplicationManifest") {
+ this.offlineAppRequested(event.originalTarget.defaultView);
+ }
+ },
+
/////////////////////////////////////////////////////////////////////////////
// OfflineApps Implementation Methods
// XXX: _getBrowserWindowForContentWindow and _getBrowserForContentWindow
// were taken from browser/components/feeds/src/WebContentConverter.
_getBrowserWindowForContentWindow: function(aContentWindow) {
return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
@@ -5352,16 +5361,17 @@ var OfflineApps = {
var browsers = aBrowserWindow.getBrowser().browsers;
for (var i = 0; i < browsers.length; ++i) {
if (browsers[i].contentWindow == aContentWindow)
return browsers[i];
}
},
_getManifestURI: function(aWindow) {
+ if (!aWindow.document.documentElement) return null;
var attr = aWindow.document.documentElement.getAttribute("manifest");
if (!attr) return null;
try {
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var contentURI = ios.newURI(aWindow.location.href, null, null);
@@ -5421,20 +5431,35 @@ var OfflineApps = {
// again.
var pm = Cc["@mozilla.org/permissionmanager;1"].
getService(Ci.nsIPermissionManager);
pm.add(aURI, "offline-app",
Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
},
// XXX: duplicated in preferences/advanced.js
- _getOfflineAppUsage: function (host)
+ _getOfflineAppUsage: function (host, groups)
{
- // XXX Bug 442810: include offline cache usage.
+ var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
+ getService(Components.interfaces.nsIApplicationCacheService);
+ if (!groups) {
+ groups = cacheService.getGroups({});
+ }
+ var ios = Components.classes["@mozilla.org/network/io-service;1"].
+ getService(Components.interfaces.nsIIOService);
+
var usage = 0;
+ for (var i = 0; i < groups.length; i++) {
+ var uri = ios.newURI(groups[i], null, null);
+ if (uri.asciiHost == host) {
+ var cache = cacheService.getActiveCache(groups[i]);
+ usage += cache.usage;
+ }
+ }
+
var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIDOMStorageManager);
usage += storageManager.getUsage(host);
return usage;
},
_checkUsage: function(aURI) {
@@ -5458,17 +5483,17 @@ var OfflineApps = {
if (!gPrefService.getBoolPref("browser.offline-apps.notify")) {
return;
}
var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
var browser = this._getBrowserForContentWindow(browserWindow,
aContentWindow);
- var currentURI = browser.webNavigation.currentURI;
+ var currentURI = aContentWindow.document.documentURIObject;
var pm = Cc["@mozilla.org/permissionmanager;1"].
getService(Ci.nsIPermissionManager);
// don't bother showing UI if the user has already made a decision
if (pm.testExactPermission(currentURI, "offline-app") !=
Ci.nsIPermissionManager.UNKNOWN_ACTION)
return;
@@ -5476,82 +5501,99 @@ var OfflineApps = {
if (gPrefService.getBoolPref("offline-apps.allow_by_default")) {
// all pages can use offline capabilities, no need to ask the user
return;
}
} catch(e) {
// this pref isn't set by default, ignore failures
}
+ var host = currentURI.asciiHost;
var notificationBox = gBrowser.getNotificationBox(browser);
- var notification = notificationBox.getNotificationWithValue("offline-app-requested");
- if (!notification) {
+ var notificationID = "offline-app-requested-" + host;
+ var notification = notificationBox.getNotificationWithValue(notificationID);
+
+ if (notification) {
+ notification.documents.push(aContentWindow.document);
+ } else {
var bundle_browser = document.getElementById("bundle_browser");
var buttons = [{
label: bundle_browser.getString("offlineApps.allow"),
accessKey: bundle_browser.getString("offlineApps.allowAccessKey"),
- callback: function() { OfflineApps.allowSite(); }
+ callback: function() {
+ for (var i = 0; i < notification.documents.length; i++) {
+ OfflineApps.allowSite(notification.documents[i]);
+ }
+ }
},{
label: bundle_browser.getString("offlineApps.never"),
accessKey: bundle_browser.getString("offlineApps.neverAccessKey"),
- callback: function() { OfflineApps.disallowSite(); }
+ callback: function() {
+ for (var i = 0; i < notification.documents.length; i++) {
+ OfflineApps.disallowSite(notification.documents[i]);
+ }
+ }
},{
label: bundle_browser.getString("offlineApps.notNow"),
accessKey: bundle_browser.getString("offlineApps.notNowAccessKey"),
callback: function() { /* noop */ }
}];
const priority = notificationBox.PRIORITY_INFO_LOW;
var message = bundle_browser.getFormattedString("offlineApps.available",
- [ currentURI.host ]);
- notificationBox.appendNotification(message, "offline-app-requested",
- "chrome://browser/skin/Info.png",
- priority, buttons);
+ [ host ]);
+ notification =
+ notificationBox.appendNotification(message, notificationID,
+ "chrome://browser/skin/Info.png",
+ priority, buttons);
+ notification.documents = [ aContentWindow.document ];
}
},
- allowSite: function() {
- var currentURI = gBrowser.selectedBrowser.webNavigation.currentURI;
+ allowSite: function(aDocument) {
var pm = Cc["@mozilla.org/permissionmanager;1"].
getService(Ci.nsIPermissionManager);
- pm.add(currentURI, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
-
- // When a site is enabled while loading, <link rel="offline-resource">
- // resources will start fetching immediately. This one time we need to
- // do it ourselves.
- this._startFetching();
+ pm.add(aDocument.documentURIObject, "offline-app",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+
+ // When a site is enabled while loading, manifest resources will
+ // start fetching immediately. This one time we need to do it
+ // ourselves.
+ this._startFetching(aDocument);
},
- disallowSite: function() {
- var currentURI = gBrowser.selectedBrowser.webNavigation.currentURI;
+ disallowSite: function(aDocument) {
var pm = Cc["@mozilla.org/permissionmanager;1"].
getService(Ci.nsIPermissionManager);
- pm.add(currentURI, "offline-app", Ci.nsIPermissionManager.DENY_ACTION);
+ pm.add(aDocument.documentURIObject, "offline-app",
+ Ci.nsIPermissionManager.DENY_ACTION);
},
manage: function() {
openAdvancedPreferences("networkTab");
},
- _startFetching: function() {
- var manifest = content.document.documentElement.getAttribute("manifest");
+ _startFetching: function(aDocument) {
+ if (!aDocument.documentElement)
+ return;
+
+ var manifest = aDocument.documentElement.getAttribute("manifest");
if (!manifest)
return;
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
- var contentURI = ios.newURI(content.location.href, null, null);
- var manifestURI = ios.newURI(manifest, content.document.characterSet,
- contentURI);
+ var manifestURI = ios.newURI(manifest, aDocument.characterSet,
+ aDocument.documentURIObject);
var updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"].
getService(Ci.nsIOfflineCacheUpdateService);
- updateService.scheduleUpdate(manifestURI, contentURI);
+ updateService.scheduleUpdate(manifestURI, aDocument.documentURIObject);
},
/////////////////////////////////////////////////////////////////////////////
// nsIObserver
observe: function (aSubject, aTopic, aState)
{
if (aTopic == "dom-storage-warn-quota-exceeded") {
if (aSubject) {
@@ -6085,27 +6127,27 @@ var FeedHandler = {
}
},
addFeed: function(feed, targetDoc) {
if (feed) {
// find which tab this is for, and set the attribute on the browser
var browserForLink = gBrowser.getBrowserForDocument(targetDoc);
if (!browserForLink) {
- // ??? this really shouldn't happen..
+ // ignore feeds loaded in subframes (see bug 305472)
return;
}
var feeds = [];
if (browserForLink.feeds != null)
feeds = browserForLink.feeds;
feeds.push(feed);
browserForLink.feeds = feeds;
- if (browserForLink == gBrowser || browserForLink == gBrowser.mCurrentBrowser) {
+ if (browserForLink == gBrowser.mCurrentBrowser) {
var feedButton = document.getElementById("feed-button");
if (feedButton)
feedButton.collapsed = false;
}
}
}
};
@@ -6863,16 +6905,18 @@ let gPrivateBrowsingUI = {
}
return result;
},
onEnterPrivateBrowsing: function PBUI_onEnterPrivateBrowsing() {
this._setPBMenuTitle("stop");
+ document.getElementById("menu_import").setAttribute("disabled", "true");
+
this._privateBrowsingAutoStarted = this._privateBrowsingService.autoStarted;
if (!this._privateBrowsingAutoStarted) {
// Adjust the window's title
let docElement = document.documentElement;
docElement.setAttribute("title",
docElement.getAttribute("title_privatebrowsing"));
docElement.setAttribute("titlemodifier",
@@ -6888,16 +6932,18 @@ let gPrivateBrowsingUI = {
.setAttribute("disabled", "true");
}
},
onExitPrivateBrowsing: function PBUI_onExitPrivateBrowsing() {
if (BrowserSearch.searchBar)
BrowserSearch.searchBar.textbox.reset();
+ document.getElementById("menu_import").removeAttribute("disabled");
+
gFindBar.getElement("findbar-textbox").reset();
this._setPBMenuTitle("start");
if (!this._privateBrowsingAutoStarted) {
// Adjust the window's title
let docElement = document.documentElement;
docElement.setAttribute("title",
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1,8 +1,9 @@
+#filter substitution
<?xml version="1.0"?>
# -*- Mode: HTML -*-
#
# ***** 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
@@ -26,16 +27,17 @@
# Blake Ross <blake@cs.stanford.edu>
# David Hyatt <hyatt@mozilla.org>
# Joe Hewitt <hewitt@netscape.com>
# Pierre Chanial <chanial@noos.fr>
# Dean Tessman <dean_tessman@hotmail.com>
# Johnathan Nightingale <johnath@mozilla.com>
# Dão Gottwald <dao@mozilla.com>
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
+# Robert Strong <robert.bugzilla@gmail.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
@@ -43,49 +45,46 @@
# 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 *****
<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
-
-<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
-
-<?xml-stylesheet href="chrome://global/skin/toolbar.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
# All DTD information is stored in a separate file so that it can be shared by
# hiddenWindow.xul.
#include browser-doctype.inc
<window id="main-window"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="BrowserStartup()" onunload="BrowserShutdown()" onclose="return WindowIsClosing();"
ondragleave="gBrowser.browserWindowOnDragLeave(event);"
ondragenter="gBrowser.browserWindowOnDragEnter(event);"
- title="&mainWindow.title;"
- title_normal="&mainWindow.title;"
+ title="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
+ title_normal="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
#ifdef XP_MACOSX
- title_privatebrowsing="&mainWindow.title;&mainWindow.titlemodifiermenuseparator;&mainWindow.titlePrivateBrowsingSuffix;"
- titledefault="&mainWindow.title;"
+ title_privatebrowsing="&mainWindow.title;@PRE_RELEASE_SUFFIX@&mainWindow.titlemodifiermenuseparator;&mainWindow.titlePrivateBrowsingSuffix;"
+ titledefault="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
titlemodifier=""
titlemodifier_normal=""
titlemodifier_privatebrowsing="&mainWindow.titlePrivateBrowsingSuffix;"
#else
- title_privatebrowsing="&mainWindow.titlemodifierPrivateBrowsing;"
- titlemodifier="&mainWindow.titlemodifier;"
- titlemodifier_normal="&mainWindow.titlemodifier;"
- titlemodifier_privatebrowsing="&mainWindow.titlemodifierPrivateBrowsing;"
+ title_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
+ titlemodifier="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
+ titlemodifier_normal="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
+ titlemodifier_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
#endif
titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
windowtype="navigator:browser"
screenX="4" screenY="4"
browsingmode="normal"
persist="screenX screenY width height sizemode">
# All JS files which are not content (only) dependent that browser.xul
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1707,16 +1707,17 @@
this.mTabListeners[ourIndex] = tabListener;
filter.addProgressListener(tabListener,
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
ourBrowser.webProgress.addProgressListener(filter,
Components.interfaces.nsIWebProgress.NOTIFY_ALL);
this.setTabTitle(aOurTab);
+ this.updateIcon(aOurTab);
// If the tab was already selected (this happpens in the scenario
// of replaceTabWithWindow), notify onLocationChange, etc.
if (aOurTab == this.selectedTab)
this.updateCurrentBrowser(true);
]]>
</body>
</method>
@@ -1906,20 +1907,23 @@
<method name="_onDragStart">
<parameter name="aEvent"/>
<body>
<![CDATA[
var target = aEvent.target;
if (target.localName == "tab" &&
aEvent.originalTarget.localName != "toolbarbutton") {
var dt = aEvent.dataTransfer;
- dt.mozSetDataAt("application/x-moz-tabbrowser-tab", target, 0);
+ dt.mozSetDataAt(TAB_DROP_TYPE, target, 0);
var uri = this.getBrowserForTab(aEvent.target).currentURI;
var spec = uri ? uri.spec : "about:blank";
- dt.mozSetDataAt("text/x-moz-url", spec + "\n" + aEvent.target.label, 0);
+
+ // We must not set text/x-moz-url data, otherwise trying to deatch
+ // the tab by dropping it on the desktop would result in an
+ // "internet shortcut"
dt.mozSetDataAt("text/plain", spec, 0);
var canvas = tabPreviews.capture(target, false);
dt.setDragImage(canvas, 0, 0);
aEvent.stopPropagation();
}
this._dragLeftWindow = false;
@@ -1941,18 +1945,18 @@
var dt = aEvent.dataTransfer;
// Disallow dropping multiple items
if (dt.mozItemCount > 1)
return dt.effectAllowed = "none";
var types = dt.mozTypesAt(0);
var sourceNode = null;
// tabs are always added as the first type
- if (types[0] == "application/x-moz-tabbrowser-tab") {
- var sourceNode = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
+ if (types[0] == TAB_DROP_TYPE) {
+ var sourceNode = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
if (sourceNode instanceof XULElement &&
sourceNode.localName == "tab" &&
(sourceNode.parentNode == this.mTabContainer ||
(sourceNode.ownerDocument.defaultView instanceof ChromeWindow &&
sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser"))) {
if (sourceNode.parentNode == this.mTabContainer &&
(aEvent.screenX >= sourceNode.boxObject.screenX &&
aEvent.screenX <= (sourceNode.boxObject.screenX +
@@ -2080,17 +2084,17 @@
<method name="_onDrop">
<parameter name="aEvent"/>
<body>
<![CDATA[
var dt = aEvent.dataTransfer;
var dropEffect = dt.dropEffect;
var draggedTab;
if (dropEffect != "link") { // copy or move
- draggedTab = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
+ draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
// not our drop then
if (!draggedTab)
return;
}
this.mTabDropIndicatorBar.collapsed = true;
aEvent.stopPropagation();
@@ -2203,17 +2207,17 @@
return;
var dt = aEvent.dataTransfer;
// The dropEffect == "none" scenarios:
// 1. Drop-within-the-tabbae
// 2. Drop on some other tabbar
// 3. Drop on text fields (even outside our window)
if (dt.dropEffect == "none") {
- var draggedTab = dt.mozGetDataAt("application/x-moz-tabbrowser-tab", 0);
+ var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
this.replaceTabWithWindow(draggedTab);
}
aEvent.stopPropagation();
]]>
</body>
</method>
<method name="browserWindowOnDragEnter">
@@ -2819,28 +2823,69 @@
<implementation>
<!-- Override scrollbox.xml method, since our scrollbox's children are
inherited from the binding parent -->
<method name="_getScrollableElements">
<body><![CDATA[
return document.getBindingParent(this).childNodes;
]]></body>
</method>
-
-#ifndef XP_MACOSX
- </implementation>
-#else
+#ifdef XP_MACOSX
<field name="_scrollButtonDownBox">
document.getAnonymousElementByAttribute(this, "anonid", "down-box");
</field>
<field name="_scrollButtonDownBoxAnimate">
document.getAnonymousElementByAttribute(this, "anonid", "down-box-animate");
</field>
+#endif
</implementation>
+ <handlers>
+ <handler event="underflow"><![CDATA[
+ if (event.detail == 0)
+ return; // Ignore vertical events
+
+ var tabs = document.getBindingParent(this);
+ tabs.removeAttribute("overflow");
+#ifdef XP_MACOSX
+ this._scrollButtonDownBox.collapsed = true;
+ this._scrollButtonDownBoxAnimate.collapsed = true;
+#endif
+ ]]></handler>
+ <handler event="overflow"><![CDATA[
+ if (event.detail == 0)
+ return; // Ignore vertical events
+
+ var tabs = document.getBindingParent(this);
+ tabs.setAttribute("overflow", "true");
+#ifdef XP_MACOSX
+ this._scrollButtonDownBox.collapsed = false;
+ this._scrollButtonDownBoxAnimate.collapsed = false;
+#endif
+ this.scrollBoxObject.ensureElementIsVisible(tabs.selectedItem);
+ ]]></handler>
+
+#ifdef XP_MACOSX
+ <handler event="UpdatedScrollButtonsDisabledState"><![CDATA[
+ // fix for bug #352353
+ // unlike the scrollup button on the tab strip (which is a
+ // simple toolbarbutton) the scrolldown button is
+ // a more complicated stack of boxes and a toolbarbutton
+ // so that we can animate when a tab is opened offscreen.
+ // in order to style the box with the actual background image
+ // we need to manually set the disable state to match the
+ // disable state of the toolbarbutton.
+ this._scrollButtonDownBox
+ .setAttribute("disabled", this._scrollButtonDown.disabled);
+ ]]></handler>
+#endif
+
+ </handlers>
+
+#ifdef XP_MACOSX
<content>
<xul:toolbarbutton class="scrollbutton-up" collapsed="true"
xbl:inherits="orient"
anonid="scrollbutton-up"
onclick="_distanceScroll(event);"
onmousedown="_startScroll(-1);"
onmouseover="_continueScroll(-1);"
onmouseup="_stopScroll();"
@@ -2860,64 +2905,16 @@
onclick="_distanceScroll(event);"
onmousedown="_startScroll(1);"
onmouseover="_continueScroll(1);"
onmouseup="_stopScroll();"
onmouseout="_pauseScroll();"
chromedir="&locale.dir;"/>
</xul:stack>
</content>
-
- <handlers>
- <handler event="underflow"><![CDATA[
- // filter underflow events which were dispatched on nested scrollboxes
- if (event.target != this)
- return;
-
- // Ignore vertical events.
- if (event.detail == 0) {
- return;
- }
-
- this._scrollButtonDownBox.collapsed = true;
- this._scrollButtonDownBoxAnimate.collapsed = true;
- ]]></handler>
-
- <handler event="overflow"><![CDATA[
- // filter underflow events which were dispatched on nested scrollboxes
- if (event.target != this)
- return;
-
- // Ignore vertical events.
- if (event.detail == 0) {
- return;
- }
-
- this._scrollButtonDownBox.collapsed = false;
- this._scrollButtonDownBoxAnimate.collapsed = false;
- ]]></handler>
-
- <handler event="UpdatedScrollButtonsDisabledState"><![CDATA[
- // filter underflow events which were dispatched on nested scrollboxes
- if (event.target != this)
- return;
-
- // fix for bug #352353
- // unlike the scrollup button on the tab strip (which is a
- // simple toolbarbutton) the scrolldown button is
- // a more complicated stack of boxes and a toolbarbutton
- // so that we can animate when a tab is opened offscreen.
- // in order to style the box with the actual background image
- // we need to manually set the disable state to match the
- // disable state of the toolbarbutton.
- this._scrollButtonDownBox
- .setAttribute("disabled", this._scrollButtonDown.disabled);
- ]]></handler>
-
- </handlers>
#endif
</binding>
<binding id="tabbrowser-tabs"
extends="chrome://global/content/bindings/tabbox.xml#tabs">
<content>
<xul:stack flex="1" class="tabs-stack">
<xul:vbox>
@@ -2993,42 +2990,31 @@
this.firstChild.minWidth = this.mTabMinWidth;
this.firstChild.maxWidth = this.mTabMaxWidth;
this.adjustTabstrip();
pb2.addObserver("browser.tabs.closeButtons",
this._prefObserver, false);
window.addEventListener("resize", this, false);
-
- // Listen to overflow/underflow events on the tabstrip,
- // we cannot put these as xbl handlers on the entire binding because
- // they would also get called for the all-tabs popup scrollbox.
- // Also, we can't rely on event.target becuase these are all
- // anonymous nodes.
- this.mTabstrip.addEventListener("overflow", this, false);
- this.mTabstrip.addEventListener("underflow", this, false);
]]>
</constructor>
<destructor>
<![CDATA[
var pb2 =
Components.classes['@mozilla.org/preferences-service;1'].
getService(Components.interfaces.nsIPrefBranch2);
pb2.removeObserver("browser.tabs.closeButtons", this._prefObserver);
// Release timer to avoid reference cycles.
if (this._animateTimer) {
this._animateTimer.cancel();
this._animateTimer = null;
}
-
- this.mTabstrip.removeEventListener("overflow", this, false);
- this.mTabstrip.removeEventListener("underflow", this, false);
]]>
</destructor>
<field name="mTabstripWidth">0</field>
<field name="mTabstrip">
document.getAnonymousElementByAttribute(this, "anonid", "arrowscrollbox");
</field>
@@ -3140,24 +3126,16 @@
} catch (e) {}
]]></body>
</method>
<method name="handleEvent">
<parameter name="aEvent"/>
<body><![CDATA[
switch (aEvent.type) {
- case "overflow":
- this.setAttribute("overflow", "true");
- this.mTabstrip.scrollBoxObject
- .ensureElementIsVisible(this.selectedItem);
- break;
- case "underflow":
- this.removeAttribute("overflow");
- break;
case "resize":
var width = this.mTabstrip.boxObject.width;
if (width != this.mTabstripWidth) {
this.adjustTabstrip();
this._fillTrailingGap();
this._handleTabSelect();
this.mTabstripWidth = width;
}
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -45,16 +45,23 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES = test_feed_discovery.html \
feed_discovery.html \
test_bug395533.html \
bug395533-data.txt \
test_contextmenu.html \
subtst_contextmenu.html \
ctxmenu-image.png \
+ test_offlineNotification.html \
+ offlineChild.html \
+ offlineChild.cacheManifest \
+ offlineChild.cacheManifest^headers^ \
+ offlineChild2.html \
+ offlineChild2.cacheManifest \
+ offlineChild2.cacheManifest^headers^ \
$(NULL)
# browser_bug423833.js disabled temporarily since it's unreliable: bug 428712
# browser_sanitize-download-history.js disabled temporarily since it's unreliable: bug 432425
_BROWSER_FILES = browser_bug321000.js \
browser_sanitize-timespans.js \
browser_bug405137.js \
browser_bug409481.js \
@@ -84,16 +91,18 @@ include $(topsrcdir)/config/rules.mk
zoom_test.html \
browser_bug416661.js \
browser_bug386835.js \
dummy_page.html \
browser_bug422590.js \
browser_sanitize-sitepermissions.js \
browser_bug356571.js \
browser_sanitize-passwordDisabledHosts.js \
+ browser_bug479408.js \
+ browser_bug479408_sample.html \
$(NULL)
ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
_BROWSER_FILES += browser_customize.js \
$(NULL)
endif
libs:: $(_TEST_FILES)
--- a/browser/base/content/test/browser_alltabslistener.js
+++ b/browser/base/content/test/browser_alltabslistener.js
@@ -1,92 +1,103 @@
const Ci = Components.interfaces;
const gCompleteState = Ci.nsIWebProgressListener.STATE_STOP +
Ci.nsIWebProgressListener.STATE_IS_NETWORK;
+function LOG(str) {
+ dump(str + "\n");
+}
+
var gFrontProgressListener = {
onProgressChange: function (aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
},
onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
var state = "onStateChange";
+ LOG("FrontProgress: " + state + " 0x" + aStateFlags.toString(16));
ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
gFrontNotificationsPos++;
},
onLocationChange: function (aWebProgress, aRequest, aLocationURI) {
var state = "onLocationChange";
+ LOG("FrontProgress: " + state + " " + aLocationURI.spec);
ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
gFrontNotificationsPos++;
},
onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
},
onSecurityChange: function (aWebProgress, aRequest, aState) {
var state = "onSecurityChange";
+ LOG("FrontProgress: " + state + " 0x" + aState.toString(16));
ok(gFrontNotificationsPos < gFrontNotifications.length, "Got an expected notification for the front notifications listener");
is(state, gFrontNotifications[gFrontNotificationsPos], "Got a notification for the front notifications listener");
gFrontNotificationsPos++;
}
}
var gAllProgressListener = {
onProgressChange: function (aBrowser, aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
},
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
var state = "onStateChange";
+ LOG("AllProgress: " + state + " 0x" + aStateFlags.toString(16));
ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
gAllNotificationsPos++;
if ((aStateFlags & gCompleteState) == gCompleteState) {
ok(gAllNotificationsPos == gAllNotifications.length, "Saw the expected number of notifications");
ok(gFrontNotificationsPos == gFrontNotifications.length, "Saw the expected number of frontnotifications");
executeSoon(gNextTest);
}
},
onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) {
var state = "onLocationChange";
+ LOG("AllProgress: " + state + " " + aLocationURI.spec);
ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
gAllNotificationsPos++;
},
onStatusChange: function (aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
var state = "onStatusChange";
ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
},
onSecurityChange: function (aBrowser, aWebProgress, aRequest, aState) {
var state = "onSecurityChange";
+ LOG("AllProgress: " + state + " 0x" + aState.toString(16));
ok(aBrowser == gTestBrowser, state + " notification came from the correct browser");
ok(gAllNotificationsPos < gAllNotifications.length, "Got an expected notification for the all notifications listener");
is(state, gAllNotifications[gAllNotificationsPos], "Got a notification for the all notifications listener");
gAllNotificationsPos++;
}
}
var gFrontNotifications, gAllNotifications, gFrontNotificationsPos, gAllNotificationsPos;
var gBackgroundTab, gForegroundTab, gBackgroundBrowser, gForegroundBrowser, gTestBrowser;
var gTestPage = "/browser/browser/base/content/test/alltabslistener.html";
var gNextTest;
function test() {
+ LOG("Running tests from alltabslistener.js");
waitForExplicitFinish();
gBackgroundTab = gBrowser.addTab("about:blank");
gForegroundTab = gBrowser.addTab("about:blank");
gBackgroundBrowser = gBrowser.getBrowserForTab(gBackgroundTab);
gForegroundBrowser = gBrowser.getBrowserForTab(gForegroundTab);
gBrowser.selectedTab = gForegroundTab;
@@ -104,65 +115,70 @@ function runTest(browser, url, next) {
}
function startTests() {
gForegroundBrowser.removeEventListener("load", startTests, true);
executeSoon(startTest1);
}
function startTest1() {
+ LOG("\nTest 1");
gBrowser.addProgressListener(gFrontProgressListener);
gBrowser.addTabsProgressListener(gAllProgressListener);
gAllNotifications = [
"onStateChange",
"onLocationChange",
"onSecurityChange",
"onStateChange"
];
gFrontNotifications = gAllNotifications;
runTest(gForegroundBrowser, "http://example.org" + gTestPage, startTest2);
}
function startTest2() {
+ LOG("\nTest 2");
gAllNotifications = [
"onStateChange",
"onLocationChange",
"onSecurityChange",
"onSecurityChange",
"onStateChange"
];
gFrontNotifications = gAllNotifications;
runTest(gForegroundBrowser, "https://example.com" + gTestPage, startTest3);
}
function startTest3() {
+ LOG("\nTest 3");
gAllNotifications = [
"onStateChange",
"onLocationChange",
"onSecurityChange",
"onStateChange"
];
gFrontNotifications = [];
runTest(gBackgroundBrowser, "http://example.org" + gTestPage, startTest4);
}
function startTest4() {
+ LOG("\nTest 4");
gAllNotifications = [
"onStateChange",
"onLocationChange",
"onSecurityChange",
"onSecurityChange",
"onStateChange"
];
gFrontNotifications = [];
runTest(gBackgroundBrowser, "https://example.com" + gTestPage, startTest5);
}
function startTest5() {
+ LOG("\nTest 5");
// Switch the foreground browser
[gForegroundBrowser, gBackgroundBrowser] = [gBackgroundBrowser, gForegroundBrowser];
[gForegroundTab, gBackgroundTab] = [gBackgroundTab, gForegroundTab];
// Avoid the onLocationChange this will fire
gBrowser.removeProgressListener(gFrontProgressListener);
gBrowser.selectedTab = gForegroundTab;
gBrowser.addProgressListener(gFrontProgressListener);
@@ -172,25 +188,27 @@ function startTest5() {
"onSecurityChange",
"onStateChange"
];
gFrontNotifications = gAllNotifications;
runTest(gForegroundBrowser, "http://example.org" + gTestPage, startTest6);
}
function startTest6() {
+ LOG("\nTest 6");
gAllNotifications = [
"onStateChange",
"onLocationChange",
"onSecurityChange",
"onStateChange"
];
gFrontNotifications = [];
runTest(gBackgroundBrowser, "http://example.org" + gTestPage, finishTest);
}
function finishTest() {
+ LOG("\nFinished tests from alltabslistener.js");
gBrowser.removeProgressListener(gFrontProgressListener);
gBrowser.removeTabsProgressListener(gAllProgressListener);
gBrowser.removeTab(gBackgroundTab);
gBrowser.removeTab(gForegroundTab);
finish();
}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug479408.js
@@ -0,0 +1,17 @@
+function test() {
+ waitForExplicitFinish();
+ let tab = gBrowser.selectedTab = gBrowser.addTab(
+ "http://localhost:8888/browser/browser/base/content/test/browser_bug479408_sample.html");
+
+ gBrowser.addEventListener("DOMLinkAdded", function(aEvent) {
+ gBrowser.removeEventListener("DOMLinkAdded", arguments.callee, true);
+
+ executeSoon(function() {
+ ok(!tab.linkedBrowser.engines,
+ "the subframe's search engine wasn't detected");
+
+ gBrowser.removeTab(tab);
+ finish();
+ });
+ }, true);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_bug479408_sample.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<title>Testcase for bug 479408</title>
+
+<iframe src='data:text/html,<link%20rel="search"%20type="application/opensearchdescription+xml"%20title="Search%20bug%20479408"%20href="http://example.com/search.xml">'>
--- a/browser/base/content/test/browser_gestureSupport.js
+++ b/browser/base/content/test/browser_gestureSupport.js
@@ -80,16 +80,25 @@ let test_expectedDelta;
let test_expectedModifiers;
function test_gestureListener(evt)
{
is(evt.type, test_expectedType,
"evt.type (" + evt.type + ") does not match expected value");
is(evt.target, test_utils.elementFromPoint(20, 20, false, false),
"evt.target (" + evt.target + ") does not match expected value");
+ is(evt.clientX, 20,
+ "evt.clientX (" + evt.clientX + ") does not match expected value");
+ is(evt.clientY, 20,
+ "evt.clientY (" + evt.clientY + ") does not match expected value");
+ isnot(evt.screenX, 0,
+ "evt.screenX (" + evt.screenX + ") does not match expected value");
+ isnot(evt.screenY, 0,
+ "evt.screenY (" + evt.screenY + ") does not match expected value");
+
is(evt.direction, test_expectedDirection,
"evt.direction (" + evt.direction + ") does not match expected value");
is(evt.delta, test_expectedDelta,
"evt.delta (" + evt.delta + ") does not match expected value");
is(evt.shiftKey, (test_expectedModifiers & Components.interfaces.nsIDOMNSEvent.SHIFT_MASK) != 0,
"evt.shiftKey did not match expected value");
is(evt.ctrlKey, (test_expectedModifiers & Components.interfaces.nsIDOMNSEvent.CONTROL_MASK) != 0,
@@ -182,33 +191,44 @@ function test_helper2(type, direction, d
successful = true;
}
catch (ex) {
successful = false;
}
ok(successful, "Unable to create SimpleGestureEvent");
try {
- event.initSimpleGestureEvent(type, true, true, null, 0, direction,
- delta, altKey, ctrlKey, shiftKey, metaKey);
+ event.initSimpleGestureEvent(type, true, true, window, 1,
+ 10, 10, 10, 10,
+ ctrlKey, altKey, shiftKey, metaKey,
+ 1, window,
+ direction, delta);
successful = true;
}
catch (ex) {
successful = false;
}
ok(successful, "event.initSimpleGestureEvent should not fail");
// Make sure the event fields match the expected values
is(event.type, type, "Mismatch on evt.type");
is(event.direction, direction, "Mismatch on evt.direction");
is(event.delta, delta, "Mismatch on evt.delta");
is(event.altKey, altKey, "Mismatch on evt.altKey");
is(event.ctrlKey, ctrlKey, "Mismatch on evt.ctrlKey");
is(event.shiftKey, shiftKey, "Mismatch on evt.shiftKey");
is(event.metaKey, metaKey, "Mismatch on evt.metaKey");
+ is(event.view, window, "Mismatch on evt.view");
+ is(event.detail, 1, "Mismatch on evt.detail");
+ is(event.clientX, 10, "Mismatch on evt.clientX");
+ is(event.clientY, 10, "Mismatch on evt.clientY");
+ is(event.screenX, 10, "Mismatch on evt.screenX");
+ is(event.screenY, 10, "Mismatch on evt.screenY");
+ is(event.button, 1, "Mismatch on evt.button");
+ is(event.relatedTarget, window, "Mismatch on evt.relatedTarget");
// Test event dispatch
let expectedEventCount = test_eventCount + 1;
document.addEventListener(type, test_eventDispatchListener, true);
document.dispatchEvent(event);
document.removeEventListener(type, test_eventDispatchListener, true);
is(expectedEventCount, test_eventCount, "Dispatched event was never received by listener");
}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild.cacheManifest
@@ -0,0 +1,2 @@
+CACHE MANIFEST
+offlineChild.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild.cacheManifest^headers^
@@ -0,0 +1,1 @@
+Content-Type: text/cache-manifest
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild.html
@@ -0,0 +1,20 @@
+<html manifest="offlineChild.cacheManifest">
+<head>
+<title></title>
+<script type="text/javascript">
+
+function finish(success) {
+ window.parent.postMessage(success ? "success" : "failure", "*");
+}
+
+applicationCache.oncached = function() { finish(true); }
+applicationCache.onnoupdate = function() { finish(true); }
+applicationCache.onerror = function() { finish(false); }
+
+</script>
+</head>
+
+<body>
+<h1>Child</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild2.cacheManifest
@@ -0,0 +1,2 @@
+CACHE MANIFEST
+offlineChild2.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild2.cacheManifest^headers^
@@ -0,0 +1,1 @@
+Content-Type: text/cache-manifest
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/offlineChild2.html
@@ -0,0 +1,20 @@
+<html manifest="offlineChild2.cacheManifest">
+<head>
+<title></title>
+<script type="text/javascript">
+
+function finish(success) {
+ window.parent.postMessage(success ? "success" : "failure", "*");
+}
+
+applicationCache.oncached = function() { finish(true); }
+applicationCache.onnoupdate = function() { finish(true); }
+applicationCache.onerror = function() { finish(false); }
+
+</script>
+</head>
+
+<body>
+<h1>Child</h1>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/test_offlineNotification.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=462856
+-->
+<head>
+ <title>Test offline app notification</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="loaded()">
+<p id="display">
+<!-- Load the test frame twice from the same domain,
+ to make sure we get notifications for both -->
+<iframe name="testFrame" src="offlineChild.html"></iframe>
+<iframe name="testFrame2" src="offlineChild2.html"></iframe>
+<!-- Load from another domain to make sure we get a second allow/deny
+ notification -->
+<iframe name="testFrame3" src="http://example.com/tests/browser/base/content/test/offlineChild.html"></iframe>
+
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var numFinished = 0;
+
+window.addEventListener("message", function(event) {
+ is(event.data, "success", "Child was successfully cached.");
+
+ if (++numFinished == 3) {
+ // Clean up after ourself
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var pm = Components.classes["@mozilla.org/permissionmanager;1"].
+ getService(Components.interfaces.nsIPermissionManager);
+
+ pm.remove(frames.testFrame.document.documentURIObject.host, "offline-app");
+ pm.remove(frames.testFrame3.document.documentURIObject.host, "offline-app");
+
+ SimpleTest.finish();
+ }
+ }, false);
+
+function loaded() {
+ // Click the notification bar's "Allow" button. This should kick
+ // off updates, which will eventually lead to getting messages from
+ // the children.
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+ var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
+ getService(Components.interfaces.nsIWindowMediator);
+ var win = wm.getMostRecentWindow("navigator:browser");
+ var notificationBox = win.gBrowser.getNotificationBox();
+
+ var notification = notificationBox.getNotificationWithValue("offline-app-requested-localhost");
+ notification.childNodes[0].click();
+
+ notification = notificationBox.getNotificationWithValue("offline-app-requested-example.com");
+ notification.childNodes[0].click();
+}
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -37,16 +37,18 @@
#
# ***** END LICENSE BLOCK *****
/**
* Communicator Shared Utility Library
* for shared application glue for the Communicator suite of applications
**/
+var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
+
var gBidiUI = false;
function getBrowserURL()
{
return "chrome://browser/content/browser.xul";
}
function goToggleToolbar( id, elementID )
--- a/browser/branding/unofficial/branding.nsi
+++ b/browser/branding/unofficial/branding.nsi
@@ -32,24 +32,16 @@
# 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 *****
# NSIS branding defines for unofficial builds.
# The official release build branding.nsi is located in other-license/branding/firefox/
# The nightly build branding.nsi is located in browser/installer/windows/nsis/
-!define BrandShortName "Shiretoko"
+
# BrandFullNameInternal is used for some registry and file system values
# instead of BrandFullName and typically should not be modified.
!define BrandFullNameInternal "Shiretoko"
!define CompanyName "mozilla.org"
!define URLInfoAbout "http://www.mozilla.org"
!define URLUpdateInfo "http://www.mozilla.org/projects/firefox"
!define SurveyURL "https://survey.mozilla.com/1/Mozilla%20Firefox/${AppVersion}/${AB_CD}/exit.html"
-
-# Everything below this line may be modified for Alpha / Beta releases.
-!define BrandFullName "Shiretoko"
-
-# Add !define NO_INSTDIR_FROM_REG to prevent finding a non-default installation
-# directory in the registry and using that as the default. This prevents
-# Beta releases built with official branding from finding an existing install
-# of an official release and defaulting to its installation directory.
--- a/browser/branding/unofficial/pref/firefox-branding.js
+++ b/browser/branding/unofficial/pref/firefox-branding.js
@@ -1,13 +1,16 @@
pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/");
pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/");
// The time interval between checks for a new version (in seconds)
// nightly=8 hours, official=24 hours
pref("app.update.interval", 28800);
+// The time interval between the downloading of mar file chunks in the
+// background (in seconds)
+pref("app.update.download.backgroundInterval", 60);
// URL user can browse to manually if for some reason all update installation
// attempts fail.
pref("app.update.url.manual", "http://www.mozilla.org/products/%APP%/");
// A default value for the "More information about this update" link
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/");
// Release notes URL
--- a/browser/components/build/Makefile.in
+++ b/browser/components/build/Makefile.in
@@ -25,16 +25,17 @@ REQUIRES = \
uriloader \
intl \
necko \
shellservice \
xulapp \
places \
browserplaces \
microsummaries \
+ privatebrowsing \
$(NULL)
EXPORTS = nsBrowserCompsCID.h
CPPSRCS = nsModule.cpp \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
@@ -42,25 +43,27 @@ DEFINES += -DPSTOREC_DLL=\"$(subst \,\\,
OS_LIBS += $(call EXPAND_LIBNAME,ole32 shell32)
endif
LOCAL_INCLUDES = \
-I$(srcdir)/../shell/src \
-I$(srcdir)/../feeds/src \
-I$(srcdir)/../places/src \
+ -I$(srcdir)/../privatebrowsing/src \
$(NULL)
ifeq ($(OS_ARCH),WINNT)
OS_LIBS += $(call EXPAND_LIBNAME,version)
endif
SHARED_LIBRARY_LIBS = \
../feeds/src/$(LIB_PREFIX)browser_feeds_s.$(LIB_SUFFIX) \
../places/src/$(LIB_PREFIX)browserplaces_s.$(LIB_SUFFIX) \
+ ../privatebrowsing/src/$(LIB_PREFIX)privatebrowsing_s.$(LIB_SUFFIX) \
$(NULL)
ifneq (,$(filter windows mac cocoa gtk2, $(MOZ_WIDGET_TOOLKIT)))
SHARED_LIBRARY_LIBS += ../shell/src/$(LIB_PREFIX)shellservice_s.$(LIB_SUFFIX)
endif
EXTRA_DSO_LDOPTS += \
$(call EXPAND_LIBNAME_PATH,unicharutil_external_s,$(LIBXUL_DIST)/lib) \
--- a/browser/components/build/nsBrowserCompsCID.h
+++ b/browser/components/build/nsBrowserCompsCID.h
@@ -92,8 +92,12 @@
{ 0x12ff56ec, 0x58be, 0x402c, { 0xb0, 0x57, 0x1, 0xf9, 0x61, 0xde, 0x96, 0x9b } }
// 6fb0c970-e1b1-11db-8314-0800200c9a66
#define NS_PLACESIMPORTEXPORTSERVICE_CID \
{ 0x6fb0c970, 0xe1b1, 0x11db, { 0x83, 0x14, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
#define NS_PLACESIMPORTEXPORTSERVICE_CONTRACTID \
"@mozilla.org/browser/places/import-export-service;1"
+
+// 136e2c4d-c5a4-477c-b131-d93d7d704f64
+#define NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID \
+{ 0x136e2c4d, 0xc5a4, 0x477c, { 0xb1, 0x31, 0xd9, 0x3d, 0x7d, 0x70, 0x4f, 0x64 } }
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -72,16 +72,19 @@
#endif // WINCE
#include "rdf.h"
#include "nsFeedSniffer.h"
#include "nsAboutFeeds.h"
#include "nsIAboutModule.h"
+#include "nsPrivateBrowsingServiceWrapper.h"
+#include "nsNetCID.h"
+
/////////////////////////////////////////////////////////////////////////////
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlacesImportExportService)
#if defined(XP_WIN)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindowsShellService)
#elif defined(XP_MACOSX)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacShellService)
#elif defined(MOZ_WIDGET_GTK2)
@@ -108,16 +111,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacIEPr
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCaminoProfileMigrator)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsICabProfileMigrator)
#endif
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrivateBrowsingServiceWrapper, Init)
+
/////////////////////////////////////////////////////////////////////////////
static const nsModuleComponentInfo components[] =
{
#if defined(XP_WIN)
{ "Browser Shell Service",
NS_SHELLSERVICE_CID,
NS_SHELLSERVICE_CONTRACTID,
@@ -212,15 +217,20 @@ static const nsModuleComponentInfo compo
{ "Phoenix Profile Migrator",
NS_PHOENIXPROFILEMIGRATOR_CID,
NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "phoenix",
nsPhoenixProfileMigratorConstructor },
{ "Seamonkey Profile Migrator",
NS_SEAMONKEYPROFILEMIGRATOR_CID,
NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "seamonkey",
- nsSeamonkeyProfileMigratorConstructor }
+ nsSeamonkeyProfileMigratorConstructor },
#endif /* WINCE */
+
+ { "PrivateBrowsing Service C++ Wrapper",
+ NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID,
+ NS_PRIVATE_BROWSING_SERVICE_CONTRACTID,
+ nsPrivateBrowsingServiceWrapperConstructor }
};
NS_IMPL_NSGETMODULE(nsBrowserCompsModule, components)
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -19,16 +19,17 @@
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Giorgio Maone <g.maone@informaction.com>
# Seth Spitzer <sspitzer@mozilla.com>
# Asaf Romano <mano@mozilla.com>
# Marco Bonardo <mak77@bonardo.net>
# Dietrich Ayala <dietrich@mozilla.com>
+# Ehsan Akhgari <ehsan.akhgari@gmail.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
@@ -318,17 +319,21 @@ BrowserGlue.prototype = {
if (sessionWillBeSaved || !this._prefs.getBoolPref("browser.warnOnQuit"))
showPrompt = false;
else if (aQuitType == "restart")
showPrompt = this._prefs.getBoolPref("browser.warnOnRestart");
else
showPrompt = this._prefs.getBoolPref("browser.tabs.warnOnClose");
} catch (ex) {}
- if (!showPrompt)
+ // Never show a prompt inside the private browsing mode
+ var inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
+ getService(Ci.nsIPrivateBrowsingService).
+ privateBrowsingEnabled;
+ if (!showPrompt || inPrivateBrowsing)
return false;
var buttonChoice = 0;
var quitBundle = this._bundleService.createBundle("chrome://browser/locale/quitDialog.properties");
var brandBundle = this._bundleService.createBundle("chrome://branding/locale/brand.properties");
var appName = brandBundle.GetStringFromName("brandShortName");
var quitDialogTitle = quitBundle.formatStringFromName(aQuitType + "DialogTitle",
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -1330,16 +1330,29 @@ var PlacesControllerDragHelper = {
// Check every dragged item
for (var i = 0; i < dropCount; i++) {
var flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
if (!flavor)
return false;
var data = dt.mozGetDataAt(flavor, i);
+ // urls can be dropped on any insertionpoint
+ // XXXmano: // Remember: this method is called for each dragover event!
+ // Thus we shouldn't use unwrapNodes here at all if possible.
+ // I think it would be OK to accept bogus data here (e.g. text which was
+ // somehow wrapped as TAB_DROP_TYPE, this is not in our control, and
+ // will just case the actual drop to be a no-op), and only rule out valid
+ // expected cases, which are either unsupported flavors, or items which
+ // cannot be dropped in the current insertionpoint. The last case will
+ // likely force us to use unwrapNodes for the private data types of
+ // places.
+ if (flavor == TAB_DROP_TYPE)
+ continue;
+
try {
var dragged = PlacesUtils.unwrapNodes(data, flavor)[0];
} catch (e) {
return false;
}
// Only bookmarks and urls can be dropped into tag containers
if (ip.isTag && ip.orientation == Ci.nsITreeView.DROP_ON &&
@@ -1358,16 +1371,17 @@ var PlacesControllerDragHelper = {
return false;
parentId = PlacesUtils.bookmarks.getFolderIdForItem(parentId);
}
}
}
return true;
},
+
/**
* Determines if a node can be moved.
*
* @param aNode
* A nsINavHistoryResultNode node.
* @returns True if the node can be moved, false otherwise.
*/
canMoveNode:
@@ -1439,18 +1453,32 @@ var PlacesControllerDragHelper = {
var dropCount = dt.mozItemCount;
var movedCount = 0;
for (var i = 0; i < dropCount; ++i) {
var flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
if (!flavor)
return false;
var data = dt.mozGetDataAt(flavor, i);
- // There's only ever one in the D&D case.
- var unwrapped = PlacesUtils.unwrapNodes(data, flavor)[0];
+ var unwrapped;
+ if (flavor != TAB_DROP_TYPE) {
+ // There's only ever one in the D&D case.
+ unwrapped = PlacesUtils.unwrapNodes(data, flavor)[0];
+ }
+ else if (data instanceof XULElement && data.localName == "tab" &&
+ data.ownerDocument.defaultView instanceof ChromeWindow) {
+ var uri = data.linkedBrowser.currentURI;
+ var spec = uri ? uri.spec : "about:blank";
+ var title = data.label;
+ unwrapped = { uri: spec,
+ title: data.label,
+ type: PlacesUtils.TYPE_X_MOZ_URL};
+ }
+ else
+ throw("bogus data was passed as a tab")
var index = insertionPoint.index;
// Adjust insertion index to prevent reversal of dragged items. When you
// drag multiple elts upward: need to increment index or each successive
// elt will be inserted at the same index, each above the previous.
var dragginUp = insertionPoint.itemId == unwrapped.parent &&
index < PlacesUtils.bookmarks.getItemIndex(unwrapped.id);
@@ -1489,20 +1517,22 @@ var PlacesControllerDragHelper = {
return (!PlacesUtils.nodeIsFolder(aContainer) ||
PlacesUtils.nodeIsReadOnly(aContainer));
},
placesFlavors: [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
PlacesUtils.TYPE_X_MOZ_PLACE],
+ // The order matters.
GENERIC_VIEW_DROP_TYPES: [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
PlacesUtils.TYPE_X_MOZ_PLACE,
PlacesUtils.TYPE_X_MOZ_URL,
+ TAB_DROP_TYPE,
PlacesUtils.TYPE_UNICODE],
/**
* Returns our flavourSet
*/
get flavourSet() {
delete this.flavourSet;
var flavourSet = new FlavourSet();
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -412,51 +412,59 @@ var PlacesOrganizer = {
},
/**
* Populates the restore menu with the dates of the backups available.
*/
populateRestoreMenu: function PO_populateRestoreMenu() {
var restorePopup = document.getElementById("fileRestorePopup");
+ var dateSvc = Cc["@mozilla.org/intl/scriptabledateformat;1"].
+ getService(Ci.nsIScriptableDateFormat);
+
// remove existing menu items
// last item is the restoreFromFile item
while (restorePopup.childNodes.length > 1)
restorePopup.removeChild(restorePopup.firstChild);
// get list of files
var localizedFilename = PlacesUtils.getString("bookmarksArchiveFilename");
var localizedFilenamePrefix = localizedFilename.substr(0, localizedFilename.indexOf("-"));
var fileList = [];
var files = this.bookmarksBackupDir.directoryEntries;
while (files.hasMoreElements()) {
var f = files.getNext().QueryInterface(Ci.nsIFile);
- var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix + ")-.+\.json");
- if (!f.isHidden() && f.leafName.match(rx))
- fileList.push(f);
+ var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix +
+ ")-([0-9]{4}-[0-9]{2}-[0-9]{2})\.json$");
+ if (!f.isHidden() && f.leafName.match(rx)) {
+ var date = f.leafName.match(rx)[2].replace(/-/g, "/");
+ var dateObj = new Date(date);
+ fileList.push({date: dateObj, filename: f.leafName});
+ }
}
fileList.sort(function PO_fileList_compare(a, b) {
- return b.lastModifiedTime - a.lastModifiedTime;
+ return b.date - a.date;
});
if (fileList.length == 0)
return;
// populate menu
for (var i = 0; i < fileList.length; i++) {
var m = restorePopup.insertBefore
(document.createElement("menuitem"),
document.getElementById("restoreFromFile"));
- var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix + ")-");
- var dateStr = fileList[i].leafName.replace(rx, "").replace(/\.json$/, "");
- if (!dateStr.length)
- dateStr = fileList[i].leafName;
- m.setAttribute("label", dateStr);
- m.setAttribute("value", fileList[i].leafName);
+ m.setAttribute("label",
+ dateSvc.FormatDate("",
+ Ci.nsIScriptableDateFormat.dateFormatLong,
+ fileList[i].date.getFullYear(),
+ fileList[i].date.getMonth() + 1,
+ fileList[i].date.getDate()));
+ m.setAttribute("value", fileList[i].filename);
m.setAttribute("oncommand",
"PlacesOrganizer.onRestoreMenuItemClick(this);");
}
restorePopup.insertBefore(document.createElement("menuseparator"),
document.getElementById("restoreFromFile"));
},
/**
@@ -1497,25 +1505,25 @@ var PlacesQueryBuilder = {
child = child.nextSibling;
}
// update collection type and get folders
var folders = [];
switch (id) {
case "scopeBarHistory":
PlacesSearchBox.filterCollection = "history";
- folders = [];
break;
case "scopeBarFolder":
var selectedFolder = PlacesOrganizer._places.selectedNode.itemId;
// note "all bookmarks" isn't the concrete parent of the top-level
// bookmark folders
if (selectedFolder != PlacesUIUtils.allBookmarksFolderId) {
PlacesSearchBox.filterCollection = "collection";
- folders.push(PlacesOrganizer._places.selectedNode.itemId);
+ folders.push(PlacesUtils.getConcreteItemId(
+ PlacesOrganizer._places.selectedNode));
break;
}
default: // all bookmarks
PlacesSearchBox.filterCollection = "bookmarks";
folders.push(PlacesUtils.bookmarksMenuFolderId,
PlacesUtils.toolbarFolderId,
PlacesUtils.unfiledBookmarksFolderId);
}
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -381,18 +381,19 @@ var PlacesUIUtils = {
// inserting a new separator.
if (copy)
return this.ptm.createSeparator(container, index);
// Move the separator otherwise
return this.ptm.moveItem(data.id, container, index);
break;
default:
if (type == PlacesUtils.TYPE_X_MOZ_URL ||
- type == PlacesUtils.TYPE_UNICODE) {
- var title = (type == PlacesUtils.TYPE_X_MOZ_URL) ? data.title :
+ type == PlacesUtils.TYPE_UNICODE ||
+ type == TAB_DROP_TYPE) {
+ var title = (type != PlacesUtils.TYPE_UNICODE) ? data.title :
data.uri;
return this.ptm.createItem(PlacesUtils._uri(data.uri),
container, index, title);
}
}
return null;
},
--- a/browser/components/places/tests/unit/tail_bookmarks.js
+++ b/browser/components/places/tests/unit/tail_bookmarks.js
@@ -32,33 +32,33 @@
* 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 ***** */
// put cleanup of the bookmarks test here.
+// Run the event loop to be more like the browser, which normally runs the
+// event loop long before code like this would run.
+// Not doing so could cause us to close the connection before all tasks have
+// been completed, and that would crash badly.
+let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
+while (tm.mainThread.hasPendingEvents())
+ tm.mainThread.processNextEvent(false);
+
// XPCShell doesn't dispatch quit-application, to ensure cleanup we have to
// dispatch it after each test run.
var os = Cc['@mozilla.org/observer-service;1'].
getService(Ci.nsIObserverService);
os.notifyObservers(null, "quit-application-granted", null);
os.notifyObservers(null, "quit-application", null);
// try to close the connection so we can remove places.sqlite
var pip = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService).
QueryInterface(Ci.nsPIPlacesDatabase);
if (pip.DBConnection.connectionReady) {
- // Run the event loop to be more like the browser, which normally runs the
- // event loop long before code like this would run.
- // Not doing so could cause us to close the connection between all tasks have
- // been completed, and that would crash badly.
- let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
- while (tm.mainThread.hasPendingEvents())
- tm.mainThread.processNextEvent(false);
-
pip.commitPendingChanges();
pip.finalizeInternalStatements();
pip.DBConnection.close();
do_check_false(pip.DBConnection.connectionReady);
}
--- a/browser/components/places/tests/unit/test_browserGlue_prefs.js
+++ b/browser/components/places/tests/unit/test_browserGlue_prefs.js
@@ -207,24 +207,29 @@ tests.push({
finish_test();
}
});
//------------------------------------------------------------------------------
function finish_test() {
+ // Simulate application closing to remove the idle observer and avoid leaks.
+ os.notifyObservers(null, "quit-application-granted", null);
do_test_finished();
}
var testIndex = 0;
function next_test() {
// Clean up database from all bookmarks.
remove_all_bookmarks();
+ // Simulate application closing to remove the idle observer and avoid leaks.
+ os.notifyObservers(null, "quit-application-granted", null);
+
// nsBrowserGlue stops observing topics after first notification,
// so we add back the observer to test additional runs.
os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false);
// Execute next test.
let test = tests.shift();
dump("\nTEST " + (++testIndex) + ": " + test.description);
test.exec();
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -211,20 +211,34 @@ var gAdvancedPane = {
windowTitle : bundlePreferences.getString("offlinepermissionstitle"),
introText : bundlePreferences.getString("offlinepermissionstext") };
document.documentElement.openWindow("Browser:Permissions",
"chrome://browser/content/preferences/permissions.xul",
"", params);
},
// XXX: duplicated in browser.js
- _getOfflineAppUsage: function (host)
+ _getOfflineAppUsage: function (host, groups)
{
- // XXX Bug 442710: include offline cache usage.
+ var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
+ getService(Components.interfaces.nsIApplicationCacheService);
+ if (!groups) {
+ groups = cacheService.getGroups({});
+ }
+ var ios = Components.classes["@mozilla.org/network/io-service;1"].
+ getService(Components.interfaces.nsIIOService);
+
var usage = 0;
+ for (var i = 0; i < groups.length; i++) {
+ var uri = ios.newURI(groups[i], null, null);
+ if (uri.asciiHost == host) {
+ var cache = cacheService.getActiveCache(groups[i]);
+ usage += cache.usage;
+ }
+ }
var storageManager = Components.classes["@mozilla.org/dom/storagemanager;1"].
getService(Components.interfaces.nsIDOMStorageManager);
usage += storageManager.getUsage(host);
return usage;
},
@@ -236,30 +250,34 @@ var gAdvancedPane = {
var pm = Components.classes["@mozilla.org/permissionmanager;1"]
.getService(Components.interfaces.nsIPermissionManager);
var list = document.getElementById("offlineAppsList");
while (list.firstChild) {
list.removeChild(list.firstChild);
}
+ var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
+ getService(Components.interfaces.nsIApplicationCacheService);
+ var groups = cacheService.getGroups({});
+
var bundle = document.getElementById("bundlePreferences");
var enumerator = pm.enumerator;
while (enumerator.hasMoreElements()) {
var perm = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
if (perm.type == "offline-app" &&
perm.capability != Components.interfaces.nsIPermissionManager.DEFAULT_ACTION &&
perm.capability != Components.interfaces.nsIPermissionManager.DENY_ACTION) {
var row = document.createElement("listitem");
row.id = "";
row.className = "offlineapp";
row.setAttribute("host", perm.host);
var converted = DownloadUtils.
- convertByteUnits(this._getOfflineAppUsage(perm.host));
+ convertByteUnits(this._getOfflineAppUsage(perm.host, groups));
row.setAttribute("usage",
bundle.getFormattedString("offlineAppUsage",
converted));
list.appendChild(row);
}
}
},
@@ -290,24 +308,28 @@ var gAdvancedPane = {
var prompt = bundle.getFormattedString("offlineAppRemovePrompt", [host]);
var confirm = bundle.getString("offlineAppRemoveConfirm");
var result = prompts.confirmEx(window, title, prompt, flags, confirm,
null, null, null, {});
if (result != 0)
return;
// clear offline cache entries
- var cacheService = Components.classes["@mozilla.org/network/cache-service;1"]
- .getService(Components.interfaces.nsICacheService);
- var cacheSession = cacheService.createSession("HTTP-offline",
- Components.interfaces.nsICache.STORE_OFFLINE,
- true)
- .QueryInterface(Components.interfaces.nsIOfflineCacheSession);
- cacheSession.clearKeysOwnedByDomain(host);
- cacheSession.evictUnownedEntries();
+ var cacheService = Components.classes["@mozilla.org/network/application-cache-service;1"].
+ getService(Components.interfaces.nsIApplicationCacheService);
+ var ios = Components.classes["@mozilla.org/network/io-service;1"].
+ getService(Components.interfaces.nsIIOService);
+ var groups = cacheService.getGroups({});
+ for (var i = 0; i < groups.length; i++) {
+ var uri = ios.newURI(groups[i], null, null);
+ if (uri.asciiHost == host) {
+ var cache = cacheService.getActiveCache(groups[i]);
+ cache.discard();
+ }
+ }
// send out an offline-app-removed signal. The nsDOMStorage
// service will clear DOM storage for this host.
var obs = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
obs.notifyObservers(null, "offline-app-removed", host);
// remove the permission
--- a/browser/components/preferences/cookies.js
+++ b/browser/components/preferences/cookies.js
@@ -548,17 +548,17 @@ var gCookiesWindow = {
this._ds.timeFormatSeconds,
date.getFullYear(),
date.getMonth() + 1,
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds());
}
- return this._bundle.getString("AtEndOfSession");
+ return this._bundle.getString("expireAtEndOfSession");
},
_updateCookieData: function (aItem)
{
var seln = this._view.selection;
var ids = ["name", "value", "host", "path", "isSecure", "expires"];
var properties;
--- a/browser/components/preferences/main.xul
+++ b/browser/components/preferences/main.xul
@@ -111,17 +111,17 @@
<menuitem label="&startupBlankPage.label;" value="0"/>
<menuitem label="&startupLastSession.label;" value="3"/>
</menupopup>
</menulist>
</hbox>
<separator class="thin"/>
<hbox align="center">
<label value="&location.label;" accesskey="&location.accesskey;" control="browserHomePage"/>
- <textbox id="browserHomePage" class="padded" flex="1"
+ <textbox id="browserHomePage" class="padded uri-element" flex="1"
type="autocomplete" autocompletesearch="history"
preference="browser.startup.homepage"/>
</hbox>
<hbox align="center" pack="end">
<button label="" accesskey="&useCurrentPage.accesskey;"
label1="&useCurrentPage.label;"
label2="&useMultiple.label;"
oncommand="gMainPane.setHomePageToCurrent();"
--- a/browser/components/privatebrowsing/src/Makefile.in
+++ b/browser/components/privatebrowsing/src/Makefile.in
@@ -37,14 +37,36 @@
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
+MODULE = privatebrowsing
+LIBRARY_NAME = privatebrowsing_s
+FORCE_STATIC_LIB = 1
+FORCE_USE_PIC = 1
+ifndef MOZ_MEMORY
+USE_STATIC_LIBS = 1
+endif
+
+REQUIRES = \
+ xpcom \
+ string \
+ necko \
+ js \
+ xpconnect \
+ $(NULL)
+
+CPPSRCS = \
+ nsPrivateBrowsingServiceWrapper.cpp \
+ $(NULL)
+
+LOCAL_INCLUDES = -I$(srcdir)/../../build
+
EXTRA_PP_COMPONENTS = \
nsPrivateBrowsingService.js \
aboutPrivateBrowsing.js \
$(NULL)
include $(topsrcdir)/config/rules.mk
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -75,16 +75,17 @@ const Cu = Components.utils;
const Cr = Components.results;
////////////////////////////////////////////////////////////////////////////////
//// PrivateBrowsingService
function PrivateBrowsingService() {
this._obs.addObserver(this, "profile-after-change", true);
this._obs.addObserver(this, "quit-application-granted", true);
+ this._obs.addObserver(this, "private-browsing", true);
}
PrivateBrowsingService.prototype = {
// Observer Service
__obs: null,
get _obs() {
if (!this.__obs)
this.__obs = Cc["@mozilla.org/observer-service;1"].
@@ -127,101 +128,96 @@ PrivateBrowsingService.prototype = {
_unload: function PBS__destroy() {
// Force an exit from the private browsing mode on shutdown
this._quitting = true;
if (this._inPrivateBrowsing)
this.privateBrowsingEnabled = false;
},
- _onPrivateBrowsingModeChanged: function PBS__onPrivateBrowsingModeChanged() {
+ _onBeforePrivateBrowsingModeChange: function PBS__onBeforePrivateBrowsingModeChange() {
// nothing needs to be done here if we're auto-starting
if (!this._autoStart) {
- // clear all auth tokens
- let sdr = Cc["@mozilla.org/security/sdr;1"].
- getService(Ci.nsISecretDecoderRing);
- sdr.logoutAndTeardown();
-
- // clear plain HTTP auth sessions
- let authMgr = Cc['@mozilla.org/network/http-auth-manager;1'].
- getService(Ci.nsIHttpAuthManager);
- authMgr.clearAll();
-
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
- if (this.privateBrowsingEnabled) {
+
+ if (this._inPrivateBrowsing) {
// whether we should save and close the current session
this._saveSession = true;
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
try {
if (prefBranch.getBoolPref("browser.privatebrowsing.keep_current_session"))
this._saveSession = false;
} catch (ex) {}
// save the whole browser state in order to restore all windows/tabs later
- if (this._saveSession && !this._savedBrowserState) {
+ if (this._saveSession && !this._savedBrowserState)
this._savedBrowserState = ss.getBrowserState();
-
- // Close all windows
- this._closeAllWindows();
-
- // Open about:privatebrowsing
- this._openAboutPrivateBrowsing();
- }
}
- else {
- // Clear the error console
- let consoleService = Cc["@mozilla.org/consoleservice;1"].
- getService(Ci.nsIConsoleService);
- consoleService.logStringMessage(null); // trigger the listeners
- consoleService.reset();
+ if (!this.quitting && this._saveSession) {
+ // dummy session used to transition from/to pb mode, see bug 476463
+ let transitionState = {
+ "windows": [{
+ "tabs": [{
+ "entries": [{
+ "url": "about:blank"
+ }]
+ }],
+ "_closedTabs": []
+ }]
+ };
+ // load dummy session to get a distinct separation between private and
+ // non-private sessions
+ ss.setBrowserState(JSON.stringify(transitionState));
- // restore the windows/tabs which were open before entering the private mode
- if (this._saveSession && this._savedBrowserState) {
- if (!this._quitting) { // don't restore when shutting down!
- ss.setBrowserState(this._savedBrowserState);
- }
- this._savedBrowserState = null;
- }
+ let browser = Cc["@mozilla.org/appshell/window-mediator;1"].
+ getService(Ci.nsIWindowMediator).
+ getMostRecentWindow("navigator:browser").gBrowser;
+ // this ensures a clean slate from which to transition into or out of
+ // private browsing
+ browser.addTab();
+ browser.removeTab(browser.tabContainer.firstChild);
}
}
else
this._saveSession = false;
},
-#ifndef XP_WIN
-#define BROKEN_WM_Z_ORDER
-#endif
-
- _closeAllWindows: function PBS__closeAllWindows() {
- let windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
- getService(Ci.nsIWindowMediator);
-#ifdef BROKEN_WM_Z_ORDER
- let windowsEnum = windowMediator.getEnumerator("navigator:browser");
-#else
- let windowsEnum = windowMediator.getZOrderDOMWindowEnumerator("navigator:browser", false);
-#endif
-
- while (windowsEnum.hasMoreElements()) {
- let win = windowsEnum.getNext();
- win.close();
+ _onAfterPrivateBrowsingModeChange: function PBS__onAfterPrivateBrowsingModeChange() {
+ // nothing to do here if we're auto-starting or the current session is being
+ // used
+ if (!this._autoStart && this._saveSession) {
+ let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+ getService(Ci.nsISessionStore);
+ // if we have transitioned out of private browsing mode and the session is
+ // to be restored, do it now
+ if (!this._inPrivateBrowsing) {
+ ss.setBrowserState(this._savedBrowserState);
+ this._savedBrowserState = null;
+ }
+ else {
+ // otherwise, if we have transitioned into private browsing mode, load
+ // about:privatebrowsing
+ let privateBrowsingState = {
+ "windows": [{
+ "tabs": [{
+ "entries": [{
+ "url": "about:privatebrowsing"
+ }]
+ }],
+ "_closedTabs": []
+ }]
+ };
+ // Transition into private browsing mode
+ ss.setBrowserState(JSON.stringify(privateBrowsingState));
+ }
}
},