зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to tracemonkey.
This commit is contained in:
Коммит
2edd3c3ca6
26
Makefile.in
26
Makefile.in
|
@ -176,33 +176,37 @@ 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)
|
||||
|
|
|
@ -81,7 +81,6 @@ CPPSRCS = \
|
|||
nsAccessibilityAtoms.cpp \
|
||||
nsCoreUtils.cpp \
|
||||
nsAccUtils.cpp \
|
||||
nsNameUtils.cpp \
|
||||
nsRelUtils.cpp \
|
||||
nsAccessibilityService.cpp \
|
||||
nsAccessible.cpp \
|
||||
|
@ -93,7 +92,8 @@ CPPSRCS = \
|
|||
nsApplicationAccessible.cpp \
|
||||
nsCaretAccessible.cpp \
|
||||
nsTextAccessible.cpp \
|
||||
nsTextUtils.cpp \
|
||||
nsTextEquivUtils.cpp \
|
||||
nsTextAttrs.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
|
|
|
@ -65,6 +65,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_ALERT,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -73,6 +74,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_DIALOG,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -81,6 +83,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_APPLICATION,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -89,7 +92,8 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_DOCUMENT,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
kNoReqStates,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_READONLY,
|
||||
kEndEntry
|
||||
},
|
||||
{
|
||||
|
@ -97,9 +101,10 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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
|
||||
},
|
||||
{
|
||||
|
@ -107,6 +112,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_CHECKBUTTON,
|
||||
eNoValue,
|
||||
eCheckUncheckAction,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_CHECKABLE,
|
||||
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
|
||||
{&nsAccessibilityAtoms::aria_checked, "mixed", nsIAccessibleStates::STATE_MIXED},
|
||||
|
@ -118,6 +124,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_COLUMNHEADER,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
|
||||
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
|
||||
|
@ -129,6 +136,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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},
|
||||
|
@ -139,6 +147,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_DIALOG,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -147,7 +156,8 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_DOCUMENT,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
kNoReqStates,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_READONLY,
|
||||
kEndEntry
|
||||
},
|
||||
{
|
||||
|
@ -155,6 +165,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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},
|
||||
|
@ -165,6 +176,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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},
|
||||
|
@ -176,6 +188,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_GROUPING,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -184,6 +197,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_HEADING,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -192,6 +206,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_GRAPHIC,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -200,6 +215,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_LABEL,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -208,6 +224,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_LINK,
|
||||
eNoValue,
|
||||
eJumpAction,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_LINKED,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -216,6 +233,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_LIST,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_READONLY,
|
||||
{&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
|
||||
kEndEntry
|
||||
|
@ -225,6 +243,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_LISTBOX,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
|
||||
{&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
|
||||
|
@ -235,6 +254,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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},
|
||||
|
@ -243,11 +263,30 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
{&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
|
||||
},
|
||||
|
@ -257,6 +296,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
eNoValue,
|
||||
eNoAction, // XXX: technically accessibles of menupopup role haven't
|
||||
// any action, but menu can be open or close.
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -265,6 +305,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_MENUBAR,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -273,6 +314,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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},
|
||||
|
@ -284,6 +326,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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},
|
||||
|
@ -294,6 +337,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_RADIO_MENU_ITEM,
|
||||
eNoValue,
|
||||
eClickAction,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_CHECKABLE,
|
||||
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED },
|
||||
kEndEntry
|
||||
|
@ -303,6 +347,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_OPTION,
|
||||
eNoValue,
|
||||
eSelectAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
|
||||
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
|
||||
|
@ -316,6 +361,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_NOTHING,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -324,6 +370,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_PROGRESSBAR,
|
||||
eHasValueMinMax,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_READONLY,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -332,7 +379,8 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_RADIOBUTTON,
|
||||
eNoValue,
|
||||
eSelectAction,
|
||||
kNoReqStates,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_CHECKABLE,
|
||||
{&nsAccessibilityAtoms::aria_checked, kBoolState, nsIAccessibleStates::STATE_CHECKED},
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -341,6 +389,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_GROUPING,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -349,6 +398,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_PANE,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -357,6 +407,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_ROW,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
|
||||
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
|
||||
|
@ -367,6 +418,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_ROWHEADER,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_selected, kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
|
||||
{&nsAccessibilityAtoms::aria_selected, "false", nsIAccessibleStates::STATE_SELECTABLE},
|
||||
|
@ -378,6 +430,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_SECTION,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -386,6 +439,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_SEPARATOR,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -394,6 +448,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_SLIDER,
|
||||
eHasValueMinMax,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
|
||||
kEndEntry
|
||||
|
@ -403,6 +458,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_SPINBUTTON,
|
||||
eHasValueMinMax,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
|
||||
kEndEntry
|
||||
|
@ -412,6 +468,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_STATUSBAR,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
ePoliteLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -420,6 +477,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_PAGETAB,
|
||||
eNoValue,
|
||||
eSwitchAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -428,6 +486,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_PAGETABLIST,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
ePoliteLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -436,6 +495,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_PROPERTYPAGE,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -444,6 +504,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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
|
||||
|
@ -452,11 +513,21 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
{&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
|
||||
},
|
||||
|
@ -465,6 +536,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_TOOLTIP,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -473,6 +545,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_OUTLINE,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_readonly, kBoolState, nsIAccessibleStates::STATE_READONLY},
|
||||
{&nsAccessibilityAtoms::aria_multiselectable, kBoolState, nsIAccessibleStates::STATE_MULTISELECTABLE | nsIAccessibleStates::STATE_EXTSELECTABLE},
|
||||
|
@ -483,6 +556,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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},
|
||||
|
@ -494,13 +568,15 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
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);
|
||||
|
@ -510,6 +586,7 @@ nsRoleMapEntry nsARIAMap::gLandmarkRoleMap = {
|
|||
nsIAccessibleRole::ROLE_NOTHING,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
};
|
||||
|
@ -519,6 +596,7 @@ nsRoleMapEntry nsARIAMap::gEmptyRoleMap = {
|
|||
nsIAccessibleRole::ROLE_NOTHING,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
kEndEntry
|
||||
};
|
||||
|
@ -540,3 +618,41 @@ nsStateMapEntry nsARIAMap::gWAIUnivStateMap[] = {
|
|||
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);
|
||||
|
|
|
@ -63,6 +63,28 @@ enum EActionRule
|
|||
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
|
||||
|
||||
|
@ -78,6 +100,13 @@ struct nsStateMapEntry
|
|||
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
|
||||
{
|
||||
|
@ -93,6 +122,10 @@ struct nsRoleMapEntry
|
|||
// 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.
|
||||
|
||||
|
@ -142,6 +175,12 @@ struct nsARIAMap
|
|||
* the role.
|
||||
*/
|
||||
static nsStateMapEntry gWAIUnivStateMap[];
|
||||
|
||||
/**
|
||||
* Map of attribute to attribute characteristics.
|
||||
*/
|
||||
static nsAttributeCharacteristics gWAIUnivAttrMap[];
|
||||
static PRUint32 gWAIUnivAttrMapLength;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -272,21 +272,38 @@ nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
|
|||
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))
|
||||
|
@ -301,33 +318,6 @@ nsAccUtils::SetLiveContainerAttributes(nsIPersistentProperties *aAttributes,
|
|||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -686,6 +676,28 @@ nsAccUtils::GetRoleMapEntry(nsIDOMNode *aNode)
|
|||
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
|
||||
|
||||
|
|
|
@ -130,12 +130,6 @@ public:
|
|||
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
|
||||
|
@ -267,6 +261,21 @@ public:
|
|||
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.
|
||||
*/
|
||||
|
|
|
@ -188,15 +188,23 @@ 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
|
||||
|
@ -249,6 +257,7 @@ 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")
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include "nsAccessible.h"
|
||||
#include "nsAccessibleRelation.h"
|
||||
#include "nsHyperTextAccessibleWrap.h"
|
||||
#include "nsNameUtils.h"
|
||||
|
||||
#include "nsIAccessibleDocument.h"
|
||||
#include "nsIAccessibleHyperText.h"
|
||||
|
@ -329,7 +328,9 @@ NS_IMETHODIMP nsAccessible::GetDescription(nsAString& aDescription)
|
|||
}
|
||||
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) {
|
||||
|
@ -341,7 +342,8 @@ NS_IMETHODIMP nsAccessible::GetDescription(nsAString& aDescription)
|
|||
|
||||
if (descriptionContent) {
|
||||
// We have a description content node
|
||||
AppendFlatStringFromSubtree(descriptionContent, &description);
|
||||
nsTextEquivUtils::
|
||||
AppendTextEquivFromContent(this, descriptionContent, &description);
|
||||
}
|
||||
}
|
||||
if (description.IsEmpty()) {
|
||||
|
@ -1456,284 +1458,6 @@ nsAccessible::TakeFocus()
|
|||
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)
|
||||
{
|
||||
|
@ -1746,7 +1470,8 @@ nsAccessible::GetHTMLName(nsAString& aLabel)
|
|||
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();
|
||||
|
@ -1756,20 +1481,7 @@ nsAccessible::GetHTMLName(nsAString& aLabel)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1829,7 +1541,7 @@ nsAccessible::GetXULName(nsAString& aLabel)
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1854,12 +1566,7 @@ nsAccessible::GetXULName(nsAString& aLabel)
|
|||
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
|
||||
|
@ -1926,7 +1633,8 @@ NS_IMETHODIMP nsAccessible::GetFinalRole(PRUint32 *aRole)
|
|||
// 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.
|
||||
|
@ -1983,36 +1691,20 @@ nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
|
|||
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);
|
||||
|
@ -2022,8 +1714,12 @@ nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
|
|||
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);
|
||||
|
@ -2031,6 +1727,17 @@ nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
|
|||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -2330,7 +2037,11 @@ nsAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
|||
*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;
|
||||
}
|
||||
|
||||
|
@ -2349,7 +2060,8 @@ nsAccessible::GetARIAState(PRUint32 *aState)
|
|||
}
|
||||
|
||||
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())) {
|
||||
|
@ -2381,6 +2093,7 @@ nsAccessible::GetARIAState(PRUint32 *aState)
|
|||
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) &&
|
||||
|
@ -3368,14 +3081,18 @@ nsAccessible::GetARIAName(nsAString& aName)
|
|||
// 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;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
|
||||
#include "nsAccessNodeWrap.h"
|
||||
|
||||
#include "nsARIAMap.h"
|
||||
#include "nsRelUtils.h"
|
||||
#include "nsTextEquivUtils.h"
|
||||
|
||||
#include "nsIAccessible.h"
|
||||
#include "nsPIAccessible.h"
|
||||
#include "nsIAccessibleHyperLink.h"
|
||||
|
@ -50,15 +54,12 @@
|
|||
#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;
|
||||
|
@ -181,18 +182,6 @@ protected:
|
|||
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.
|
||||
|
||||
|
@ -206,14 +195,6 @@ protected:
|
|||
*/
|
||||
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);
|
||||
|
|
|
@ -344,7 +344,7 @@ nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
|
|||
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
|
||||
|
|
|
@ -263,7 +263,9 @@ nsDocAccessible::GetDescription(nsAString& aDescription)
|
|||
|
||||
if (aDescription.IsEmpty()) {
|
||||
nsAutoString description;
|
||||
GetTextFromRelationID(nsAccessibilityAtoms::aria_describedby, description);
|
||||
nsTextEquivUtils::
|
||||
GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
|
||||
description);
|
||||
aDescription = description;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,169 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=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) 2008
|
||||
* 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 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 "nsNameUtils.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Name rules to role map.
|
||||
|
||||
PRUint32 nsNameUtils::gRoleToNameRulesMap[] =
|
||||
{
|
||||
eNoRule, // ROLE_NOTHING
|
||||
eNoRule, // ROLE_TITLEBAR
|
||||
eNoRule, // ROLE_MENUBAR
|
||||
eNoRule, // ROLE_SCROLLBAR
|
||||
eNoRule, // ROLE_GRIP
|
||||
eNoRule, // ROLE_SOUND
|
||||
eNoRule, // ROLE_CURSOR
|
||||
eNoRule, // ROLE_CARET
|
||||
eNoRule, // ROLE_ALERT
|
||||
eNoRule, // ROLE_WINDOW
|
||||
eNoRule, // ROLE_INTERNAL_FRAME
|
||||
eNoRule, // ROLE_MENUPOPUP
|
||||
eFromSubtree, // ROLE_MENUITEM
|
||||
eFromSubtree, // ROLE_TOOLTIP
|
||||
eNoRule, // ROLE_APPLICATION
|
||||
eNoRule, // ROLE_DOCUMENT
|
||||
eNoRule, // ROLE_PANE
|
||||
eNoRule, // ROLE_CHART
|
||||
eNoRule, // ROLE_DIALOG
|
||||
eNoRule, // ROLE_BORDER
|
||||
eNoRule, // ROLE_GROUPING
|
||||
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
|
||||
eFromSubtree, // ROLE_LINK
|
||||
eFromSubtree, // ROLE_HELPBALLOON
|
||||
eNoRule, // ROLE_CHARACTER
|
||||
eNoRule, // 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
|
||||
eNoRule, // ROLE_DROPLIST
|
||||
eNoRule, // 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
|
||||
eFromSubtree, // ROLE_BUTTONMENU
|
||||
eFromSubtree, // ROLE_BUTTONDROPDOWNGRID
|
||||
eNoRule, // ROLE_WHITESPACE
|
||||
eNoRule, // ROLE_PAGETABLIST
|
||||
eNoRule, // ROLE_CLOCK
|
||||
eNoRule, // ROLE_SPLITBUTTON
|
||||
eNoRule, // ROLE_IPADDRESS
|
||||
eNoRule, // ROLE_ACCEL_LABEL
|
||||
eNoRule, // ROLE_ARROW
|
||||
eNoRule, // ROLE_CANVAS
|
||||
eFromSubtree, // ROLE_CHECK_MENU_ITEM
|
||||
eNoRule, // ROLE_COLOR_CHOOSER
|
||||
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
|
||||
eNoRule, // ROLE_ICON
|
||||
eNoRule, // 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
|
||||
eFromSubtree, // ROLE_TOGGLE_BUTTON
|
||||
eNoRule, // ROLE_TREE_TABLE
|
||||
eNoRule, // ROLE_VIEWPORT
|
||||
eNoRule, // ROLE_HEADER
|
||||
eNoRule, // ROLE_FOOTER
|
||||
eNoRule, // ROLE_PARAGRAPH
|
||||
eNoRule, // ROLE_RULER
|
||||
eNoRule, // ROLE_AUTOCOMPLETE
|
||||
eNoRule, // ROLE_EDITBAR
|
||||
eNoRule, // ROLE_ENTRY
|
||||
eNoRule, // ROLE_CAPTION
|
||||
eNoRule, // ROLE_DOCUMENT_FRAME
|
||||
eNoRule, // ROLE_HEADING
|
||||
eNoRule, // ROLE_PAGE
|
||||
eNoRule, // 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
|
||||
eNoRule, // ROLE_IMAGE_MAP
|
||||
eFromSubtree, // ROLE_OPTION
|
||||
eFromSubtree, // ROLE_RICH_OPTION
|
||||
eNoRule, // ROLE_LISTBOX
|
||||
eNoRule, // ROLE_FLAT_EQUATION
|
||||
eFromSubtree // ROLE_GRID_CELL
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,508 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=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) 2008
|
||||
* 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 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 "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 nsTextEquivUtils::gRoleToNameRulesMap[] =
|
||||
{
|
||||
eNoRule, // ROLE_NOTHING
|
||||
eNoRule, // ROLE_TITLEBAR
|
||||
eNoRule, // ROLE_MENUBAR
|
||||
eNoRule, // ROLE_SCROLLBAR
|
||||
eNoRule, // ROLE_GRIP
|
||||
eNoRule, // ROLE_SOUND
|
||||
eNoRule, // ROLE_CURSOR
|
||||
eNoRule, // ROLE_CARET
|
||||
eNoRule, // ROLE_ALERT
|
||||
eNoRule, // ROLE_WINDOW
|
||||
eNoRule, // ROLE_INTERNAL_FRAME
|
||||
eNoRule, // ROLE_MENUPOPUP
|
||||
eFromSubtree, // ROLE_MENUITEM
|
||||
eFromSubtree, // ROLE_TOOLTIP
|
||||
eNoRule, // ROLE_APPLICATION
|
||||
eNoRule, // ROLE_DOCUMENT
|
||||
eNoRule, // ROLE_PANE
|
||||
eNoRule, // ROLE_CHART
|
||||
eNoRule, // ROLE_DIALOG
|
||||
eNoRule, // ROLE_BORDER
|
||||
eNoRule, // ROLE_GROUPING
|
||||
eNoRule, // ROLE_SEPARATOR
|
||||
eNoRule, // ROLE_TOOLBAR
|
||||
eNoRule, // ROLE_STATUSBAR
|
||||
eNoRule, // ROLE_TABLE
|
||||
eFromSubtree, // ROLE_COLUMNHEADER
|
||||
eFromSubtree, // ROLE_ROWHEADER
|
||||
eFromSubtree, // ROLE_COLUMN
|
||||
eFromSubtree, // ROLE_ROW
|
||||
eFromSubtreeIfRec, // ROLE_CELL
|
||||
eFromSubtree, // ROLE_LINK
|
||||
eFromSubtree, // ROLE_HELPBALLOON
|
||||
eNoRule, // ROLE_CHARACTER
|
||||
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
|
||||
eFromValue, // ROLE_COMBOBOX
|
||||
eNoRule, // ROLE_DROPLIST
|
||||
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
|
||||
eFromSubtree, // ROLE_BUTTONMENU
|
||||
eFromSubtree, // ROLE_BUTTONDROPDOWNGRID
|
||||
eNoRule, // ROLE_WHITESPACE
|
||||
eNoRule, // ROLE_PAGETABLIST
|
||||
eNoRule, // ROLE_CLOCK
|
||||
eNoRule, // ROLE_SPLITBUTTON
|
||||
eNoRule, // ROLE_IPADDRESS
|
||||
eNoRule, // ROLE_ACCEL_LABEL
|
||||
eNoRule, // ROLE_ARROW
|
||||
eNoRule, // ROLE_CANVAS
|
||||
eFromSubtree, // ROLE_CHECK_MENU_ITEM
|
||||
eNoRule, // ROLE_COLOR_CHOOSER
|
||||
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
|
||||
eFromSubtreeIfRec, // ROLE_HTML_CONTAINER
|
||||
eNoRule, // ROLE_ICON
|
||||
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
|
||||
eFromSubtreeIfRec, // ROLE_TEXT_CONTAINER
|
||||
eFromSubtree, // ROLE_TOGGLE_BUTTON
|
||||
eNoRule, // ROLE_TREE_TABLE
|
||||
eNoRule, // ROLE_VIEWPORT
|
||||
eNoRule, // ROLE_HEADER
|
||||
eNoRule, // ROLE_FOOTER
|
||||
eFromSubtreeIfRec, // ROLE_PARAGRAPH
|
||||
eNoRule, // ROLE_RULER
|
||||
eNoRule, // ROLE_AUTOCOMPLETE
|
||||
eNoRule, // ROLE_EDITBAR
|
||||
eFromValue, // ROLE_ENTRY
|
||||
eNoRule, // ROLE_CAPTION
|
||||
eNoRule, // ROLE_DOCUMENT_FRAME
|
||||
eNoRule, // ROLE_HEADING
|
||||
eNoRule, // ROLE_PAGE
|
||||
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
|
||||
eNoRule, // ROLE_IMAGE_MAP
|
||||
eFromSubtree, // ROLE_OPTION
|
||||
eFromSubtree, // ROLE_RICH_OPTION
|
||||
eNoRule, // ROLE_LISTBOX
|
||||
eNoRule, // ROLE_FLAT_EQUATION
|
||||
eFromSubtree // ROLE_GRID_CELL
|
||||
};
|
|
@ -0,0 +1,168 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=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) 2008
|
||||
* 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 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 _nsTextEquivUtils_H_
|
||||
#define _nsTextEquivUtils_H_
|
||||
|
||||
#include "nsIAccessible.h"
|
||||
|
||||
#include "nsIContent.h"
|
||||
#include "nsIStringBundle.h"
|
||||
|
||||
/**
|
||||
* Text equivalent computation rules (see nsTextEquivUtils::gRoleToNameRulesMap)
|
||||
*/
|
||||
enum ETextEquivRule
|
||||
{
|
||||
// No rule.
|
||||
eNoRule = 0x00,
|
||||
|
||||
// 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 nsTextEquivUtils
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* 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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -627,7 +627,8 @@ nsHTMLGroupboxAccessible::GetNameInternal(nsAString& aName)
|
|||
|
||||
nsIContent *legendContent = GetLegend();
|
||||
if (legendContent) {
|
||||
return AppendFlatStringFromSubtree(legendContent, &aName);
|
||||
return nsTextEquivUtils::
|
||||
AppendTextEquivFromContent(this, legendContent, &aName);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -526,7 +526,8 @@ nsHTMLSelectOptionAccessible::GetNameInternal(nsAString& aName)
|
|||
|
||||
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
|
||||
|
|
|
@ -967,7 +967,8 @@ NS_IMETHODIMP nsHTMLTableAccessible::GetDescription(nsAString& aDescription)
|
|||
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
|
||||
|
|
|
@ -169,22 +169,9 @@ 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)
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include "nsAccessibilityAtoms.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "nsAccessibleTreeWalker.h"
|
||||
#include "nsTextUtils.h"
|
||||
#include "nsTextAttrs.h"
|
||||
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsContentCID.h"
|
||||
|
@ -1174,17 +1174,8 @@ nsHyperTextAccessible::GetTextAttributes(PRBool aIncludeDefAttrs,
|
|||
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
|
||||
|
@ -1204,35 +1195,8 @@ nsHyperTextAccessible::GetDefaultTextAttributes(nsIPersistentProperties **aAttri
|
|||
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
|
||||
|
@ -2320,275 +2284,3 @@ nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode,
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include "nsIAccessibleHyperText.h"
|
||||
#include "nsIAccessibleEditableText.h"
|
||||
#include "nsAccessibleEventData.h"
|
||||
#include "nsTextUtils.h"
|
||||
#include "nsTextAttrs.h"
|
||||
|
||||
#include "nsFrameSelection.h"
|
||||
#include "nsISelectionController.h"
|
||||
|
@ -293,88 +293,6 @@ protected:
|
|||
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,
|
||||
|
|
|
@ -234,7 +234,9 @@ 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;
|
||||
|
|
|
@ -66,7 +66,9 @@ 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;
|
||||
}
|
||||
|
|
|
@ -61,8 +61,6 @@ public:
|
|||
|
||||
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
|
||||
|
|
|
@ -165,12 +165,15 @@ nsXULLinkAccessible::GetValue(nsAString& aValue)
|
|||
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
|
||||
|
|
|
@ -78,12 +78,10 @@ _TEST_FILES =\
|
|||
$(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 \
|
||||
|
@ -99,17 +97,26 @@ _TEST_FILES =\
|
|||
$(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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,6 +178,9 @@ function getNode(aNodeOrID)
|
|||
*/
|
||||
function getAccessible(aAccOrElmOrID, aInterfaces, aElmObj, aDoNotFailIfNoAcc)
|
||||
{
|
||||
if (!aAccOrElmOrID)
|
||||
return;
|
||||
|
||||
var elm = null;
|
||||
|
||||
if (aAccOrElmOrID instanceof nsIAccessible) {
|
||||
|
@ -246,6 +249,27 @@ 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.
|
||||
*/
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Constants
|
||||
|
||||
const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
|
||||
const EVENT_DOM_DESTROY = nsIAccessibleEvent.EVENT_DOM_DESTROY;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// General
|
||||
|
||||
|
@ -6,6 +12,38 @@
|
|||
*/
|
||||
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.
|
||||
*
|
||||
|
@ -386,6 +424,9 @@ function removeA11yEventListener(aEventType, aEventHandler)
|
|||
|
||||
function dumpInfoToDOM(aInfo)
|
||||
{
|
||||
if (!gA11yEventDumpID)
|
||||
return;
|
||||
|
||||
var dumpElm = document.getElementById(gA11yEventDumpID);
|
||||
var div = document.createElement("div");
|
||||
div.textContent = aInfo;
|
||||
|
|
|
@ -119,6 +119,7 @@
|
|||
<rule fromsubtree="true"/>
|
||||
<rule attr="title" type="string"/>
|
||||
</ruleset>
|
||||
|
||||
</ruledfn>
|
||||
|
||||
<rulesample>
|
||||
|
@ -193,12 +194,13 @@
|
|||
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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -55,11 +55,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
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");
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<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"
|
||||
|
@ -10,19 +10,16 @@
|
|||
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>
|
||||
|
@ -31,7 +28,7 @@
|
|||
|
||||
<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>
|
||||
|
@ -39,6 +36,6 @@
|
|||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
|
||||
<div id="eventdump"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -35,6 +35,10 @@
|
|||
// 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).
|
||||
|
@ -129,10 +133,21 @@
|
|||
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();
|
||||
}
|
||||
|
||||
|
@ -175,6 +190,12 @@
|
|||
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"
|
||||
|
@ -286,16 +307,39 @@
|
|||
</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>
|
||||
|
|
|
@ -40,6 +40,10 @@
|
|||
// 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).
|
||||
|
@ -101,7 +105,7 @@
|
|||
// 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",
|
||||
|
@ -111,7 +115,7 @@
|
|||
// 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",
|
||||
|
@ -195,6 +199,14 @@
|
|||
<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>
|
||||
|
|
|
@ -47,8 +47,8 @@
|
|||
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
|
||||
];
|
||||
|
|
|
@ -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>
|
|
@ -2,9 +2,10 @@
|
|||
<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"
|
||||
|
@ -20,10 +21,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=454997
|
|||
<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();
|
||||
}
|
||||
|
@ -33,16 +46,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=454997
|
|||
</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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -66,10 +66,10 @@
|
|||
"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);
|
||||
|
@ -101,15 +101,15 @@
|
|||
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
|
||||
|
@ -129,26 +129,26 @@
|
|||
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
|
||||
|
@ -170,23 +170,23 @@
|
|||
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
|
||||
|
@ -208,17 +208,17 @@
|
|||
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
|
||||
|
@ -240,18 +240,18 @@
|
|||
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)
|
||||
|
@ -271,44 +271,165 @@
|
|||
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",
|
||||
|
@ -321,45 +442,53 @@
|
|||
|
||||
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);
|
||||
|
||||
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 = {"language": "en" };
|
||||
testTextAttrs(ID, 26, attrs, 26, 27);
|
||||
|
||||
attrs = {"language": "de"};
|
||||
testTextAttrs(ID, 27, attrs, 27, 42);
|
||||
|
||||
attrs = {"language": "en"};
|
||||
testTextAttrs(ID, 42, attrs, 42, 43);
|
||||
attrs = { "font-size": "14pt" };
|
||||
testTextAttrs(ID, 7, attrs, defAttrs, 7, 13);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 43, attrs, 43, 50);
|
||||
testTextAttrs(ID, 13, attrs, defAttrs, 13, 22);
|
||||
|
||||
tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
|
||||
// Walk to the span with the different background color
|
||||
tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
|
||||
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
|
||||
attrs = {"color": gComputedStyle.color};
|
||||
testTextAttrs(ID, 50, attrs, 50, 57);
|
||||
attrs = { "background-color": gComputedStyle.backgroundColor };
|
||||
testTextAttrs(ID, 23, attrs, defAttrs, 22, 37);
|
||||
|
||||
tempElem = tempElem.firstChild.nextSibling;
|
||||
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
|
||||
attrs = {"font-weight": gComputedStyle.fontWeight,
|
||||
"color": gComputedStyle.color};
|
||||
testTextAttrs(ID, 57, attrs, 57, 61);
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 38, attrs, defAttrs, 37, 45);
|
||||
|
||||
tempElem = tempElem.parentNode;
|
||||
// Walk from the background color span to the one with font-style
|
||||
tempElem = tempElem.nextSibling.nextSibling;
|
||||
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
|
||||
attrs = {"color": gComputedStyle.color};
|
||||
testTextAttrs(ID, 61, attrs, 61, 68);
|
||||
attrs = {"font-style": gComputedStyle.fontStyle};
|
||||
testTextAttrs(ID, 46, attrs, defAttrs, 45, 62);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 63, attrs, defAttrs, 62, 70);
|
||||
|
||||
// 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, 71, attrs, defAttrs, 70, 84);
|
||||
|
||||
attrs = {};
|
||||
testTextAttrs(ID, 85, attrs, defAttrs, 84, 92);
|
||||
|
||||
attrs = { "text-underline-style": "solid" };
|
||||
testTextAttrs(ID, 93, attrs, defAttrs, 92, 102);
|
||||
|
||||
attrs = {};
|
||||
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
|
||||
|
@ -425,6 +554,22 @@
|
|||
|
||||
<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>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<!--
|
||||
Auxilliary file used as frame source.
|
||||
-->
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<p>Frame source body has no role</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<!--
|
||||
Auxilliary file used as frame source.
|
||||
-->
|
||||
<head>
|
||||
</head>
|
||||
<body role="article">
|
||||
<p>Article</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<!--
|
||||
Auxilliary file used as frame source.
|
||||
-->
|
||||
<head>
|
||||
</head>
|
||||
<body role="checkbox">
|
||||
<p>Checkbox</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<!--
|
||||
Auxilliary file used as frame source.
|
||||
-->
|
||||
<head>
|
||||
</head>
|
||||
<body role="textbox">
|
||||
<p>Texbox</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -3,6 +3,9 @@ pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERS
|
|||
// 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%/");
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
# 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
|
||||
|
@ -54,9 +55,15 @@ 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
|
||||
|
|
|
@ -1155,6 +1155,10 @@ function prepareForStartup() {
|
|||
// 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);
|
||||
}
|
||||
|
@ -2903,6 +2907,9 @@ const BrowserSearch = {
|
|||
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) {
|
||||
|
@ -2914,8 +2921,8 @@ const BrowserSearch = {
|
|||
// 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
|
||||
|
@ -3872,10 +3879,6 @@ var XULBrowserWindow = {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4909,7 +4912,7 @@ var contentAreaDNDObserver = {
|
|||
|
||||
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" &&
|
||||
|
@ -4958,7 +4961,7 @@ var contentAreaDNDObserver = {
|
|||
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");
|
||||
|
@ -5331,6 +5334,12 @@ var OfflineApps = {
|
|||
obs.removeObserver(this, "offline-cache-update-completed");
|
||||
},
|
||||
|
||||
handleEvent: function(event) {
|
||||
if (event.type == "MozApplicationManifest") {
|
||||
this.offlineAppRequested(event.originalTarget.defaultView);
|
||||
}
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// OfflineApps Implementation Methods
|
||||
|
||||
|
@ -5357,6 +5366,7 @@ var OfflineApps = {
|
|||
},
|
||||
|
||||
_getManifestURI: function(aWindow) {
|
||||
if (!aWindow.document.documentElement) return null;
|
||||
var attr = aWindow.document.documentElement.getAttribute("manifest");
|
||||
if (!attr) return null;
|
||||
|
||||
|
@ -5426,10 +5436,25 @@ var OfflineApps = {
|
|||
},
|
||||
|
||||
// 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);
|
||||
|
@ -5463,7 +5488,7 @@ var OfflineApps = {
|
|||
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);
|
||||
|
||||
|
@ -5481,19 +5506,32 @@ var OfflineApps = {
|
|||
// 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"),
|
||||
|
@ -5502,51 +5540,55 @@ var OfflineApps = {
|
|||
|
||||
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);
|
||||
pm.add(aDocument.documentURIObject, "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();
|
||||
// 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);
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -6090,7 +6132,7 @@ var FeedHandler = {
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
@ -6100,7 +6142,7 @@ var FeedHandler = {
|
|||
|
||||
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;
|
||||
|
@ -6868,6 +6910,8 @@ let gPrivateBrowsingUI = {
|
|||
onEnterPrivateBrowsing: function PBUI_onEnterPrivateBrowsing() {
|
||||
this._setPBMenuTitle("stop");
|
||||
|
||||
document.getElementById("menu_import").setAttribute("disabled", "true");
|
||||
|
||||
this._privateBrowsingAutoStarted = this._privateBrowsingService.autoStarted;
|
||||
|
||||
if (!this._privateBrowsingAutoStarted) {
|
||||
|
@ -6893,6 +6937,8 @@ let gPrivateBrowsingUI = {
|
|||
if (BrowserSearch.searchBar)
|
||||
BrowserSearch.searchBar.textbox.reset();
|
||||
|
||||
document.getElementById("menu_import").removeAttribute("disabled");
|
||||
|
||||
gFindBar.getElement("findbar-textbox").reset();
|
||||
|
||||
this._setPBMenuTitle("start");
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#filter substitution
|
||||
<?xml version="1.0"?>
|
||||
# -*- Mode: HTML -*-
|
||||
#
|
||||
|
@ -31,6 +32,7 @@
|
|||
# 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
|
||||
|
@ -48,10 +50,7 @@
|
|||
|
||||
<?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"?>
|
||||
|
@ -68,19 +67,19 @@
|
|||
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"
|
||||
|
|
|
@ -1712,6 +1712,7 @@
|
|||
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.
|
||||
|
@ -1911,10 +1912,13 @@
|
|||
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);
|
||||
|
@ -1946,8 +1950,8 @@
|
|||
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 ||
|
||||
|
@ -2085,7 +2089,7 @@
|
|||
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;
|
||||
|
@ -2208,7 +2212,7 @@
|
|||
// 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();
|
||||
|
@ -2824,18 +2828,59 @@
|
|||
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"
|
||||
|
@ -2865,54 +2910,6 @@
|
|||
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>
|
||||
|
||||
|
@ -2998,14 +2995,6 @@
|
|||
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>
|
||||
|
||||
|
@ -3021,9 +3010,6 @@
|
|||
this._animateTimer.cancel();
|
||||
this._animateTimer = null;
|
||||
}
|
||||
|
||||
this.mTabstrip.removeEventListener("overflow", this, false);
|
||||
this.mTabstrip.removeEventListener("underflow", this, false);
|
||||
]]>
|
||||
</destructor>
|
||||
|
||||
|
@ -3145,14 +3131,6 @@
|
|||
<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) {
|
||||
|
|
|
@ -50,6 +50,13 @@ _TEST_FILES = test_feed_discovery.html \
|
|||
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
|
||||
|
@ -89,6 +96,8 @@ _BROWSER_FILES = browser_bug321000.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)))
|
||||
|
|
|
@ -3,6 +3,10 @@ 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,
|
||||
|
@ -11,6 +15,7 @@ var gFrontProgressListener = {
|
|||
|
||||
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++;
|
||||
|
@ -18,6 +23,7 @@ var gFrontProgressListener = {
|
|||
|
||||
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++;
|
||||
|
@ -28,6 +34,7 @@ var gFrontProgressListener = {
|
|||
|
||||
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++;
|
||||
|
@ -42,6 +49,7 @@ var gAllProgressListener = {
|
|||
|
||||
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");
|
||||
|
@ -56,6 +64,7 @@ var gAllProgressListener = {
|
|||
|
||||
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");
|
||||
|
@ -69,6 +78,7 @@ var gAllProgressListener = {
|
|||
|
||||
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");
|
||||
|
@ -82,6 +92,7 @@ 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");
|
||||
|
@ -109,6 +120,7 @@ function startTests() {
|
|||
}
|
||||
|
||||
function startTest1() {
|
||||
LOG("\nTest 1");
|
||||
gBrowser.addProgressListener(gFrontProgressListener);
|
||||
gBrowser.addTabsProgressListener(gAllProgressListener);
|
||||
|
||||
|
@ -123,6 +135,7 @@ function startTest1() {
|
|||
}
|
||||
|
||||
function startTest2() {
|
||||
LOG("\nTest 2");
|
||||
gAllNotifications = [
|
||||
"onStateChange",
|
||||
"onLocationChange",
|
||||
|
@ -135,6 +148,7 @@ function startTest2() {
|
|||
}
|
||||
|
||||
function startTest3() {
|
||||
LOG("\nTest 3");
|
||||
gAllNotifications = [
|
||||
"onStateChange",
|
||||
"onLocationChange",
|
||||
|
@ -146,6 +160,7 @@ function startTest3() {
|
|||
}
|
||||
|
||||
function startTest4() {
|
||||
LOG("\nTest 4");
|
||||
gAllNotifications = [
|
||||
"onStateChange",
|
||||
"onLocationChange",
|
||||
|
@ -158,6 +173,7 @@ function startTest4() {
|
|||
}
|
||||
|
||||
function startTest5() {
|
||||
LOG("\nTest 5");
|
||||
// Switch the foreground browser
|
||||
[gForegroundBrowser, gBackgroundBrowser] = [gBackgroundBrowser, gForegroundBrowser];
|
||||
[gForegroundTab, gBackgroundTab] = [gBackgroundTab, gForegroundTab];
|
||||
|
@ -177,6 +193,7 @@ function startTest5() {
|
|||
}
|
||||
|
||||
function startTest6() {
|
||||
LOG("\nTest 6");
|
||||
gAllNotifications = [
|
||||
"onStateChange",
|
||||
"onLocationChange",
|
||||
|
@ -188,6 +205,7 @@ function startTest6() {
|
|||
}
|
||||
|
||||
function finishTest() {
|
||||
LOG("\nFinished tests from alltabslistener.js");
|
||||
gBrowser.removeProgressListener(gFrontProgressListener);
|
||||
gBrowser.removeTabsProgressListener(gAllProgressListener);
|
||||
gBrowser.removeTab(gBackgroundTab);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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">'>
|
|
@ -85,6 +85,15 @@ function test_gestureListener(evt)
|
|||
"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,
|
||||
|
@ -187,8 +196,11 @@ function test_helper2(type, direction, delta, altKey, ctrlKey, shiftKey, metaKey
|
|||
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) {
|
||||
|
@ -204,6 +216,14 @@ function test_helper2(type, direction, delta, altKey, ctrlKey, shiftKey, metaKey
|
|||
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;
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
CACHE MANIFEST
|
||||
offlineChild.html
|
|
@ -1,2 +1 @@
|
|||
Content-Type: text/cache-manifest
|
||||
Cache-Control: no-cache
|
|
@ -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>
|
|
@ -0,0 +1,2 @@
|
|||
CACHE MANIFEST
|
||||
offlineChild2.html
|
|
@ -1,2 +1 @@
|
|||
Cache-Control: no-cache
|
||||
Content-Type: text/cache-manifest
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
@ -42,6 +42,8 @@
|
|||
* for shared application glue for the Communicator suite of applications
|
||||
**/
|
||||
|
||||
var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
|
||||
|
||||
var gBidiUI = false;
|
||||
|
||||
function getBrowserURL()
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
# 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"
|
||||
|
@ -45,11 +45,3 @@
|
|||
!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.
|
||||
|
|
|
@ -3,6 +3,9 @@ pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERS
|
|||
// 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%/");
|
||||
|
|
|
@ -30,6 +30,7 @@ REQUIRES = \
|
|||
places \
|
||||
browserplaces \
|
||||
microsummaries \
|
||||
privatebrowsing \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = nsBrowserCompsCID.h
|
||||
|
@ -47,6 +48,7 @@ LOCAL_INCLUDES = \
|
|||
-I$(srcdir)/../shell/src \
|
||||
-I$(srcdir)/../feeds/src \
|
||||
-I$(srcdir)/../places/src \
|
||||
-I$(srcdir)/../privatebrowsing/src \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
|
@ -56,6 +58,7 @@ 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)))
|
||||
|
|
|
@ -97,3 +97,7 @@
|
|||
|
||||
#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 } }
|
||||
|
|
|
@ -77,6 +77,9 @@
|
|||
#include "nsAboutFeeds.h"
|
||||
#include "nsIAboutModule.h"
|
||||
|
||||
#include "nsPrivateBrowsingServiceWrapper.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsPlacesImportExportService)
|
||||
|
@ -113,6 +116,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsICabProfileMigrator)
|
|||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrivateBrowsingServiceWrapper, Init)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const nsModuleComponentInfo components[] =
|
||||
|
@ -217,9 +222,14 @@ static const nsModuleComponentInfo components[] =
|
|||
{ "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)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
# 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
|
||||
|
@ -323,7 +324,11 @@ BrowserGlue.prototype = {
|
|||
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;
|
||||
|
|
|
@ -1335,6 +1335,19 @@ var PlacesControllerDragHelper = {
|
|||
|
||||
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) {
|
||||
|
@ -1363,6 +1376,7 @@ var PlacesControllerDragHelper = {
|
|||
return true;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Determines if a node can be moved.
|
||||
*
|
||||
|
@ -1444,8 +1458,22 @@ var PlacesControllerDragHelper = {
|
|||
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;
|
||||
|
||||
|
@ -1494,10 +1522,12 @@ var PlacesControllerDragHelper = {
|
|||
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],
|
||||
|
||||
/**
|
||||
|
|
|
@ -417,6 +417,9 @@ var PlacesOrganizer = {
|
|||
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)
|
||||
|
@ -429,13 +432,17 @@ var PlacesOrganizer = {
|
|||
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)
|
||||
|
@ -446,12 +453,13 @@ var PlacesOrganizer = {
|
|||
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);");
|
||||
}
|
||||
|
@ -1502,7 +1510,6 @@ var PlacesQueryBuilder = {
|
|||
switch (id) {
|
||||
case "scopeBarHistory":
|
||||
PlacesSearchBox.filterCollection = "history";
|
||||
folders = [];
|
||||
break;
|
||||
case "scopeBarFolder":
|
||||
var selectedFolder = PlacesOrganizer._places.selectedNode.itemId;
|
||||
|
@ -1510,7 +1517,8 @@ var PlacesQueryBuilder = {
|
|||
// 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
|
||||
|
|
|
@ -386,8 +386,9 @@ var PlacesUIUtils = {
|
|||
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);
|
||||
|
|
|
@ -37,6 +37,14 @@
|
|||
|
||||
// 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'].
|
||||
|
@ -49,14 +57,6 @@ 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();
|
||||
|
|
|
@ -212,6 +212,8 @@ tests.push({
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
function finish_test() {
|
||||
// Simulate application closing to remove the idle observer and avoid leaks.
|
||||
os.notifyObservers(null, "quit-application-granted", null);
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
|
@ -220,6 +222,9 @@ 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);
|
||||
|
|
|
@ -216,10 +216,24 @@ var gAdvancedPane = {
|
|||
},
|
||||
|
||||
// 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);
|
||||
|
@ -241,6 +255,10 @@ var gAdvancedPane = {
|
|||
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;
|
||||
|
@ -254,7 +272,7 @@ var gAdvancedPane = {
|
|||
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));
|
||||
|
@ -295,14 +313,18 @@ var gAdvancedPane = {
|
|||
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.
|
||||
|
|
|
@ -553,7 +553,7 @@ var gCookiesWindow = {
|
|||
date.getMinutes(),
|
||||
date.getSeconds());
|
||||
}
|
||||
return this._bundle.getString("AtEndOfSession");
|
||||
return this._bundle.getString("expireAtEndOfSession");
|
||||
},
|
||||
|
||||
_updateCookieData: function (aItem)
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
<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>
|
||||
|
|
|
@ -42,6 +42,28 @@ 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 \
|
||||
|
|
|
@ -80,6 +80,7 @@ const Cr = Components.results;
|
|||
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 = {
|
||||
|
@ -132,22 +133,13 @@ PrivateBrowsingService.prototype = {
|
|||
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"].
|
||||
|
@ -158,65 +150,69 @@ PrivateBrowsingService.prototype = {
|
|||
} 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));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_openAboutPrivateBrowsing: function PBS__openAboutPrivateBrowsing() {
|
||||
let windowWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Ci.nsIWindowWatcher);
|
||||
let url = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
url.data = "about:privatebrowsing";
|
||||
windowWatcher.openWindow(null, "chrome://browser/content/browser.xul",
|
||||
null, "chrome,all,resizable=yes,dialog=no", url);
|
||||
},
|
||||
|
||||
_canEnterPrivateBrowsingMode: function PBS__canEnterPrivateBrowsingMode() {
|
||||
let cancelEnter = Cc["@mozilla.org/supports-PRBool;1"].
|
||||
createInstance(Ci.nsISupportsPRBool);
|
||||
|
@ -255,6 +251,25 @@ PrivateBrowsingService.prototype = {
|
|||
case "quit-application-granted":
|
||||
this._unload();
|
||||
break;
|
||||
case "private-browsing":
|
||||
// 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();
|
||||
|
||||
if (!this._inPrivateBrowsing) {
|
||||
// Clear the error console
|
||||
let consoleService = Cc["@mozilla.org/consoleservice;1"].
|
||||
getService(Ci.nsIConsoleService);
|
||||
consoleService.logStringMessage(null); // trigger the listeners
|
||||
consoleService.reset();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -301,9 +316,17 @@ PrivateBrowsingService.prototype = {
|
|||
let quitting = Cc["@mozilla.org/supports-PRBool;1"].
|
||||
createInstance(Ci.nsISupportsPRBool);
|
||||
quitting.data = this._quitting;
|
||||
|
||||
// notify observers of the pending private browsing mode change
|
||||
this._obs.notifyObservers(quitting, "private-browsing-change-granted", data);
|
||||
|
||||
// destroy the current session and start initial cleanup
|
||||
this._onBeforePrivateBrowsingModeChange();
|
||||
|
||||
this._obs.notifyObservers(quitting, "private-browsing", data);
|
||||
|
||||
this._onPrivateBrowsingModeChanged();
|
||||
// load the appropriate session
|
||||
this._onAfterPrivateBrowsingModeChange();
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError("Exception thrown while processing the " +
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/* ***** 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 Private Browsing.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsPrivateBrowsingServiceWrapper.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
|
||||
class JSStackGuard
|
||||
{
|
||||
public:
|
||||
JSStackGuard();
|
||||
~JSStackGuard();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIJSContextStack> mJSStack;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS2(nsPrivateBrowsingServiceWrapper, nsIPrivateBrowsingService, nsIObserver)
|
||||
|
||||
nsresult
|
||||
nsPrivateBrowsingServiceWrapper::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
mPBService = do_GetService("@mozilla.org/privatebrowsing;1", &rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
JSStackGuard::JSStackGuard()
|
||||
: mJSStack(nsnull)
|
||||
{
|
||||
nsresult rv;
|
||||
mJSStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && mJSStack) {
|
||||
rv = mJSStack->Push(nsnull);
|
||||
if (NS_FAILED(rv))
|
||||
mJSStack = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
JSStackGuard::~JSStackGuard()
|
||||
{
|
||||
if (mJSStack) {
|
||||
JSContext *cx;
|
||||
mJSStack->Pop(&cx);
|
||||
NS_ASSERTION(cx == nsnull, "JSContextStack mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrivateBrowsingServiceWrapper::GetPrivateBrowsingEnabled(PRBool *aPrivateBrowsingEnabled)
|
||||
{
|
||||
if (!aPrivateBrowsingEnabled)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
JSStackGuard guard;
|
||||
return mPBService->GetPrivateBrowsingEnabled(aPrivateBrowsingEnabled);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrivateBrowsingServiceWrapper::SetPrivateBrowsingEnabled(PRBool aPrivateBrowsingEnabled)
|
||||
{
|
||||
JSStackGuard guard;
|
||||
return mPBService->SetPrivateBrowsingEnabled(aPrivateBrowsingEnabled);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrivateBrowsingServiceWrapper::GetAutoStarted(PRBool *aAutoStarted)
|
||||
{
|
||||
if (!aAutoStarted)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
JSStackGuard guard;
|
||||
return mPBService->GetAutoStarted(aAutoStarted);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrivateBrowsingServiceWrapper::RemoveDataFromDomain(const nsACString & aDomain)
|
||||
{
|
||||
JSStackGuard guard;
|
||||
return mPBService->RemoveDataFromDomain(aDomain);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrivateBrowsingServiceWrapper::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
|
||||
{
|
||||
JSStackGuard guard;
|
||||
nsCOMPtr<nsIObserver> observer(do_QueryInterface(mPBService));
|
||||
NS_ENSURE_TRUE(observer, NS_ERROR_FAILURE);
|
||||
return observer->Observe(aSubject, aTopic, aData);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/* ***** 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 Private Browsing.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPrivateBrowsingService.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
class nsIJSContextStack;
|
||||
|
||||
class nsPrivateBrowsingServiceWrapper : public nsIPrivateBrowsingService,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPRIVATEBROWSINGSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsresult Init();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPrivateBrowsingService> mPBService;
|
||||
};
|
|
@ -51,6 +51,8 @@ _BROWSER_TEST_FILES = \
|
|||
browser_privatebrowsing_searchbar.js \
|
||||
browser_privatebrowsing_findbar.js \
|
||||
browser_privatebrowsing_zoom.js \
|
||||
browser_privatebrowsing_transition.js \
|
||||
browser_privatebrowsing_import.js \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_BROWSER_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/* ***** 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 Private Browsing Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ehsan Akhgari.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ehsan Akhgari <ehsan.akhgari@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 ***** */
|
||||
|
||||
// This test makes sure that the File->Import menu item is disabled inside the
|
||||
// private browsing mode.
|
||||
|
||||
function test() {
|
||||
// initialization
|
||||
let prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
|
||||
let pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
|
||||
let importMenuItem = document.getElementById("menu_import");
|
||||
|
||||
// make sure the menu item is not disabled to begin with
|
||||
ok(!importMenuItem.hasAttribute("disabled"),
|
||||
"File->Import menu item should not be disabled outside of the private browsing mode");
|
||||
|
||||
// enter private browsing mode
|
||||
pb.privateBrowsingEnabled = true;
|
||||
|
||||
ok(importMenuItem.hasAttribute("disabled"),
|
||||
"File->Import menu item should be disabled inside of the private browsing mode");
|
||||
|
||||
// leave private browsing mode
|
||||
pb.privateBrowsingEnabled = false;
|
||||
|
||||
ok(!importMenuItem.hasAttribute("disabled"),
|
||||
"File->Import menu item should not be disabled after leaving the private browsing mode");
|
||||
|
||||
// cleanup
|
||||
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/* ***** 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 Private Browsing Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Nochum Sossonko.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Nochum Sossonko <nsossonko@hotmail.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 ***** */
|
||||
|
||||
// Tests the order of events and notifications when entering/exiting private
|
||||
// browsing mode. This ensures that all private data is removed on exit, e.g.
|
||||
// a cookie set in on unload handler, see bug 476463.
|
||||
let cookieManager = Cc["@mozilla.org/cookiemanager;1"].
|
||||
getService(Ci.nsICookieManager2);
|
||||
let pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
let _obs = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
let observerNotified = 0, firstUnloadFired = 0, secondUnloadFired = 0;
|
||||
|
||||
let pbObserver = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "private-browsing") {
|
||||
switch(aData) {
|
||||
case "enter":
|
||||
observerNotified++;
|
||||
is(observerNotified, 1, "This should be the first notification");
|
||||
is(firstUnloadFired, 1, "The first unload event should have been processed by now");
|
||||
break;
|
||||
case "exit":
|
||||
_obs.removeObserver(this, "private-browsing");
|
||||
observerNotified++;
|
||||
is(observerNotified, 2, "This should be the second notification");
|
||||
is(secondUnloadFired, 1, "The second unload event should have been processed by now");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
_obs.addObserver(pbObserver, "private-browsing", false);
|
||||
is(gBrowser.tabContainer.childNodes.length, 1, "There should only be one tab");
|
||||
let testTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = testTab;
|
||||
testTab.linkedBrowser.addEventListener("unload", (function() {
|
||||
testTab.linkedBrowser.removeEventListener("unload", arguments.callee, true);
|
||||
firstUnloadFired++;
|
||||
is(observerNotified, 0, "The notification shouldn't have been sent yet");
|
||||
}), true);
|
||||
|
||||
pb.privateBrowsingEnabled = true;
|
||||
let testTab = gBrowser.addTab();
|
||||
gBrowser.selectedTab = testTab;
|
||||
testTab.linkedBrowser.addEventListener("unload", (function() {
|
||||
testTab.linkedBrowser.removeEventListener("unload", arguments.callee, true);
|
||||
secondUnloadFired++;
|
||||
is(observerNotified, 1, "The notification shouldn't have been sent yet");
|
||||
cookieManager.add("example.com", "test/", "PB", "1", false, false, false, 1000000000000);
|
||||
}), true);
|
||||
|
||||
pb.privateBrowsingEnabled = false;
|
||||
gBrowser.tabContainer.lastChild.linkedBrowser.addEventListener("unload", (function() {
|
||||
gBrowser.tabContainer.lastChild.linkedBrowser.removeEventListener("unload", arguments.callee, true);
|
||||
let count = cookieManager.countCookiesFromHost("example.com");
|
||||
is(count, 0, "There shouldn't be any cookies once pb mode has exited");
|
||||
cookieManager.QueryInterface(Ci.nsICookieManager);
|
||||
cookieManager.remove("example.com", "PB", "test/", false);
|
||||
}), true);
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* ***** 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 Private Browsing Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ehsan Akhgari.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ehsan Akhgari <ehsan.akhgari@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 ***** */
|
||||
|
||||
// This test checks the browser.privatebrowsing.autostart preference.
|
||||
|
||||
function do_test() {
|
||||
// initialization
|
||||
var prefsService = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
prefsService.setBoolPref("browser.privatebrowsing.autostart", true);
|
||||
do_check_true(prefsService.getBoolPref("browser.privatebrowsing.autostart"));
|
||||
|
||||
var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
|
||||
getService(Ci.nsIPrivateBrowsingService).
|
||||
QueryInterface(Ci.nsIObserver);
|
||||
|
||||
// private browsing not auto-started yet
|
||||
do_check_false(pb.autoStarted);
|
||||
|
||||
// simulate startup to make the PB service read the prefs
|
||||
pb.observe(null, "profile-after-change", "");
|
||||
|
||||
// the private mode should be entered automatically
|
||||
do_check_true(pb.privateBrowsingEnabled);
|
||||
|
||||
// private browsing is auto-started
|
||||
do_check_true(pb.autoStarted);
|
||||
|
||||
// leave private browsing mode
|
||||
pb.privateBrowsingEnabled = false;
|
||||
|
||||
// private browsing not auto-started
|
||||
do_check_false(pb.autoStarted);
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/* ***** 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 Private Browsing Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Ehsan Akhgari.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ehsan Akhgari <ehsan.akhgari@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 ***** */
|
||||
|
||||
// This test makes sure that the private browsing mode is left at application
|
||||
// shutdown.
|
||||
|
||||
function do_test() {
|
||||
// initialization
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
|
||||
|
||||
var expectedQuitting;
|
||||
var called = 0;
|
||||
var observer = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == kPrivateBrowsingNotification &&
|
||||
aData == kExit) {
|
||||
// increment the call counter
|
||||
++ called;
|
||||
|
||||
do_check_neq(aSubject, null);
|
||||
try {
|
||||
aSubject.QueryInterface(Ci.nsISupportsPRBool);
|
||||
} catch (ex) {
|
||||
do_throw("aSubject was not null, but wasn't an nsISupportsPRBool");
|
||||
}
|
||||
// check the "quitting" argument
|
||||
do_check_eq(aSubject.data, expectedQuitting);
|
||||
|
||||
// finish up the test
|
||||
if (expectedQuitting) {
|
||||
os.removeObserver(this, kPrivateBrowsingNotification);
|
||||
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
|
||||
do_test_finished();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// set the observer
|
||||
os.addObserver(observer, kPrivateBrowsingNotification, false);
|
||||
|
||||
// enter the private browsing mode
|
||||
pb.privateBrowsingEnabled = true;
|
||||
|
||||
// exit the private browsing mode
|
||||
expectedQuitting = false;
|
||||
pb.privateBrowsingEnabled = false;
|
||||
do_check_eq(called, 1);
|
||||
|
||||
// enter the private browsing mode
|
||||
pb.privateBrowsingEnabled = true;
|
||||
|
||||
// Simulate an exit
|
||||
expectedQuitting = true;
|
||||
do_test_pending();
|
||||
os.notifyObservers(null, "quit-application-granted", null);
|
||||
}
|
|
@ -0,0 +1,618 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=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 Private Browsing Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Shawn Wilsher <me@shawnwilsher.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 ***** */
|
||||
|
||||
/**
|
||||
* Test added with bug 460086 to test the behavior of the new API that was added
|
||||
* to remove all traces of visiting a site.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Constants
|
||||
|
||||
let pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
|
||||
const COOKIE_EXPIRY = Math.round(Date.now() / 1000) + 60;
|
||||
const COOKIE_NAME = "testcookie";
|
||||
const COOKIE_PATH = "/";
|
||||
|
||||
const LOGIN_USERNAME = "username";
|
||||
const LOGIN_PASSWORD = "password";
|
||||
const LOGIN_USERNAME_FIELD = "username_field";
|
||||
const LOGIN_PASSWORD_FIELD = "password_field";
|
||||
|
||||
const PERMISSION_TYPE = "test-perm";
|
||||
const PERMISSION_VALUE = Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
|
||||
const PREFERENCE_NAME = "test-pref";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Utility Functions
|
||||
|
||||
/**
|
||||
* Creates an nsIURI object for the given string representation of a URI.
|
||||
*
|
||||
* @param aURIString
|
||||
* The spec of the URI to create.
|
||||
* @returns an nsIURI representing aURIString.
|
||||
*/
|
||||
function uri(aURIString)
|
||||
{
|
||||
return Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService).
|
||||
newURI(aURIString, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a visit to history.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to add.
|
||||
*/
|
||||
function add_visit(aURI)
|
||||
{
|
||||
check_visited(aURI, false);
|
||||
let bh = Cc["@mozilla.org/browser/global-history;2"].
|
||||
getService(Ci.nsIBrowserHistory);
|
||||
bh.addPageWithDetails(aURI, aURI.spec, Date.now() * 1000);
|
||||
check_visited(aURI, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to ensure a URI string is visited or not.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to check.
|
||||
* @param aIsVisited
|
||||
* True if the URI should be visited, false otherwise.
|
||||
*/
|
||||
function check_visited(aURI, aIsVisited)
|
||||
{
|
||||
let gh = Cc["@mozilla.org/browser/global-history;2"].
|
||||
getService(Ci.nsIGlobalHistory2);
|
||||
let checker = aIsVisited ? do_check_true : do_check_false;
|
||||
checker(gh.isVisited(aURI));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a cookie to the cookie service.
|
||||
*
|
||||
* @param aDomain
|
||||
*/
|
||||
function add_cookie(aDomain)
|
||||
{
|
||||
check_cookie_exists(aDomain, false);
|
||||
let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
|
||||
cm.add(aDomain, COOKIE_PATH, COOKIE_NAME, "", false, false, false,
|
||||
COOKIE_EXPIRY);
|
||||
check_cookie_exists(aDomain, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to ensure that a cookie exists or not for a domain.
|
||||
*
|
||||
* @param aDomain
|
||||
* The domain to check for the cookie.
|
||||
* @param aExists
|
||||
* True if the cookie should exist, false otherwise.
|
||||
*/
|
||||
function check_cookie_exists(aDomain, aExists)
|
||||
{
|
||||
let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
|
||||
let cookie = {
|
||||
host: aDomain,
|
||||
name: COOKIE_NAME,
|
||||
path: COOKIE_PATH
|
||||
}
|
||||
let checker = aExists ? do_check_true : do_check_false;
|
||||
checker(cm.cookieExists(cookie));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a download to download history.
|
||||
*
|
||||
* @param aURIString
|
||||
* The string of the URI to add.
|
||||
* @param aIsActive
|
||||
* If it should be set to an active state in the database. This does not
|
||||
* make it show up in the list of active downloads however!
|
||||
*/
|
||||
function add_download(aURIString, aIsActive)
|
||||
{
|
||||
check_downloaded(aURIString, false);
|
||||
let db = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager).
|
||||
DBConnection;
|
||||
let stmt = db.createStatement(
|
||||
"INSERT INTO moz_downloads (source, state) " +
|
||||
"VALUES (:source, :state)"
|
||||
);
|
||||
stmt.params.source = aURIString;
|
||||
stmt.params.state = aIsActive ? Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING :
|
||||
Ci.nsIDownloadManager.DOWNLOAD_FINISHED;
|
||||
try {
|
||||
stmt.execute();
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
check_downloaded(aURIString, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to ensure a URI string is in download history or not.
|
||||
*
|
||||
* @param aURIString
|
||||
* The string of the URI to check.
|
||||
* @param aIsDownloaded
|
||||
* True if the URI should be downloaded, false otherwise.
|
||||
*/
|
||||
function check_downloaded(aURIString, aIsDownloaded)
|
||||
{
|
||||
let db = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager).
|
||||
DBConnection;
|
||||
let stmt = db.createStatement(
|
||||
"SELECT * " +
|
||||
"FROM moz_downloads " +
|
||||
"WHERE source = :source"
|
||||
);
|
||||
stmt.params.source = aURIString;
|
||||
|
||||
let checker = aIsDownloaded ? do_check_true : do_check_false;
|
||||
try {
|
||||
checker(stmt.step());
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a disabled host to the login manager.
|
||||
*
|
||||
* @param aHost
|
||||
* The host to add to the list of disabled hosts.
|
||||
*/
|
||||
function add_disabled_host(aHost)
|
||||
{
|
||||
check_disabled_host(aHost, false);
|
||||
let lm = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
lm.setLoginSavingEnabled(aHost, false);
|
||||
check_disabled_host(aHost, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a host is disabled for storing logins or not.
|
||||
*
|
||||
* @param aHost
|
||||
* The host to check if it is disabled.
|
||||
* @param aIsDisabled
|
||||
* True if the host should be disabled, false otherwise.
|
||||
*/
|
||||
function check_disabled_host(aHost, aIsDisabled)
|
||||
{
|
||||
let lm = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
let checker = aIsDisabled ? do_check_false : do_check_true;
|
||||
checker(lm.getLoginSavingEnabled(aHost));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a login for the specified host to the login manager.
|
||||
*
|
||||
* @param aHost
|
||||
* The host to add the login for.
|
||||
*/
|
||||
function add_login(aHost)
|
||||
{
|
||||
check_login_exists(aHost, false);
|
||||
let login = Cc["@mozilla.org/login-manager/loginInfo;1"].
|
||||
createInstance(Ci.nsILoginInfo);
|
||||
login.init(aHost, "", null, LOGIN_USERNAME, LOGIN_PASSWORD,
|
||||
LOGIN_USERNAME_FIELD, LOGIN_PASSWORD_FIELD);
|
||||
let lm = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
lm.addLogin(login);
|
||||
check_login_exists(aHost, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a login exists for a host.
|
||||
*
|
||||
* @param aHost
|
||||
* The host to check for the test login.
|
||||
* @param aExists
|
||||
* True if the login should exist, false otherwise.
|
||||
*/
|
||||
function check_login_exists(aHost, aExists)
|
||||
{
|
||||
let lm = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
let count = { value: 0 };
|
||||
lm.findLogins(count, aHost, "", null);
|
||||
do_check_eq(count.value, aExists ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a permission for the specified URI to the permission manager.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to add the test permission for.
|
||||
*/
|
||||
function add_permission(aURI)
|
||||
{
|
||||
check_permission_exists(aURI, false);
|
||||
let pm = Cc["@mozilla.org/permissionmanager;1"].
|
||||
getService(Ci.nsIPermissionManager);
|
||||
pm.add(aURI, PERMISSION_TYPE, PERMISSION_VALUE);
|
||||
check_permission_exists(aURI, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a permission exists for the given URI.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to check if a permission exists.
|
||||
* @param aExists
|
||||
* True if the permission should exist, false otherwise.
|
||||
*/
|
||||
function check_permission_exists(aURI, aExists)
|
||||
{
|
||||
let pm = Cc["@mozilla.org/permissionmanager;1"].
|
||||
getService(Ci.nsIPermissionManager);
|
||||
let perm = pm.testExactPermission(aURI, PERMISSION_TYPE);
|
||||
let checker = aExists ? do_check_eq : do_check_neq;
|
||||
checker(perm, PERMISSION_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a content preference for the specified URI.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to add a preference for.
|
||||
*/
|
||||
function add_preference(aURI)
|
||||
{
|
||||
check_preference_exists(aURI, false);
|
||||
let cp = Cc["@mozilla.org/content-pref/service;1"].
|
||||
getService(Ci.nsIContentPrefService);
|
||||
cp.setPref(aURI, PREFERENCE_NAME, "foo");
|
||||
check_preference_exists(aURI, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a preference exists for the given URI.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to check if a preference exists.
|
||||
* @param aExists
|
||||
* True if the permission should exist, false otherwise.
|
||||
*/
|
||||
function check_preference_exists(aURI, aExists)
|
||||
{
|
||||
let cp = Cc["@mozilla.org/content-pref/service;1"].
|
||||
getService(Ci.nsIContentPrefService);
|
||||
let checker = aExists ? do_check_true : do_check_false;
|
||||
checker(cp.hasPref(aURI, PREFERENCE_NAME));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Test Functions
|
||||
|
||||
// History
|
||||
function test_history_cleared_with_direct_match()
|
||||
{
|
||||
const TEST_URI = uri("http://mozilla.org/foo");
|
||||
add_visit(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_visited(TEST_URI, false);
|
||||
}
|
||||
|
||||
function test_history_cleared_with_subdomain()
|
||||
{
|
||||
const TEST_URI = uri("http://www.mozilla.org/foo");
|
||||
add_visit(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_visited(TEST_URI, false);
|
||||
}
|
||||
|
||||
function test_history_not_cleared_with_uri_contains_domain()
|
||||
{
|
||||
const TEST_URI = uri("http://ilovemozilla.org/foo");
|
||||
add_visit(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_visited(TEST_URI, true);
|
||||
|
||||
// Clear history since we left something there from this test.
|
||||
let bh = Cc["@mozilla.org/browser/global-history;2"].
|
||||
getService(Ci.nsIBrowserHistory);
|
||||
bh.removeAllPages();
|
||||
}
|
||||
|
||||
// Cookie Service
|
||||
function test_cookie_cleared_with_direct_match()
|
||||
{
|
||||
const TEST_DOMAIN = "mozilla.org";
|
||||
add_cookie(TEST_DOMAIN);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_cookie_exists(TEST_DOMAIN, false);
|
||||
}
|
||||
|
||||
function test_cookie_cleared_with_subdomain()
|
||||
{
|
||||
const TEST_DOMAIN = "www.mozilla.org";
|
||||
add_cookie(TEST_DOMAIN);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_cookie_exists(TEST_DOMAIN, false);
|
||||
}
|
||||
|
||||
function test_cookie_not_cleared_with_uri_contains_domain()
|
||||
{
|
||||
const TEST_DOMAIN = "ilovemozilla.org";
|
||||
add_cookie(TEST_DOMAIN);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_cookie_exists(TEST_DOMAIN, true);
|
||||
}
|
||||
|
||||
// Download Manager
|
||||
function test_download_history_cleared_with_direct_match()
|
||||
{
|
||||
const TEST_URI = "http://mozilla.org/foo";
|
||||
add_download(TEST_URI, false);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_downloaded(TEST_URI, false);
|
||||
}
|
||||
|
||||
function test_download_history_cleared_with_subdomain()
|
||||
{
|
||||
const TEST_URI = "http://www.mozilla.org/foo";
|
||||
add_download(TEST_URI, false);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_downloaded(TEST_URI, false);
|
||||
}
|
||||
|
||||
function test_download_history_not_cleared_with_active_direct_match()
|
||||
{
|
||||
// Tests that downloads marked as active in the db are not deleted from the db
|
||||
const TEST_URI = "http://mozilla.org/foo";
|
||||
add_download(TEST_URI, true);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_downloaded(TEST_URI, true);
|
||||
|
||||
// Reset state
|
||||
let db = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager).
|
||||
DBConnection;
|
||||
db.executeSimpleSQL("DELETE FROM moz_downloads");
|
||||
check_downloaded(TEST_URI, false);
|
||||
}
|
||||
|
||||
// Login Manager
|
||||
function test_login_manager_disabled_hosts_cleared_with_direct_match()
|
||||
{
|
||||
const TEST_HOST = "http://mozilla.org";
|
||||
add_disabled_host(TEST_HOST);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_disabled_host(TEST_HOST, false);
|
||||
}
|
||||
|
||||
function test_login_manager_disabled_hosts_cleared_with_subdomain()
|
||||
{
|
||||
const TEST_HOST = "http://www.mozilla.org";
|
||||
add_disabled_host(TEST_HOST);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_disabled_host(TEST_HOST, false);
|
||||
}
|
||||
|
||||
function test_login_manager_disabled_hosts_not_cleared_with_uri_contains_domain()
|
||||
{
|
||||
const TEST_HOST = "http://ilovemozilla.org";
|
||||
add_disabled_host(TEST_HOST);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_disabled_host(TEST_HOST, true);
|
||||
|
||||
// Reset state
|
||||
let lm = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
lm.setLoginSavingEnabled(TEST_HOST, true);
|
||||
check_disabled_host(TEST_HOST, false);
|
||||
}
|
||||
|
||||
function test_login_manager_logins_cleared_with_direct_match()
|
||||
{
|
||||
const TEST_HOST = "http://mozilla.org";
|
||||
add_login(TEST_HOST);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_login_exists(TEST_HOST, false);
|
||||
}
|
||||
|
||||
function test_login_manager_logins_cleared_with_subdomain()
|
||||
{
|
||||
const TEST_HOST = "http://www.mozilla.org";
|
||||
add_login(TEST_HOST);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_login_exists(TEST_HOST, false);
|
||||
}
|
||||
|
||||
function tets_login_manager_logins_not_cleared_with_uri_contains_domain()
|
||||
{
|
||||
const TEST_HOST = "http://ilovemozilla.org";
|
||||
add_login(TEST_HOST);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_login_exists(TEST_HOST, true);
|
||||
|
||||
let lm = Cc["@mozilla.org/login-manager;1"].
|
||||
getService(Ci.nsILoginManager);
|
||||
lm.removeAllLogins();
|
||||
check_login_exists(TEST_HOST, false);
|
||||
}
|
||||
|
||||
// Permission Manager
|
||||
function test_permission_manager_cleared_with_direct_match()
|
||||
{
|
||||
const TEST_URI = uri("http://mozilla.org");
|
||||
add_permission(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_permission_exists(TEST_URI, false);
|
||||
}
|
||||
|
||||
function test_permission_manager_cleared_with_subdomain()
|
||||
{
|
||||
const TEST_URI = uri("http://www.mozilla.org");
|
||||
add_permission(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_permission_exists(TEST_URI, false);
|
||||
}
|
||||
|
||||
function test_permission_manager_not_cleared_with_uri_contains_domain()
|
||||
{
|
||||
const TEST_URI = uri("http://ilovemozilla.org");
|
||||
add_permission(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_permission_exists(TEST_URI, true);
|
||||
|
||||
// Reset state
|
||||
let pm = Cc["@mozilla.org/permissionmanager;1"].
|
||||
getService(Ci.nsIPermissionManager);
|
||||
pm.removeAll();
|
||||
check_permission_exists(TEST_URI, false);
|
||||
}
|
||||
|
||||
// Content Preferences
|
||||
function test_content_preferences_cleared_with_direct_match()
|
||||
{
|
||||
const TEST_URI = uri("http://mozilla.org");
|
||||
add_preference(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_preference_exists(TEST_URI, false);
|
||||
}
|
||||
|
||||
function test_content_preferences_cleared_with_subdomain()
|
||||
{
|
||||
const TEST_URI = uri("http://www.mozilla.org");
|
||||
add_preference(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_preference_exists(TEST_URI, false);
|
||||
}
|
||||
|
||||
function test_content_preferecnes_not_cleared_with_uri_contains_domain()
|
||||
{
|
||||
const TEST_URI = uri("http://ilovemozilla.org");
|
||||
add_preference(TEST_URI);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
check_preference_exists(TEST_URI, true);
|
||||
|
||||
// Reset state
|
||||
let cp = Cc["@mozilla.org/content-pref/service;1"].
|
||||
getService(Ci.nsIContentPrefService);
|
||||
cp.removePref(TEST_URI, PREFERENCE_NAME);
|
||||
check_preference_exists(TEST_URI, false);
|
||||
}
|
||||
|
||||
// Cache
|
||||
function test_cache_cleared()
|
||||
{
|
||||
// Because this test is asynchronous, it should be the last test
|
||||
do_check_eq(tests[tests.length - 1], arguments.callee);
|
||||
|
||||
// NOTE: We could be more extensive with this test and actually add an entry
|
||||
// to the cache, and then make sure it is gone. However, we trust that
|
||||
// the API is well tested, and that when we get the observer
|
||||
// notification, we have actually cleared the cache.
|
||||
// This seems to happen asynchronously...
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
let observer = {
|
||||
observe: function(aSubject, aTopic, aData)
|
||||
{
|
||||
os.removeObserver(observer, "cacheservice:empty-cache");
|
||||
do_test_finished();
|
||||
}
|
||||
};
|
||||
os.addObserver(observer, "cacheservice:empty-cache", false);
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
let tests = [
|
||||
// History
|
||||
test_history_cleared_with_direct_match,
|
||||
test_history_cleared_with_subdomain,
|
||||
test_history_not_cleared_with_uri_contains_domain,
|
||||
|
||||
// Cookie Service
|
||||
test_cookie_cleared_with_direct_match,
|
||||
test_cookie_cleared_with_subdomain,
|
||||
test_cookie_not_cleared_with_uri_contains_domain,
|
||||
|
||||
// Download Manager
|
||||
// Note: active downloads tested in test_removeDataFromDomain_activeDownloads.js
|
||||
test_download_history_cleared_with_direct_match,
|
||||
test_download_history_cleared_with_subdomain,
|
||||
test_download_history_not_cleared_with_active_direct_match,
|
||||
|
||||
// Login Manager
|
||||
test_login_manager_disabled_hosts_cleared_with_direct_match,
|
||||
test_login_manager_disabled_hosts_cleared_with_subdomain,
|
||||
test_login_manager_disabled_hosts_not_cleared_with_uri_contains_domain,
|
||||
test_login_manager_logins_cleared_with_direct_match,
|
||||
test_login_manager_logins_cleared_with_subdomain,
|
||||
tets_login_manager_logins_not_cleared_with_uri_contains_domain,
|
||||
|
||||
// Permission Manager
|
||||
test_permission_manager_cleared_with_direct_match,
|
||||
test_permission_manager_cleared_with_subdomain,
|
||||
test_permission_manager_not_cleared_with_uri_contains_domain,
|
||||
|
||||
// Content Preferences
|
||||
test_content_preferences_cleared_with_direct_match,
|
||||
test_content_preferences_cleared_with_subdomain,
|
||||
test_content_preferecnes_not_cleared_with_uri_contains_domain,
|
||||
|
||||
// Cache
|
||||
test_cache_cleared,
|
||||
];
|
||||
|
||||
function do_test()
|
||||
{
|
||||
for (let i = 0; i < tests.length; i++)
|
||||
tests[i]();
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 sts=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 Private Browsing Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Shawn Wilsher <me@shawnwilsher.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 ***** */
|
||||
|
||||
/**
|
||||
* Test added with bug 460086 to test the behavior of the new API that was added
|
||||
* to remove all traces of visiting a site.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Constants
|
||||
|
||||
let pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Utility Functions
|
||||
|
||||
/**
|
||||
* Creates an nsIURI object for the given file.
|
||||
*
|
||||
* @param aFile
|
||||
* The nsIFile of the URI to create.
|
||||
* @returns an nsIURI representing aFile.
|
||||
*/
|
||||
function uri(aFile)
|
||||
{
|
||||
return Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService).
|
||||
newFileURI(aFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to ensure a URI string is in download history or not.
|
||||
*
|
||||
* @param aURIString
|
||||
* The string of the URI to check.
|
||||
* @param aIsActive
|
||||
* True if the URI should be actively downloaded, false otherwise.
|
||||
*/
|
||||
function check_active_download(aURIString, aIsActive)
|
||||
{
|
||||
let dm = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager);
|
||||
let enumerator = dm.activeDownloads;
|
||||
let found = false;
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let dl = enumerator.getNext().QueryInterface(Ci.nsIDownload);
|
||||
if (dl.source.spec == aURIString)
|
||||
found = true;
|
||||
}
|
||||
let checker = aIsActive ? do_check_true : do_check_false;
|
||||
checker(found);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Test Functions
|
||||
|
||||
let destFile = dirSvc.get("TmpD", Ci.nsIFile);
|
||||
destFile.append("dm-test-file");
|
||||
destFile = uri(destFile);
|
||||
let data = [
|
||||
{ source: "http://mozilla.org/direct_match",
|
||||
target: destFile.spec,
|
||||
removed: true
|
||||
},
|
||||
{ source: "http://www.mozilla.org/subdomain",
|
||||
target: destFile.spec,
|
||||
removed: true
|
||||
},
|
||||
{ source: "http://ilovemozilla.org/contains_domain",
|
||||
target: destFile.spec,
|
||||
removed: false
|
||||
},
|
||||
];
|
||||
|
||||
function do_test()
|
||||
{
|
||||
// We add this data to the database first, but we cannot instantiate the
|
||||
// download manager service, otherwise these downloads will not be placed in
|
||||
// the active downloads array.
|
||||
|
||||
// Copy the empty downloads database to our profile directory
|
||||
let downloads = do_get_file("toolkit/components/downloads/test/downloads.empty.sqlite");
|
||||
downloads.copyTo(dirSvc.get("ProfD", Ci.nsIFile), "downloads.sqlite");
|
||||
|
||||
// Open the database
|
||||
let ss = Cc["@mozilla.org/storage/service;1"].
|
||||
getService(Ci.mozIStorageService);
|
||||
let file = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
file.append("downloads.sqlite");
|
||||
let db = ss.openDatabase(file);
|
||||
|
||||
// Insert the data
|
||||
let stmt = db.createStatement(
|
||||
"INSERT INTO moz_downloads (source, target, state, autoResume, entityID) " +
|
||||
"VALUES (:source, :target, :state, :autoResume, :entityID)"
|
||||
);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
stmt.params.source = data[i].source;
|
||||
stmt.params.target = data[i].target;
|
||||
stmt.params.state = Ci.nsIDownloadManager.DOWNLOAD_PAUSED;
|
||||
stmt.params.autoResume = 0; // DONT_RESUME is 0
|
||||
stmt.params.entityID = "foo" // just has to be non-null for our test
|
||||
stmt.execute();
|
||||
stmt.reset();
|
||||
}
|
||||
stmt.finalize();
|
||||
stmt = null;
|
||||
db.close();
|
||||
db = null;
|
||||
|
||||
// Check to make sure it's all there
|
||||
for (let i = 0; i < data.length; i++)
|
||||
check_active_download(data[i].source, true);
|
||||
|
||||
// Dispatch the remove call
|
||||
pb.removeDataFromDomain("mozilla.org");
|
||||
|
||||
// And check our data
|
||||
for (let i = 0; i < data.length; i++)
|
||||
check_active_download(data[i].source, !data[i].removed);
|
||||
}
|
|
@ -109,3 +109,16 @@ function cleanUp()
|
|||
}
|
||||
}
|
||||
cleanUp();
|
||||
|
||||
var PRIVATEBROWSING_CONTRACT_ID;
|
||||
function run_test_on_all_services() {
|
||||
var contractIDs = [
|
||||
"@mozilla.org/privatebrowsing;1",
|
||||
"@mozilla.org/privatebrowsing-wrapper;1"
|
||||
];
|
||||
for (var i = 0; i < contractIDs.length; ++i) {
|
||||
PRIVATEBROWSING_CONTRACT_ID = contractIDs[i];
|
||||
run_test_on_service();
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
// This test should run before the rest of private browsing service unit tests,
|
||||
// hence the naming used for this file.
|
||||
|
||||
function run_test() {
|
||||
function run_test_on_service() {
|
||||
// initialization
|
||||
var os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
|
@ -50,14 +50,14 @@ function run_test() {
|
|||
prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
|
||||
|
||||
// the contract ID should be available
|
||||
do_check_true("@mozilla.org/privatebrowsing;1" in Cc);
|
||||
do_check_true(PRIVATEBROWSING_CONTRACT_ID in Cc);
|
||||
|
||||
// the interface should be available
|
||||
do_check_true("nsIPrivateBrowsingService" in Ci);
|
||||
|
||||
// it should be possible to initialize the component
|
||||
try {
|
||||
var pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
} catch (ex) {
|
||||
LOG("exception thrown when trying to get the service: " + ex);
|
||||
|
@ -222,3 +222,8 @@ function run_test() {
|
|||
|
||||
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
|
||||
}
|
||||
|
||||
// Support running tests on both the service itself and its wrapper
|
||||
function run_test() {
|
||||
run_test_on_all_services();
|
||||
}
|
||||
|
|
|
@ -59,9 +59,9 @@ function is_about_privatebrowsing_available() {
|
|||
return false;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
function run_test_on_service() {
|
||||
// initialization
|
||||
var pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
|
@ -86,3 +86,8 @@ function run_test() {
|
|||
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
|
||||
}
|
||||
}
|
||||
|
||||
// Support running tests on both the service itself and its wrapper
|
||||
function run_test() {
|
||||
run_test_on_all_services();
|
||||
}
|
||||
|
|
|
@ -38,12 +38,12 @@
|
|||
// This test makes sure the HTTP authenticated sessions are correctly cleared
|
||||
// when entering and leaving the private browsing mode.
|
||||
|
||||
function run_test() {
|
||||
function run_test_on_service() {
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
|
||||
|
||||
var pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
var pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
|
||||
var am = Cc["@mozilla.org/network/http-auth-manager;1"].
|
||||
|
@ -112,3 +112,8 @@ function run_test() {
|
|||
prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
|
||||
}
|
||||
}
|
||||
|
||||
// Support running tests on both the service itself and its wrapper
|
||||
function run_test() {
|
||||
run_test_on_all_services();
|
||||
}
|
||||
|
|
|
@ -38,31 +38,7 @@
|
|||
// This test checks the browser.privatebrowsing.autostart preference.
|
||||
|
||||
function run_test() {
|
||||
// initialization
|
||||
var prefsService = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
prefsService.setBoolPref("browser.privatebrowsing.autostart", true);
|
||||
do_check_true(prefsService.getBoolPref("browser.privatebrowsing.autostart"));
|
||||
|
||||
var pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
getService(Ci.nsIPrivateBrowsingService).
|
||||
QueryInterface(Ci.nsIObserver);
|
||||
|
||||
// private browsing not auto-started yet
|
||||
do_check_false(pb.autoStarted);
|
||||
|
||||
// simulate startup to make the PB service read the prefs
|
||||
pb.observe(null, "profile-after-change", "");
|
||||
|
||||
// the private mode should be entered automatically
|
||||
do_check_true(pb.privateBrowsingEnabled);
|
||||
|
||||
// private browsing is auto-started
|
||||
do_check_true(pb.autoStarted);
|
||||
|
||||
// leave private browsing mode
|
||||
pb.privateBrowsingEnabled = false;
|
||||
|
||||
// private browsing not auto-started
|
||||
do_check_false(pb.autoStarted);
|
||||
PRIVATEBROWSING_CONTRACT_ID = "@mozilla.org/privatebrowsing;1";
|
||||
do_import_script("browser/components/privatebrowsing/test/unit/do_test_privatebrowsing_autostart.js");
|
||||
do_test();
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче