зеркало из https://github.com/mozilla/gecko-dev.git
Merging backout
This commit is contained in:
Коммит
4fd12ef2e8
|
@ -81,7 +81,6 @@ CPPSRCS = \
|
|||
nsAccessibilityAtoms.cpp \
|
||||
nsCoreUtils.cpp \
|
||||
nsAccUtils.cpp \
|
||||
nsNameUtils.cpp \
|
||||
nsRelUtils.cpp \
|
||||
nsAccessibilityService.cpp \
|
||||
nsAccessible.cpp \
|
||||
|
@ -93,6 +92,7 @@ CPPSRCS = \
|
|||
nsApplicationAccessible.cpp \
|
||||
nsCaretAccessible.cpp \
|
||||
nsTextAccessible.cpp \
|
||||
nsTextEquivUtils.cpp \
|
||||
nsTextAttrs.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -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,6 +92,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_DOCUMENT,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
nsIAccessibleStates::STATE_READONLY,
|
||||
kEndEntry
|
||||
},
|
||||
|
@ -97,6 +101,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_PUSHBUTTON,
|
||||
eNoValue,
|
||||
eClickAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&nsAccessibilityAtoms::aria_pressed, kBoolState, nsIAccessibleStates::STATE_PRESSED},
|
||||
{&nsAccessibilityAtoms::aria_pressed, "mixed", nsIAccessibleStates::STATE_MIXED},
|
||||
|
@ -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,6 +156,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_DOCUMENT,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
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,6 +379,7 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[] =
|
|||
nsIAccessibleRole::ROLE_RADIOBUTTON,
|
||||
eNoValue,
|
||||
eSelectAction,
|
||||
eNoLiveAttr,
|
||||
kNoReqStates,
|
||||
{&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
|
||||
};
|
||||
|
|
|
@ -63,6 +63,13 @@ enum EActionRule
|
|||
eSwitchAction
|
||||
};
|
||||
|
||||
enum ELiveAttrRule
|
||||
{
|
||||
eNoLiveAttr,
|
||||
eOffLiveAttr,
|
||||
ePoliteLiveAttr
|
||||
};
|
||||
|
||||
// ARIA attribute characteristic masks, grow as needed
|
||||
|
||||
/**
|
||||
|
@ -115,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.
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
@ -669,6 +686,18 @@ nsAccUtils::GetAttributeCharacteristics(nsIAtom* aAtom)
|
|||
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
|
||||
|
||||
|
|
|
@ -270,6 +270,12 @@ public:
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -256,6 +256,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.
|
||||
|
@ -2012,7 +1720,7 @@ nsAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
|
|||
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);
|
||||
|
@ -2035,6 +1743,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;
|
||||
}
|
||||
|
||||
|
@ -3378,14 +3097,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
|
||||
};
|
|
@ -1,71 +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 ***** */
|
||||
|
||||
#ifndef _nsNameUtils_H_
|
||||
#define _nsNameUtils_H_
|
||||
|
||||
#include "prtypes.h"
|
||||
|
||||
/**
|
||||
* Name from subtree calculation rules.
|
||||
*/
|
||||
enum ENameFromSubtreeRule
|
||||
{
|
||||
// do not walk into subtree to compute the name
|
||||
eNoRule = 0x00,
|
||||
|
||||
// compute the name from the subtree
|
||||
eFromSubtree = 0x01
|
||||
};
|
||||
|
||||
/**
|
||||
* The class provides utils methods to compute the accessible name and
|
||||
* description.
|
||||
*/
|
||||
class nsNameUtils
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Map array from roles to name rules (bit state of ENameFromSubtreeRule).
|
||||
*/
|
||||
static PRUint32 gRoleToNameRulesMap[];
|
||||
};
|
||||
|
||||
#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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -81,7 +81,7 @@ _TEST_FILES =\
|
|||
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 \
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -3,9 +3,8 @@ function testName(aAccOrElmOrID, aName, aMsg)
|
|||
var msg = aMsg ? aMsg : "";
|
||||
|
||||
var acc = getAccessible(aAccOrElmOrID);
|
||||
if (!acc) {
|
||||
ok(false, msg + "No accessible for " + aAccOrElmOrID + "!");
|
||||
}
|
||||
if (!acc)
|
||||
return;
|
||||
|
||||
try {
|
||||
is(acc.name, aName, msg + "Wrong name of the accessible for " + aAccOrElmOrID);
|
||||
|
@ -36,13 +35,67 @@ function testNames()
|
|||
gRuleDoc = request.responseXML;
|
||||
|
||||
var markupElms = evaluateXPath(gRuleDoc, "//rules/rulesample/markup");
|
||||
for (var idx = 0; idx < markupElms.length; idx++)
|
||||
testNamesForMarkup(markupElms[idx]);
|
||||
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.
|
||||
|
@ -50,7 +103,7 @@ function testNames()
|
|||
function testNamesForMarkup(aMarkupElm)
|
||||
{
|
||||
var div = document.createElement("div");
|
||||
div.setAttribute("test", "test");
|
||||
div.setAttribute("id", "test");
|
||||
|
||||
var child = aMarkupElm.firstChild;
|
||||
while (child) {
|
||||
|
@ -58,90 +111,114 @@ function testNamesForMarkup(aMarkupElm)
|
|||
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[@test='test']/" + aMarkupElm.getAttribute("ref");
|
||||
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);
|
||||
|
||||
for (var idx = 0; idx < ruleElms.length; idx++)
|
||||
testNameForRule(elms[0], ruleElms[idx]);
|
||||
|
||||
document.body.removeChild(div);
|
||||
gTestIterator.iterateRules(elms[0], aContainer, ruleElms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test name for current rule and current 'markup' element. Used by
|
||||
* testNamesForMarkup function.
|
||||
*/
|
||||
function testNameForRule(aElm, aRule)
|
||||
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");
|
||||
if (attr) {
|
||||
var name = "";
|
||||
var attrValue = aElm.getAttribute(attr);
|
||||
|
||||
var type = aRule.getAttribute("type");
|
||||
if (type == "string") {
|
||||
name = attrValue;
|
||||
var attrValue = aElm.getAttribute(attr);
|
||||
|
||||
} 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 += " ";
|
||||
var type = aRule.getAttribute("type");
|
||||
if (type == "string") {
|
||||
name = attrValue;
|
||||
|
||||
name += labelElm.getAttribute("a11yname");
|
||||
}
|
||||
} 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);
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
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;
|
||||
},
|
||||
var filter = {
|
||||
acceptNode: function filter_acceptNode(aNode)
|
||||
{
|
||||
if (aNode.localName == this.mLocalName &&
|
||||
aNode.getAttribute(this.mAttrName) == this.mAttrValue)
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
|
||||
mLocalName: elm,
|
||||
mAttrName: elmattr,
|
||||
mAttrValue: aElm.getAttribute("id")
|
||||
};
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
},
|
||||
|
||||
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;
|
||||
}
|
||||
mLocalName: elm,
|
||||
mAttrName: elmattr,
|
||||
mAttrValue: aElm.getAttribute("id")
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
];
|
||||
|
|
|
@ -23,10 +23,24 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=475006
|
|||
testAttrs("atomic", {"atomic" : "true"}, true);
|
||||
testAttrs("autocomplete", {"autocomplete" : "true"}, true);
|
||||
// bug 477876 testAttrs("checked", {"checkable" : "true"}, true);
|
||||
testAttrs("dropeffect", {"dropeffect" : "copy"}, true);
|
||||
testAttrs("dropeffect", {"dropeffect" : "copy"}, true);
|
||||
|
||||
// live object attribute
|
||||
testAttrs("live", {"live" : "polite"}, true);
|
||||
testAttrs("me", {"container-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);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -50,7 +64,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=475006
|
|||
<div id="autocomplete" role="textbox" aria-autocomplete="true"></div>
|
||||
<div id="checked" aria-checked="true"></div>
|
||||
<div id="dropeffect" aria-dropeffect="copy"></div>
|
||||
<div id="live" aria-live="polite">excuse <div id="me">me</div></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>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -4909,7 +4909,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 +4958,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");
|
||||
|
|
|
@ -1912,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);
|
||||
|
@ -1947,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 ||
|
||||
|
@ -2086,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;
|
||||
|
@ -2209,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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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],
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -200,6 +200,10 @@ SessionStoreService.prototype = {
|
|||
|
||||
// observe prefs changes so we can modify stored data to match
|
||||
this._prefBranch.addObserver("sessionstore.max_tabs_undo", this, true);
|
||||
|
||||
// this pref is only read at startup, so no need to observe it
|
||||
this._sessionhistory_max_entries =
|
||||
this._prefBranch.getIntPref("sessionhistory.max_entries");
|
||||
|
||||
// get file references
|
||||
var dirService = Cc["@mozilla.org/file/directory_service;1"].
|
||||
|
@ -1007,8 +1011,11 @@ SessionStoreService.prototype = {
|
|||
}
|
||||
catch (ex) { } // this could happen if we catch a tab during (de)initialization
|
||||
|
||||
// XXXzeniko anchor navigation doesn't reset __SS_data, so we could reuse
|
||||
// data even when we shouldn't (e.g. Back, different anchor)
|
||||
if (history && browser.parentNode.__SS_data &&
|
||||
browser.parentNode.__SS_data.entries[history.index] && !aFullData) {
|
||||
browser.parentNode.__SS_data.entries[history.index] &&
|
||||
history.index < this._sessionhistory_max_entries - 1 && !aFullData) {
|
||||
tabData = browser.parentNode.__SS_data;
|
||||
tabData.index = history.index + 1;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ _BROWSER_TEST_FILES = \
|
|||
browser_393716.js \
|
||||
browser_408470.js \
|
||||
browser_408470_sample.html \
|
||||
browser_447951.js \
|
||||
browser_447951_sample.html \
|
||||
browser_448741.js \
|
||||
browser_454908.js \
|
||||
browser_454908_sample.html \
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/* ***** 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 sessionstore test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Simon Bünzli <zeniko@gmail.com>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* 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 ***** */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 447951 **/
|
||||
|
||||
// test setup
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
waitForExplicitFinish();
|
||||
const baseURL = "http://localhost:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_447951_sample.html#";
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
let tabState = { entries: [] };
|
||||
let max_entries = gPrefService.getIntPref("browser.sessionhistory.max_entries");
|
||||
for (let i = 0; i < max_entries; i++)
|
||||
tabState.entries.push({ url: baseURL + i });
|
||||
|
||||
ss.setTabState(tab, JSON.stringify(tabState));
|
||||
tab.addEventListener("SSTabRestored", function(aEvent) {
|
||||
this.removeEventListener("SSTabRestored", arguments.callee, false);
|
||||
tabState = eval("(" + ss.getTabState(tab) + ")");
|
||||
is(tabState.entries.length, max_entries, "session history filled to the limit");
|
||||
is(tabState.entries[0].url, baseURL + 0, "... but not more");
|
||||
|
||||
// visit yet another anchor (appending it to session history)
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
let event = doc.createEvent("MouseEvents");
|
||||
event.initMouseEvent("click", true, true, doc.defaultView, 1,
|
||||
0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
doc.querySelector("a").dispatchEvent(event);
|
||||
|
||||
executeSoon(function() {
|
||||
tabState = eval("(" + ss.getTabState(tab) + ")");
|
||||
is(tab.linkedBrowser.currentURI.spec, baseURL + "end",
|
||||
"the new anchor was loaded");
|
||||
is(tabState.entries[tabState.entries.length - 1].url, baseURL + "end",
|
||||
"... and ignored");
|
||||
is(tabState.entries[0].url, baseURL + 1,
|
||||
"... and the first item was removed");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
}, false);
|
||||
}, true);
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Testcase for bug 447951</title>
|
||||
|
||||
<a href="#end">click me</a>
|
|
@ -3819,18 +3819,20 @@ nsCanvasRenderingContext2D::PutImageData()
|
|||
PRUint8 ir, ig, ib, ia;
|
||||
PRUint8 *ptr = imgPtr;
|
||||
for (int32 i = 0; i < w*h; i++) {
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
ir = ptr[0];
|
||||
ig = ptr[1];
|
||||
ib = ptr[2];
|
||||
ia = ptr[3];
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
ptr[0] = (ib*ia + 254) / 255;
|
||||
ptr[1] = (ig*ia + 254) / 255;
|
||||
ptr[2] = (ir*ia + 254) / 255;
|
||||
#else
|
||||
ptr[0] = (ptr[0]*ptr[3] + 254) / 255;
|
||||
ptr[1] = (ptr[1]*ptr[3] + 254) / 255;
|
||||
ptr[2] = (ptr[2]*ptr[3] + 254) / 255;
|
||||
ptr[0] = ia;
|
||||
ptr[1] = (ir*ia + 254) / 255;
|
||||
ptr[2] = (ig*ia + 254) / 255;
|
||||
ptr[3] = (ib*ia + 254) / 255;
|
||||
#endif
|
||||
ptr += 4;
|
||||
}
|
||||
|
|
|
@ -137,9 +137,8 @@ nsDOMUIEvent::GetScreenPoint()
|
|||
return mEvent->refPoint;
|
||||
}
|
||||
|
||||
nsIntRect bounds(mEvent->refPoint, nsIntSize(1, 1));
|
||||
nsIntRect offset;
|
||||
((nsGUIEvent*)mEvent)->widget->WidgetToScreen ( bounds, offset );
|
||||
nsIntPoint offset = mEvent->refPoint +
|
||||
((nsGUIEvent*)mEvent)->widget->WidgetToScreenOffset();
|
||||
nscoord factor = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
|
||||
return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
|
||||
nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
|
||||
|
|
|
@ -593,10 +593,7 @@ nsMouseWheelTransaction::GetScreenPoint(nsGUIEvent* aEvent)
|
|||
{
|
||||
NS_ASSERTION(aEvent, "aEvent is null");
|
||||
NS_ASSERTION(aEvent->widget, "aEvent-widget is null");
|
||||
nsIntRect tmpRect;
|
||||
aEvent->widget->WidgetToScreen(nsIntRect(aEvent->refPoint, nsIntSize(1, 1)),
|
||||
tmpRect);
|
||||
return tmpRect.TopLeft();
|
||||
return aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
PRUint32
|
||||
|
@ -2087,10 +2084,8 @@ nsEventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
|
|||
{
|
||||
// Note that |inDownEvent| could be either a mouse down event or a
|
||||
// synthesized mouse move event.
|
||||
nsIntRect screenPt;
|
||||
inDownEvent->widget->WidgetToScreen(nsIntRect(inDownEvent->refPoint, nsIntSize(1, 1)),
|
||||
screenPt);
|
||||
mGestureDownPoint = screenPt.TopLeft();
|
||||
mGestureDownPoint = inDownEvent->refPoint +
|
||||
inDownEvent->widget->WidgetToScreenOffset();
|
||||
|
||||
inDownFrame->GetContentForEvent(aPresContext, inDownEvent,
|
||||
getter_AddRefs(mGestureDownContent));
|
||||
|
@ -2131,9 +2126,8 @@ nsEventStateManager::FillInEventFromGestureDown(nsMouseEvent* aEvent)
|
|||
// Set the coordinates in the new event to the coordinates of
|
||||
// the old event, adjusted for the fact that the widget might be
|
||||
// different
|
||||
nsIntRect tmpRect(0, 0, 1, 1);
|
||||
aEvent->widget->WidgetToScreen(tmpRect, tmpRect);
|
||||
aEvent->refPoint = mGestureDownPoint - tmpRect.TopLeft();
|
||||
nsIntPoint tmpPoint = aEvent->widget->WidgetToScreenOffset();
|
||||
aEvent->refPoint = mGestureDownPoint - tmpPoint;
|
||||
aEvent->isShift = mGestureDownShift;
|
||||
aEvent->isControl = mGestureDownControl;
|
||||
aEvent->isAlt = mGestureDownAlt;
|
||||
|
@ -2192,10 +2186,7 @@ nsEventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
|
|||
}
|
||||
|
||||
// fire drag gesture if mouse has moved enough
|
||||
nsIntRect tmpRect;
|
||||
aEvent->widget->WidgetToScreen(nsIntRect(aEvent->refPoint, nsIntSize(1, 1)),
|
||||
tmpRect);
|
||||
nsIntPoint pt = tmpRect.TopLeft();
|
||||
nsIntPoint pt = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
|
||||
if (PR_ABS(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
|
||||
PR_ABS(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
|
||||
#ifdef CLICK_HOLD_CONTEXT_MENUS
|
||||
|
|
|
@ -92,30 +92,12 @@ class nsAudioStream
|
|||
// Block until buffered audio data has been consumed.
|
||||
void Drain();
|
||||
|
||||
// Pause sound playback.
|
||||
void Pause();
|
||||
|
||||
// Resume sound playback.
|
||||
void Resume();
|
||||
|
||||
// Return the position (in seconds) of the audio sample currently being
|
||||
// played by the audio hardware.
|
||||
double GetTime();
|
||||
|
||||
private:
|
||||
double mVolume;
|
||||
void* mAudioHandle;
|
||||
int mRate;
|
||||
int mChannels;
|
||||
|
||||
// The byte position in the audio buffer where playback was last paused.
|
||||
PRInt64 mSavedPauseBytes;
|
||||
PRInt64 mPauseBytes;
|
||||
|
||||
float mStartTime;
|
||||
float mPauseTime;
|
||||
PRInt64 mSamplesBuffered;
|
||||
|
||||
SampleFormat mFormat;
|
||||
|
||||
// When a Write() request is made, and the number of samples
|
||||
|
@ -123,7 +105,5 @@ class nsAudioStream
|
|||
// backend, the remaining samples are stored in this variable. They
|
||||
// will be written on the next Write() request.
|
||||
nsTArray<short> mBufferOverflow;
|
||||
|
||||
PRPackedBool mPaused;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -67,10 +67,6 @@ public:
|
|||
// request to return an error. Call on main thread only.
|
||||
void Cancel();
|
||||
|
||||
// Return the number of bytes buffered from the file. This can safely
|
||||
// be read without blocking.
|
||||
PRUint32 Available();
|
||||
|
||||
// Suspend any downloads that are in progress.
|
||||
void Suspend();
|
||||
|
||||
|
|
|
@ -88,7 +88,6 @@ public:
|
|||
virtual nsresult Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes) = 0;
|
||||
virtual nsresult Seek(PRInt32 aWhence, PRInt64 aOffset) = 0;
|
||||
virtual PRInt64 Tell() = 0;
|
||||
virtual PRUint32 Available() = 0;
|
||||
virtual void Cancel() { }
|
||||
virtual nsIPrincipal* GetCurrentPrincipal() = 0;
|
||||
virtual void Suspend() = 0;
|
||||
|
@ -172,10 +171,6 @@ class nsMediaStream
|
|||
// Can be called from any thread.
|
||||
PRInt64 Tell();
|
||||
|
||||
// Return the number of bytes available in the stream that can be
|
||||
// read without blocking. Can be called from any thread.
|
||||
PRUint32 Available();
|
||||
|
||||
// Cancels any currently blocking request and forces that request to
|
||||
// return an error. Call on main thread only.
|
||||
void Cancel();
|
||||
|
|
|
@ -200,6 +200,8 @@ class nsWaveDecoder : public nsMediaDecoder
|
|||
|
||||
virtual void SetTotalBytes(PRInt64 aBytes);
|
||||
|
||||
void PlaybackPositionChanged();
|
||||
|
||||
// Setter for the duration. This is ignored by the wave decoder since it can
|
||||
// compute the duration directly from the wave data.
|
||||
virtual void SetDuration(PRInt64 aDuration);
|
||||
|
@ -268,6 +270,12 @@ private:
|
|||
// state machine will validate the offset against the current media.
|
||||
float mTimeOffset;
|
||||
|
||||
// The current playback position of the media resource in units of
|
||||
// seconds. This is updated every time a block of audio is passed to the
|
||||
// backend (unless an prior update is still pending). It is read and
|
||||
// written from the main thread only.
|
||||
float mCurrentTime;
|
||||
|
||||
// Copy of the current time, duration, and ended state when the state
|
||||
// machine was disposed. Used to respond to time and duration queries
|
||||
// with sensible values after the state machine is destroyed.
|
||||
|
|
|
@ -52,11 +52,6 @@ PRLogModuleInfo* gAudioStreamLog = nsnull;
|
|||
|
||||
#define FAKE_BUFFER_SIZE 176400
|
||||
|
||||
static float CurrentTimeInSeconds()
|
||||
{
|
||||
return PR_IntervalToMilliseconds(PR_IntervalNow()) / 1000.0;
|
||||
}
|
||||
|
||||
void nsAudioStream::InitLibrary()
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -73,12 +68,7 @@ nsAudioStream::nsAudioStream() :
|
|||
mAudioHandle(0),
|
||||
mRate(0),
|
||||
mChannels(0),
|
||||
mSavedPauseBytes(0),
|
||||
mPauseBytes(0),
|
||||
mPauseTime(0.0),
|
||||
mSamplesBuffered(0),
|
||||
mFormat(FORMAT_S16_LE),
|
||||
mPaused(PR_FALSE)
|
||||
mFormat(FORMAT_S16_LE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -87,7 +77,6 @@ void nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aForm
|
|||
mRate = aRate;
|
||||
mChannels = aNumChannels;
|
||||
mFormat = aFormat;
|
||||
mStartTime = CurrentTimeInSeconds();
|
||||
if (sa_stream_create_pcm(reinterpret_cast<sa_stream_t**>(&mAudioHandle),
|
||||
NULL,
|
||||
SA_MODE_WRONLY,
|
||||
|
@ -121,7 +110,6 @@ void nsAudioStream::Write(const void* aBuf, PRUint32 aCount)
|
|||
NS_ABORT_IF_FALSE(aCount % mChannels == 0,
|
||||
"Buffer size must be divisible by channel count");
|
||||
|
||||
mSamplesBuffered += aCount;
|
||||
PRUint32 offset = mBufferOverflow.Length();
|
||||
PRInt32 count = aCount + offset;
|
||||
|
||||
|
@ -214,13 +202,8 @@ void nsAudioStream::SetVolume(float aVolume)
|
|||
|
||||
void nsAudioStream::Drain()
|
||||
{
|
||||
if (!mAudioHandle) {
|
||||
// mSamplesBuffered already accounts for the data in the
|
||||
// mBufferOverflow array.
|
||||
PRUint32 drainTime = (float(mSamplesBuffered) / mRate / mChannels - GetTime()) * 1000.0;
|
||||
PR_Sleep(PR_MillisecondsToInterval(drainTime));
|
||||
if (!mAudioHandle)
|
||||
return;
|
||||
}
|
||||
|
||||
// Write any remaining unwritten sound data in the overflow buffer
|
||||
if (!mBufferOverflow.IsEmpty()) {
|
||||
|
@ -235,69 +218,3 @@ void nsAudioStream::Drain()
|
|||
Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void nsAudioStream::Pause()
|
||||
{
|
||||
if (mPaused)
|
||||
return;
|
||||
|
||||
// Save the elapsed playback time. Used to offset the wall-clock time
|
||||
// when resuming.
|
||||
mPauseTime = CurrentTimeInSeconds() - mStartTime;
|
||||
|
||||
mPaused = PR_TRUE;
|
||||
|
||||
if (!mAudioHandle)
|
||||
return;
|
||||
|
||||
int64_t bytes = 0;
|
||||
#if !defined(WIN32)
|
||||
sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_SOFTWARE, &bytes);
|
||||
#endif
|
||||
mSavedPauseBytes = bytes;
|
||||
|
||||
sa_stream_pause(static_cast<sa_stream_t*>(mAudioHandle));
|
||||
}
|
||||
|
||||
void nsAudioStream::Resume()
|
||||
{
|
||||
if (!mPaused)
|
||||
return;
|
||||
|
||||
// Reset the start time to the current time offset backwards by the
|
||||
// elapsed time saved when the stream paused.
|
||||
mStartTime = CurrentTimeInSeconds() - mPauseTime;
|
||||
|
||||
mPaused = PR_FALSE;
|
||||
|
||||
if (!mAudioHandle)
|
||||
return;
|
||||
|
||||
sa_stream_resume(static_cast<sa_stream_t*>(mAudioHandle));
|
||||
|
||||
#if !defined(WIN32)
|
||||
mPauseBytes += mSavedPauseBytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
double nsAudioStream::GetTime()
|
||||
{
|
||||
// If the audio backend failed to open, emulate the current playback
|
||||
// position using the system clock.
|
||||
if (!mAudioHandle) {
|
||||
if (mPaused) {
|
||||
return mPauseTime;
|
||||
}
|
||||
float curTime = CurrentTimeInSeconds() - mStartTime;
|
||||
float maxTime = float(mSamplesBuffered) / mRate / mChannels;
|
||||
return NS_MIN(curTime, maxTime);
|
||||
}
|
||||
|
||||
int64_t bytes = 0;
|
||||
#if defined(WIN32)
|
||||
sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_HARDWARE, &bytes);
|
||||
#else
|
||||
sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_SOFTWARE, &bytes);
|
||||
#endif
|
||||
return double(bytes + mPauseBytes) / (sizeof(short) * mChannels * mRate);
|
||||
}
|
||||
|
|
|
@ -48,11 +48,6 @@ void nsChannelReader::Cancel()
|
|||
mStream.Cancel();
|
||||
}
|
||||
|
||||
PRUint32 nsChannelReader::Available()
|
||||
{
|
||||
return mStream.Available();
|
||||
}
|
||||
|
||||
OggPlayErrorCode nsChannelReader::initialise(int aBlock)
|
||||
{
|
||||
return E_OGGPLAY_OK;
|
||||
|
|
|
@ -71,7 +71,6 @@ public:
|
|||
virtual nsresult Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes);
|
||||
virtual nsresult Seek(PRInt32 aWhence, PRInt64 aOffset);
|
||||
virtual PRInt64 Tell();
|
||||
virtual PRUint32 Available();
|
||||
virtual void Cancel();
|
||||
virtual nsIPrincipal* GetCurrentPrincipal();
|
||||
virtual void Suspend();
|
||||
|
@ -186,20 +185,6 @@ PRInt64 nsDefaultStreamStrategy::Tell()
|
|||
return mPosition;
|
||||
}
|
||||
|
||||
PRUint32 nsDefaultStreamStrategy::Available()
|
||||
{
|
||||
// The request pulls from the pipe, not the channels input
|
||||
// stream. This allows calling from any thread as the pipe is
|
||||
// threadsafe.
|
||||
nsAutoLock lock(mLock);
|
||||
if (!mPipeInput)
|
||||
return 0;
|
||||
|
||||
PRUint32 count = 0;
|
||||
mPipeInput->Available(&count);
|
||||
return count;
|
||||
}
|
||||
|
||||
void nsDefaultStreamStrategy::Cancel()
|
||||
{
|
||||
if (mListener)
|
||||
|
@ -239,7 +224,6 @@ public:
|
|||
virtual nsresult Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes);
|
||||
virtual nsresult Seek(PRInt32 aWhence, PRInt64 aOffset);
|
||||
virtual PRInt64 Tell();
|
||||
virtual PRUint32 Available();
|
||||
virtual nsIPrincipal* GetCurrentPrincipal();
|
||||
virtual void Suspend();
|
||||
virtual void Resume();
|
||||
|
@ -419,17 +403,6 @@ PRInt64 nsFileStreamStrategy::Tell()
|
|||
return offset;
|
||||
}
|
||||
|
||||
PRUint32 nsFileStreamStrategy::Available()
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
if (!mInput)
|
||||
return 0;
|
||||
|
||||
PRUint32 count = 0;
|
||||
mInput->Available(&count);
|
||||
return count;
|
||||
}
|
||||
|
||||
nsIPrincipal* nsFileStreamStrategy::GetCurrentPrincipal()
|
||||
{
|
||||
return mPrincipal;
|
||||
|
@ -463,7 +436,6 @@ public:
|
|||
virtual nsresult Read(char* aBuffer, PRUint32 aCount, PRUint32* aBytes);
|
||||
virtual nsresult Seek(PRInt32 aWhence, PRInt64 aOffset);
|
||||
virtual PRInt64 Tell();
|
||||
virtual PRUint32 Available();
|
||||
virtual void Cancel();
|
||||
virtual nsIPrincipal* GetCurrentPrincipal();
|
||||
virtual void Suspend();
|
||||
|
@ -763,12 +735,13 @@ nsresult nsHttpStreamStrategy::Seek(PRInt32 aWhence, PRInt64 aOffset)
|
|||
bytesRead += bytes;
|
||||
} while (bytesRead != bytesAhead);
|
||||
|
||||
// We don't need to notify the decoder here that we seeked. It will
|
||||
// look like we just read ahead a bit. In fact, we mustn't tell
|
||||
// the decoder that we seeked, since the seek notification might
|
||||
// race with the "data downloaded" notification after the data was
|
||||
// written into the pipe, so that the seek notification
|
||||
// happens *first*, hopelessly confusing the decoder.
|
||||
// We don't need to notify the decoder here that we seeked, just that
|
||||
// we read ahead. In fact, we mustn't tell the decoder that we seeked,
|
||||
// since the seek notification might race with the "data downloaded"
|
||||
// notification after the data was written into the pipe, so that the
|
||||
// seek notification happens *first*, hopelessly confusing the
|
||||
// decoder.
|
||||
mDecoder->NotifyBytesConsumed(bytesRead);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
@ -795,20 +768,6 @@ PRInt64 nsHttpStreamStrategy::Tell()
|
|||
return mAtEOF ? mDecoder->GetStatistics().mTotalBytes : mPosition;
|
||||
}
|
||||
|
||||
PRUint32 nsHttpStreamStrategy::Available()
|
||||
{
|
||||
// The request pulls from the pipe, not the channels input
|
||||
// stream. This allows calling from any thread as the pipe is
|
||||
// threadsafe.
|
||||
nsAutoLock lock(mLock);
|
||||
if (!mPipeInput)
|
||||
return 0;
|
||||
|
||||
PRUint32 count = 0;
|
||||
mPipeInput->Available(&count);
|
||||
return count;
|
||||
}
|
||||
|
||||
void nsHttpStreamStrategy::Cancel()
|
||||
{
|
||||
mCancelled = PR_TRUE;
|
||||
|
@ -909,11 +868,6 @@ PRInt64 nsMediaStream::Tell()
|
|||
return mStreamStrategy->Tell();
|
||||
}
|
||||
|
||||
PRUint32 nsMediaStream::Available()
|
||||
{
|
||||
return mStreamStrategy->Available();
|
||||
}
|
||||
|
||||
void nsMediaStream::Cancel()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(),
|
||||
|
|
|
@ -54,9 +54,13 @@
|
|||
// Maximum number of seconds to wait when buffering.
|
||||
#define BUFFERING_TIMEOUT 3
|
||||
|
||||
// The number of seconds of buffer data before buffering happens
|
||||
// based on current playback rate.
|
||||
#define BUFFERING_SECONDS_LOW_WATER_MARK 1
|
||||
// Duration the playback loop will sleep after refilling the backend's audio
|
||||
// buffers. The loop's goal is to keep AUDIO_BUFFER_LENGTH milliseconds of
|
||||
// audio buffered to allow time to refill before the backend underruns.
|
||||
// Should be a multiple of 10 to deal with poor timer granularity on some
|
||||
// platforms.
|
||||
#define AUDIO_BUFFER_WAKEUP 100
|
||||
#define AUDIO_BUFFER_LENGTH (2 * AUDIO_BUFFER_WAKEUP)
|
||||
|
||||
// Magic values that identify RIFF chunks we're interested in.
|
||||
#define RIFF_CHUNK_MAGIC 0x52494646
|
||||
|
@ -74,13 +78,21 @@
|
|||
// extended (for non-PCM encodings), but we skip any extended data.
|
||||
#define WAVE_FORMAT_CHUNK_SIZE 16
|
||||
|
||||
// Size of format chunk including RIFF chunk header.
|
||||
#define WAVE_FORMAT_SIZE (RIFF_CHUNK_HEADER_SIZE + WAVE_FORMAT_CHUNK_SIZE)
|
||||
|
||||
// PCM encoding type from format chunk. Linear PCM is the only encoding
|
||||
// supported by nsAudioStream.
|
||||
#define WAVE_FORMAT_ENCODING_PCM 1
|
||||
|
||||
enum State {
|
||||
STATE_LOADING_METADATA,
|
||||
STATE_BUFFERING,
|
||||
STATE_PLAYING,
|
||||
STATE_SEEKING,
|
||||
STATE_PAUSED,
|
||||
STATE_ENDED,
|
||||
STATE_ERROR,
|
||||
STATE_SHUTDOWN
|
||||
};
|
||||
|
||||
/*
|
||||
A single nsWaveStateMachine instance is owned by the decoder, created
|
||||
on-demand at load time. Upon creation, the decoder immediately
|
||||
|
@ -101,17 +113,6 @@
|
|||
class nsWaveStateMachine : public nsRunnable
|
||||
{
|
||||
public:
|
||||
enum State {
|
||||
STATE_LOADING_METADATA,
|
||||
STATE_BUFFERING,
|
||||
STATE_PLAYING,
|
||||
STATE_SEEKING,
|
||||
STATE_PAUSED,
|
||||
STATE_ENDED,
|
||||
STATE_ERROR,
|
||||
STATE_SHUTDOWN
|
||||
};
|
||||
|
||||
nsWaveStateMachine(nsWaveDecoder* aDecoder, nsMediaStream* aStream,
|
||||
PRUint32 aBufferWaitTime, float aInitialVolume);
|
||||
~nsWaveStateMachine();
|
||||
|
@ -148,18 +149,9 @@ public:
|
|||
// Returns true if the state machine has reached the end of playback. Threadsafe.
|
||||
PRBool IsEnded();
|
||||
|
||||
// Called by the decoder to indicate that the media stream has closed.
|
||||
// aAtEnd is true if we read to the end of the file.
|
||||
void StreamEnded(PRBool aAtEnd);
|
||||
|
||||
// Main state machine loop. Runs forever, until shutdown state is reached.
|
||||
NS_IMETHOD Run();
|
||||
|
||||
// Called by the decoder when the SeekStarted event runs. This ensures
|
||||
// the current time offset of the state machine is updated to the new seek
|
||||
// position at the appropriate time.
|
||||
void UpdateTimeOffset(float aTime);
|
||||
|
||||
// Called by the decoder, on the main thread.
|
||||
nsMediaDecoder::Statistics GetStatistics();
|
||||
|
||||
|
@ -177,13 +169,19 @@ public:
|
|||
// Called by the main thread only
|
||||
nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus();
|
||||
|
||||
private:
|
||||
// Clear the flag indicating that a playback position change event is
|
||||
// currently queued and return the current time. This is called from the
|
||||
// main thread.
|
||||
float GetTimeForPositionChange();
|
||||
|
||||
private:
|
||||
// Returns PR_TRUE if we're in shutdown state. Threadsafe.
|
||||
PRBool IsShutdown();
|
||||
|
||||
// Reads from the media stream. Returns PR_FALSE on failure or EOF.
|
||||
PRBool ReadAll(char* aBuf, PRUint32 aSize);
|
||||
// Reads from the media stream. Returns PR_FALSE on failure or EOF. If
|
||||
// aBytesRead is non-null, the number of bytes read will be returned via
|
||||
// this.
|
||||
PRBool ReadAll(char* aBuf, PRInt64 aSize, PRInt64* aBytesRead);
|
||||
|
||||
// Change the current state and wake the playback thread if it is waiting
|
||||
// on mMonitor. Used by public member functions called from both threads,
|
||||
|
@ -200,6 +198,11 @@ private:
|
|||
// the stream data is a RIFF bitstream containing WAVE data.
|
||||
PRBool LoadRIFFChunk();
|
||||
|
||||
// Read forward in the stream until aWantedChunk is found. Return chunk
|
||||
// size in aChunkSize. aChunkSize will not be rounded up if the chunk
|
||||
// size is odd.
|
||||
PRBool ScanForwardUntil(PRUint32 aWantedChunk, PRUint32* aChunkSize);
|
||||
|
||||
// Scan forward in the stream looking for the WAVE format chunk. If
|
||||
// found, parse and validate required metadata, then use it to set
|
||||
// mSampleRate, mChannels, mSampleSize, and mSampleFormat.
|
||||
|
@ -210,29 +213,40 @@ private:
|
|||
// mWavePCMOffset.
|
||||
PRBool FindDataOffset();
|
||||
|
||||
// Return the length of the PCM data.
|
||||
PRInt64 GetDataLength();
|
||||
|
||||
// Fire a PlaybackPositionChanged event. If aCoalesce is true and a
|
||||
// PlaybackPositionChanged event is already pending, an event is not
|
||||
// fired.
|
||||
void FirePositionChanged(PRBool aCoalesce);
|
||||
|
||||
// Returns the number of seconds that aBytes represents based on the
|
||||
// current audio parameters. e.g. 176400 bytes is 1 second at 16-bit
|
||||
// stereo 44.1kHz.
|
||||
float BytesToTime(PRUint32 aBytes) const
|
||||
float BytesToTime(PRInt64 aBytes) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mMetadataValid, "Requires valid metadata");
|
||||
NS_ABORT_IF_FALSE(aBytes >= 0, "Must be >= 0");
|
||||
return float(aBytes) / mSampleRate / mSampleSize;
|
||||
}
|
||||
|
||||
// Returns the number of bytes that aTime represents based on the current
|
||||
// audio parameters. e.g. 1 second is 176400 bytes at 16-bit stereo
|
||||
// 44.1kHz.
|
||||
PRUint32 TimeToBytes(float aTime) const
|
||||
PRInt64 TimeToBytes(float aTime) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mMetadataValid, "Requires valid metadata");
|
||||
return PRUint32(aTime * mSampleRate * mSampleSize);
|
||||
NS_ABORT_IF_FALSE(aTime >= 0.0, "Must be >= 0");
|
||||
return RoundDownToSample(PRInt64(aTime * mSampleRate * mSampleSize));
|
||||
}
|
||||
|
||||
// Rounds aBytes down to the nearest complete sample. Assumes beginning
|
||||
// of byte range is already sample aligned by caller.
|
||||
PRUint32 RoundDownToSample(PRUint32 aBytes) const
|
||||
PRInt64 RoundDownToSample(PRInt64 aBytes) const
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mMetadataValid, "Requires valid metadata");
|
||||
NS_ABORT_IF_FALSE(aBytes >= 0, "Must be >= 0");
|
||||
return aBytes - (aBytes % mSampleSize);
|
||||
}
|
||||
|
||||
|
@ -258,16 +272,13 @@ private:
|
|||
// Maximum time in milliseconds to spend waiting for data during buffering.
|
||||
PRUint32 mBufferingWait;
|
||||
|
||||
// Maximum number of bytes to wait for during buffering.
|
||||
PRUint32 mBufferingBytes;
|
||||
|
||||
// Machine time that buffering began, used with mBufferingWait to time out
|
||||
// buffering.
|
||||
PRIntervalTime mBufferingStart;
|
||||
|
||||
// Maximum number of bytes mAudioStream buffers internally. Used to
|
||||
// calculate next wakeup time after refilling audio buffers.
|
||||
PRUint32 mAudioBufferSize;
|
||||
// Download position where we should stop buffering. Only accessed
|
||||
// in the decoder thread.
|
||||
PRInt64 mBufferingEndOffset;
|
||||
|
||||
/*
|
||||
Metadata extracted from the WAVE header. Used to initialize the audio
|
||||
|
@ -289,11 +300,11 @@ private:
|
|||
|
||||
// Size of PCM data stored in the WAVE as reported by the data chunk in
|
||||
// the media.
|
||||
PRUint32 mWaveLength;
|
||||
PRInt64 mWaveLength;
|
||||
|
||||
// Start offset of the PCM data in the media stream. Extends mWaveLength
|
||||
// bytes.
|
||||
PRUint32 mWavePCMOffset;
|
||||
PRInt64 mWavePCMOffset;
|
||||
|
||||
/*
|
||||
All member variables following this comment are accessed by both
|
||||
|
@ -326,15 +337,9 @@ private:
|
|||
// Volume that the audio backend will be initialized with.
|
||||
float mInitialVolume;
|
||||
|
||||
// Time position (in seconds) to offset current time from audio stream.
|
||||
// Set when the seek started event runs and when the stream is closed
|
||||
// during shutdown.
|
||||
float mTimeOffset;
|
||||
|
||||
// Set when StreamEnded has fired to indicate that we should not expect
|
||||
// any more data from mStream than what is already buffered (i.e. what
|
||||
// Available() reports).
|
||||
PRPackedBool mExpectMoreData;
|
||||
// Playback position (in bytes), updated as the playback loop runs and
|
||||
// upon seeking.
|
||||
PRInt64 mTimeOffset;
|
||||
|
||||
// Time position (in seconds) to seek to. Set by Seek(float).
|
||||
float mSeekTime;
|
||||
|
@ -343,6 +348,12 @@ private:
|
|||
// mChannels, mSampleSize, mSampleFormat, mWaveLength, mWavePCMOffset must
|
||||
// check this flag before assuming the values are valid.
|
||||
PRPackedBool mMetadataValid;
|
||||
|
||||
// True if an event to notify about a change in the playback position has
|
||||
// been queued, but not yet run. It is set to false when the event is
|
||||
// run. This allows coalescing of these events as they can be produced
|
||||
// many times per second.
|
||||
PRPackedBool mPositionChangeQueued;
|
||||
};
|
||||
|
||||
nsWaveStateMachine::nsWaveStateMachine(nsWaveDecoder* aDecoder, nsMediaStream* aStream,
|
||||
|
@ -350,9 +361,8 @@ nsWaveStateMachine::nsWaveStateMachine(nsWaveDecoder* aDecoder, nsMediaStream* a
|
|||
: mDecoder(aDecoder),
|
||||
mStream(aStream),
|
||||
mBufferingWait(aBufferWaitTime),
|
||||
mBufferingBytes(0),
|
||||
mBufferingStart(0),
|
||||
mAudioBufferSize(0),
|
||||
mBufferingEndOffset(0),
|
||||
mSampleRate(0),
|
||||
mChannels(0),
|
||||
mSampleSize(0),
|
||||
|
@ -366,10 +376,10 @@ nsWaveStateMachine::nsWaveStateMachine(nsWaveDecoder* aDecoder, nsMediaStream* a
|
|||
mDownloadPosition(0),
|
||||
mPlaybackPosition(0),
|
||||
mInitialVolume(aInitialVolume),
|
||||
mTimeOffset(0.0),
|
||||
mExpectMoreData(PR_TRUE),
|
||||
mTimeOffset(0),
|
||||
mSeekTime(0.0),
|
||||
mMetadataValid(PR_FALSE)
|
||||
mMetadataValid(PR_FALSE),
|
||||
mPositionChangeQueued(PR_FALSE)
|
||||
{
|
||||
mMonitor = nsAutoMonitor::NewMonitor("nsWaveStateMachine");
|
||||
mDownloadStatistics.Start(PR_IntervalNow());
|
||||
|
@ -449,14 +459,7 @@ nsWaveStateMachine::GetDuration()
|
|||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
if (mMetadataValid) {
|
||||
PRUint32 length = mWaveLength;
|
||||
// If the decoder has a valid content length, and it's shorter than the
|
||||
// expected length of the PCM data, calculate the playback duration from
|
||||
// the content length rather than the expected PCM data length.
|
||||
if (mTotalBytes >= 0 && mTotalBytes - mWavePCMOffset < length) {
|
||||
length = mTotalBytes - mWavePCMOffset;
|
||||
}
|
||||
return BytesToTime(length);
|
||||
return BytesToTime(GetDataLength());
|
||||
}
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
|
@ -465,11 +468,10 @@ float
|
|||
nsWaveStateMachine::GetCurrentTime()
|
||||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
double time = 0.0;
|
||||
if (mAudioStream) {
|
||||
time = mAudioStream->GetTime();
|
||||
if (mMetadataValid) {
|
||||
return BytesToTime(mTimeOffset);
|
||||
}
|
||||
return float(time + mTimeOffset);
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -486,30 +488,25 @@ nsWaveStateMachine::IsEnded()
|
|||
return mState == STATE_ENDED || mState == STATE_SHUTDOWN;
|
||||
}
|
||||
|
||||
void
|
||||
nsWaveStateMachine::StreamEnded(PRBool aAtEnd)
|
||||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
mExpectMoreData = PR_FALSE;
|
||||
|
||||
// If we know the content length, set the bytes downloaded to this
|
||||
// so the final progress event gets the correct final value.
|
||||
if (mTotalBytes >= 0) {
|
||||
mDownloadPosition = mTotalBytes;
|
||||
}
|
||||
}
|
||||
|
||||
nsHTMLMediaElement::NextFrameStatus
|
||||
nsWaveStateMachine::GetNextFrameStatus()
|
||||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
if (mPlaybackPosition < mDownloadPosition)
|
||||
return nsHTMLMediaElement::NEXT_FRAME_AVAILABLE;
|
||||
if (mState == STATE_BUFFERING)
|
||||
return nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE_BUFFERING;
|
||||
if (mPlaybackPosition < mDownloadPosition)
|
||||
return nsHTMLMediaElement::NEXT_FRAME_AVAILABLE;
|
||||
return nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
|
||||
float
|
||||
nsWaveStateMachine::GetTimeForPositionChange()
|
||||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
mPositionChangeQueued = PR_FALSE;
|
||||
return GetCurrentTime();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWaveStateMachine::Run()
|
||||
{
|
||||
|
@ -552,10 +549,12 @@ nsWaveStateMachine::Run()
|
|||
case STATE_BUFFERING: {
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
if ((PR_IntervalToMilliseconds(now - mBufferingStart) < mBufferingWait) &&
|
||||
mStream->Available() < mBufferingBytes) {
|
||||
LOG(PR_LOG_DEBUG, ("Buffering data until %d bytes or %d milliseconds\n",
|
||||
mBufferingBytes - mStream->Available(),
|
||||
mBufferingWait - (now - mBufferingStart)));
|
||||
mDownloadPosition < mBufferingEndOffset &&
|
||||
(mTotalBytes < 0 || mDownloadPosition < mTotalBytes)) {
|
||||
LOG(PR_LOG_DEBUG,
|
||||
("In buffering: buffering data until %d bytes available or %d milliseconds\n",
|
||||
PRUint32(mBufferingEndOffset - mDownloadPosition),
|
||||
mBufferingWait - (PR_IntervalToMilliseconds(now - mBufferingStart))));
|
||||
monitor.Wait(PR_MillisecondsToInterval(1000));
|
||||
} else {
|
||||
ChangeState(mNextState);
|
||||
|
@ -570,86 +569,102 @@ nsWaveStateMachine::Run()
|
|||
case STATE_PLAYING: {
|
||||
if (!mAudioStream) {
|
||||
OpenAudioStream();
|
||||
} else {
|
||||
mAudioStream->Resume();
|
||||
if (!mAudioStream) {
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mStream->Available() < mSampleSize) {
|
||||
if (mExpectMoreData) {
|
||||
// Buffer until mBufferingWait milliseconds of data is available.
|
||||
mBufferingBytes = TimeToBytes(float(mBufferingWait) / 1000.0);
|
||||
mBufferingStart = PR_IntervalNow();
|
||||
PRUint32 startTime = PR_IntervalToMilliseconds(PR_IntervalNow());
|
||||
startTime -= AUDIO_BUFFER_LENGTH;
|
||||
PRIntervalTime lastWakeup = PR_MillisecondsToInterval(startTime);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, UpdateReadyStateForData);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
do {
|
||||
PRIntervalTime now = PR_IntervalNow();
|
||||
PRInt32 sleepTime = PR_IntervalToMilliseconds(now - lastWakeup);
|
||||
lastWakeup = now;
|
||||
|
||||
ChangeState(STATE_BUFFERING);
|
||||
} else {
|
||||
// Media stream has ended and there is less data available than a
|
||||
// single sample so end playback.
|
||||
// We aim to have AUDIO_BUFFER_LENGTH milliseconds of audio
|
||||
// buffered, but only sleep for AUDIO_BUFFER_WAKEUP milliseconds
|
||||
// (waking early to refill before the backend underruns). Since we
|
||||
// wake early, we only buffer sleepTime milliseconds of audio since
|
||||
// there is still AUDIO_BUFFER_LENGTH - sleepTime milliseconds of
|
||||
// audio buffered.
|
||||
PRInt32 targetTime = AUDIO_BUFFER_LENGTH;
|
||||
if (sleepTime < targetTime) {
|
||||
targetTime = sleepTime;
|
||||
}
|
||||
|
||||
PRInt64 len = TimeToBytes(float(targetTime) / 1000.0f);
|
||||
|
||||
PRInt64 leftToPlay = GetDataLength() - mTimeOffset;
|
||||
if (leftToPlay <= len) {
|
||||
len = leftToPlay;
|
||||
ChangeState(STATE_ENDED);
|
||||
}
|
||||
} else {
|
||||
// Assuming enough data is available from the network, we aim to
|
||||
// completely fill the audio backend's buffers with data. This
|
||||
// allows us plenty of time to wake up and refill the buffers
|
||||
// without an underrun occurring.
|
||||
PRUint32 sampleSize = mSampleFormat == nsAudioStream::FORMAT_U8 ? 1 : 2;
|
||||
PRUint32 len = RoundDownToSample(NS_MIN(mStream->Available(),
|
||||
PRUint32(mAudioStream->Available() * sampleSize)));
|
||||
if (len) {
|
||||
nsAutoArrayPtr<char> buf(new char[len]);
|
||||
PRUint32 got = 0;
|
||||
|
||||
PRInt64 available = mDownloadPosition - mPlaybackPosition;
|
||||
|
||||
// don't buffer if we're at the end of the stream
|
||||
if (mState != STATE_ENDED && available < len) {
|
||||
mBufferingStart = PR_IntervalNow();
|
||||
mBufferingEndOffset = mDownloadPosition + TimeToBytes(float(mBufferingWait) / 1000.0f);
|
||||
mNextState = mState;
|
||||
ChangeState(STATE_BUFFERING);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, UpdateReadyStateForData);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
nsAutoArrayPtr<char> buf(new char[size_t(len)]);
|
||||
PRInt64 got = 0;
|
||||
|
||||
monitor.Exit();
|
||||
if (NS_FAILED(mStream->Read(buf.get(), len, &got))) {
|
||||
NS_WARNING("Stream read failed");
|
||||
}
|
||||
PRBool ok = ReadAll(buf.get(), len, &got);
|
||||
PRInt64 streamPos = mStream->Tell();
|
||||
monitor.Enter();
|
||||
|
||||
if (got == 0) {
|
||||
// Reached EOF.
|
||||
if (!ok) {
|
||||
ChangeState(STATE_ENDED);
|
||||
if (got == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got less data than requested, go ahead and write what we
|
||||
// got to the audio hardware. It's unlikely that this can happen
|
||||
// since we never attempt to read more data than what is already
|
||||
// buffered.
|
||||
len = RoundDownToSample(got);
|
||||
|
||||
// Calculate difference between the current media stream position
|
||||
// and the expected end of the PCM data.
|
||||
PRInt64 endDelta = mWavePCMOffset + mWaveLength - mStream->Tell();
|
||||
PRInt64 endDelta = mWavePCMOffset + mWaveLength - streamPos;
|
||||
if (endDelta < 0) {
|
||||
// Read past the end of PCM data. Adjust len to avoid playing
|
||||
// Read past the end of PCM data. Adjust got to avoid playing
|
||||
// back trailing data.
|
||||
len -= -endDelta;
|
||||
if (RoundDownToSample(len) != len) {
|
||||
NS_WARNING("PCM data does not end with complete sample");
|
||||
len = RoundDownToSample(len);
|
||||
}
|
||||
got -= -endDelta;
|
||||
ChangeState(STATE_ENDED);
|
||||
}
|
||||
|
||||
PRUint32 lengthInSamples = len;
|
||||
if (mSampleFormat == nsAudioStream::FORMAT_S16_LE) {
|
||||
lengthInSamples /= sizeof(short);
|
||||
if (mState == STATE_ENDED) {
|
||||
got = RoundDownToSample(got);
|
||||
}
|
||||
|
||||
PRUint32 sampleSize = mSampleFormat == nsAudioStream::FORMAT_U8 ? 1 : 2;
|
||||
NS_ABORT_IF_FALSE(got % sampleSize == 0, "Must write complete samples");
|
||||
PRUint32 lengthInSamples = got / sampleSize;
|
||||
|
||||
monitor.Exit();
|
||||
mAudioStream->Write(buf.get(), lengthInSamples);
|
||||
monitor.Enter();
|
||||
|
||||
mTimeOffset += got;
|
||||
FirePositionChanged(PR_FALSE);
|
||||
}
|
||||
|
||||
// To avoid waking up too frequently to top up these buffers,
|
||||
// calculate the duration of the currently buffered data and sleep
|
||||
// until most of the buffered data has been consumed. We can't
|
||||
// sleep for the entire duration because we might not wake up in
|
||||
// time to refill the buffers, causing an underrun. To avoid this,
|
||||
// wake up when approximately half the buffered data has been
|
||||
// consumed. This could be made smarter, but at least avoids waking
|
||||
// up frequently to perform small buffer refills.
|
||||
float nextWakeup = BytesToTime(mAudioBufferSize - mAudioStream->Available() * sizeof(short)) * 1000.0 / 2.0;
|
||||
monitor.Wait(PR_MillisecondsToInterval(PRUint32(nextWakeup)));
|
||||
}
|
||||
if (mState == STATE_PLAYING) {
|
||||
monitor.Wait(PR_MillisecondsToInterval(AUDIO_BUFFER_WAKEUP));
|
||||
}
|
||||
} while (mState == STATE_PLAYING);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -672,7 +687,9 @@ nsWaveStateMachine::Run()
|
|||
|
||||
// Calculate relative offset within PCM data.
|
||||
PRInt64 position = RoundDownToSample(TimeToBytes(seekTime));
|
||||
NS_ABORT_IF_FALSE(position >= 0 && position <= mWaveLength, "Invalid seek position");
|
||||
NS_ABORT_IF_FALSE(position >= 0 && position <= GetDataLength(), "Invalid seek position");
|
||||
|
||||
mTimeOffset = position;
|
||||
|
||||
// If position==0, instead of seeking to position+mWavePCMOffset,
|
||||
// we want to first seek to 0 before seeking to
|
||||
|
@ -704,12 +721,6 @@ nsWaveStateMachine::Run()
|
|||
break;
|
||||
}
|
||||
|
||||
monitor.Exit();
|
||||
nsCOMPtr<nsIRunnable> stopEvent =
|
||||
NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, SeekingStopped);
|
||||
NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC);
|
||||
monitor.Enter();
|
||||
|
||||
if (mState == STATE_SEEKING && mSeekTime == seekTime) {
|
||||
// Special case: if a seek was requested during metadata load,
|
||||
// mNextState will have been clobbered. This can only happen when
|
||||
|
@ -722,29 +733,30 @@ nsWaveStateMachine::Run()
|
|||
}
|
||||
ChangeState(nextState);
|
||||
}
|
||||
|
||||
FirePositionChanged(PR_TRUE);
|
||||
|
||||
monitor.Exit();
|
||||
nsCOMPtr<nsIRunnable> stopEvent =
|
||||
NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, SeekingStopped);
|
||||
NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC);
|
||||
monitor.Enter();
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_PAUSED:
|
||||
if (mAudioStream) {
|
||||
mAudioStream->Pause();
|
||||
}
|
||||
monitor.Wait();
|
||||
break;
|
||||
|
||||
case STATE_ENDED:
|
||||
FirePositionChanged(PR_TRUE);
|
||||
|
||||
if (mAudioStream) {
|
||||
monitor.Exit();
|
||||
mAudioStream->Drain();
|
||||
monitor.Enter();
|
||||
mTimeOffset += mAudioStream->GetTime();
|
||||
}
|
||||
|
||||
// Dispose the audio stream early (before SHUTDOWN) so that
|
||||
// GetCurrentTime no longer attempts to query the audio backend for
|
||||
// stream time.
|
||||
CloseAudioStream();
|
||||
|
||||
if (mState != STATE_SHUTDOWN) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, PlaybackEnded);
|
||||
|
@ -765,9 +777,6 @@ nsWaveStateMachine::Run()
|
|||
break;
|
||||
|
||||
case STATE_SHUTDOWN:
|
||||
if (mAudioStream) {
|
||||
mTimeOffset += mAudioStream->GetTime();
|
||||
}
|
||||
CloseAudioStream();
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -776,20 +785,61 @@ nsWaveStateMachine::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsWaveStateMachine::UpdateTimeOffset(float aTime)
|
||||
#if defined(DEBUG)
|
||||
static PRBool
|
||||
IsValidStateTransition(State aStartState, State aEndState)
|
||||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
mTimeOffset = NS_MIN(aTime, GetDuration());
|
||||
if (mTimeOffset < 0.0) {
|
||||
mTimeOffset = 0.0;
|
||||
if (aEndState == STATE_SHUTDOWN) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
if (aStartState == aEndState) {
|
||||
LOG(PR_LOG_WARNING, ("Transition to current state requested"));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
switch (aStartState) {
|
||||
case STATE_LOADING_METADATA:
|
||||
if (aEndState == STATE_PLAYING || aEndState == STATE_SEEKING ||
|
||||
aEndState == STATE_PAUSED || aEndState == STATE_ERROR)
|
||||
return PR_TRUE;
|
||||
break;
|
||||
case STATE_BUFFERING:
|
||||
if (aEndState == STATE_PLAYING || aEndState == STATE_PAUSED ||
|
||||
aEndState == STATE_SEEKING)
|
||||
return PR_TRUE;
|
||||
break;
|
||||
case STATE_PLAYING:
|
||||
if (aEndState == STATE_BUFFERING || aEndState == STATE_SEEKING ||
|
||||
aEndState == STATE_ENDED || aEndState == STATE_PAUSED)
|
||||
return PR_TRUE;
|
||||
break;
|
||||
case STATE_SEEKING:
|
||||
if (aEndState == STATE_PLAYING || aEndState == STATE_PAUSED)
|
||||
return PR_TRUE;
|
||||
break;
|
||||
case STATE_PAUSED:
|
||||
if (aEndState == STATE_PLAYING || aEndState == STATE_SEEKING)
|
||||
return PR_TRUE;
|
||||
break;
|
||||
case STATE_ENDED:
|
||||
case STATE_ERROR:
|
||||
case STATE_SHUTDOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
LOG(PR_LOG_ERROR, ("Invalid state transition from %d to %d", aStartState, aEndState));
|
||||
return PR_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsWaveStateMachine::ChangeState(State aState)
|
||||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
#if defined(DEBUG)
|
||||
NS_ABORT_IF_FALSE(IsValidStateTransition(mState, aState), "Invalid state transition");
|
||||
#endif
|
||||
mState = aState;
|
||||
monitor.NotifyAll();
|
||||
}
|
||||
|
@ -805,7 +855,6 @@ nsWaveStateMachine::OpenAudioStream()
|
|||
"Attempting to initialize audio stream with invalid metadata");
|
||||
mAudioStream->Init(mChannels, mSampleRate, mSampleFormat);
|
||||
mAudioStream->SetVolume(mInitialVolume);
|
||||
mAudioBufferSize = mAudioStream->Available() * sizeof(short);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -835,7 +884,8 @@ nsWaveStateMachine::GetStatistics()
|
|||
}
|
||||
|
||||
void
|
||||
nsWaveStateMachine::SetTotalBytes(PRInt64 aBytes) {
|
||||
nsWaveStateMachine::SetTotalBytes(PRInt64 aBytes)
|
||||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
mTotalBytes = aBytes;
|
||||
}
|
||||
|
@ -913,18 +963,25 @@ nsWaveStateMachine::IsShutdown()
|
|||
}
|
||||
|
||||
PRBool
|
||||
nsWaveStateMachine::ReadAll(char* aBuf, PRUint32 aSize)
|
||||
nsWaveStateMachine::ReadAll(char* aBuf, PRInt64 aSize, PRInt64* aBytesRead = nsnull)
|
||||
{
|
||||
PRUint32 got = 0;
|
||||
if (aBytesRead) {
|
||||
*aBytesRead = 0;
|
||||
}
|
||||
do {
|
||||
PRUint32 read = 0;
|
||||
if (NS_FAILED(mStream->Read(aBuf + got, aSize - got, &read))) {
|
||||
NS_WARNING("Stream read failed");
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (IsShutdown())
|
||||
if (IsShutdown() || read == 0) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
got += read;
|
||||
if (aBytesRead) {
|
||||
*aBytesRead = got;
|
||||
}
|
||||
} while (got != aSize);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -958,28 +1015,59 @@ nsWaveStateMachine::LoadRIFFChunk()
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsWaveStateMachine::ScanForwardUntil(PRUint32 aWantedChunk, PRUint32* aChunkSize)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aChunkSize);
|
||||
*aChunkSize = 0;
|
||||
|
||||
for (;;) {
|
||||
char chunkHeader[8];
|
||||
const char* p = chunkHeader;
|
||||
|
||||
if (!ReadAll(chunkHeader, sizeof(chunkHeader))) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 magic = ReadUint32BE(&p);
|
||||
PRUint32 size = ReadUint32LE(&p);
|
||||
|
||||
if (magic == aWantedChunk) {
|
||||
*aChunkSize = size;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// RIFF chunks are two-byte aligned, so round up if necessary.
|
||||
size += size % 2;
|
||||
|
||||
nsAutoArrayPtr<char> chunk(new char[size]);
|
||||
if (!ReadAll(chunk.get(), size)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsWaveStateMachine::LoadFormatChunk()
|
||||
{
|
||||
PRUint32 rate, channels, sampleSize, sampleFormat;
|
||||
char waveFormat[WAVE_FORMAT_SIZE];
|
||||
PRUint32 fmtSize, rate, channels, sampleSize, sampleFormat;
|
||||
char waveFormat[WAVE_FORMAT_CHUNK_SIZE];
|
||||
const char* p = waveFormat;
|
||||
|
||||
// RIFF chunks are always word (two byte) aligned.
|
||||
NS_ABORT_IF_FALSE(mStream->Tell() % 2 == 0,
|
||||
"LoadFormatChunk called with unaligned stream");
|
||||
|
||||
// The "format" chunk may not directly follow the "riff" chunk, so skip
|
||||
// over any intermediate chunks.
|
||||
if (!ScanForwardUntil(FRMT_CHUNK_MAGIC, &fmtSize)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (!ReadAll(waveFormat, sizeof(waveFormat))) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (ReadUint32BE(&p) != FRMT_CHUNK_MAGIC) {
|
||||
NS_WARNING("Expected format chunk");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 fmtsize = ReadUint32LE(&p);
|
||||
|
||||
if (ReadUint16LE(&p) != WAVE_FORMAT_ENCODING_PCM) {
|
||||
NS_WARNING("WAVE is not uncompressed PCM, compressed encodings are not supported");
|
||||
return PR_FALSE;
|
||||
|
@ -1000,7 +1088,7 @@ nsWaveStateMachine::LoadFormatChunk()
|
|||
// extension size of 0 bytes. Be polite and handle this rather than
|
||||
// considering the file invalid. This code skips any extension of the
|
||||
// "format" chunk.
|
||||
if (fmtsize > WAVE_FORMAT_CHUNK_SIZE) {
|
||||
if (fmtSize > WAVE_FORMAT_CHUNK_SIZE) {
|
||||
char extLength[2];
|
||||
const char* p = extLength;
|
||||
|
||||
|
@ -1009,7 +1097,7 @@ nsWaveStateMachine::LoadFormatChunk()
|
|||
}
|
||||
|
||||
PRUint16 extra = ReadUint16LE(&p);
|
||||
if (fmtsize - (WAVE_FORMAT_CHUNK_SIZE + 2) != extra) {
|
||||
if (fmtSize - (WAVE_FORMAT_CHUNK_SIZE + 2) != extra) {
|
||||
NS_WARNING("Invalid extended format chunk size");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
@ -1062,33 +1150,8 @@ nsWaveStateMachine::FindDataOffset()
|
|||
|
||||
// The "data" chunk may not directly follow the "format" chunk, so skip
|
||||
// over any intermediate chunks.
|
||||
for (;;) {
|
||||
char chunkHeader[8];
|
||||
const char* p = chunkHeader;
|
||||
|
||||
if (!ReadAll(chunkHeader, sizeof(chunkHeader))) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 magic = ReadUint32BE(&p);
|
||||
|
||||
if (magic == DATA_CHUNK_MAGIC) {
|
||||
length = ReadUint32LE(&p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (magic == FRMT_CHUNK_MAGIC) {
|
||||
LOG(PR_LOG_ERROR, ("Invalid WAVE: expected \"data\" chunk but found \"format\" chunk"));
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 size = ReadUint32LE(&p);
|
||||
size += size % 2;
|
||||
|
||||
nsAutoArrayPtr<char> chunk(new char[size]);
|
||||
if (!ReadAll(chunk.get(), size)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (!ScanForwardUntil(DATA_CHUNK_MAGIC, &length)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
offset = mStream->Tell();
|
||||
|
@ -1108,12 +1171,41 @@ nsWaveStateMachine::FindDataOffset()
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRInt64
|
||||
nsWaveStateMachine::GetDataLength()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mMetadataValid,
|
||||
"Attempting to initialize audio stream with invalid metadata");
|
||||
|
||||
PRInt64 length = mWaveLength;
|
||||
// If the decoder has a valid content length, and it's shorter than the
|
||||
// expected length of the PCM data, calculate the playback duration from
|
||||
// the content length rather than the expected PCM data length.
|
||||
if (mTotalBytes >= 0 && mTotalBytes - mWavePCMOffset < length) {
|
||||
length = mTotalBytes - mWavePCMOffset;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void
|
||||
nsWaveStateMachine::FirePositionChanged(PRBool aCoalesce)
|
||||
{
|
||||
if (aCoalesce && mPositionChangeQueued) {
|
||||
return;
|
||||
}
|
||||
|
||||
mPositionChangeQueued = PR_TRUE;
|
||||
nsCOMPtr<nsIRunnable> event = NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, PlaybackPositionChanged);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsWaveDecoder, nsIObserver)
|
||||
|
||||
nsWaveDecoder::nsWaveDecoder()
|
||||
: mInitialVolume(1.0),
|
||||
mStream(nsnull),
|
||||
mTimeOffset(0.0),
|
||||
mCurrentTime(0.0),
|
||||
mEndedCurrentTime(0.0),
|
||||
mEndedDuration(std::numeric_limits<float>::quiet_NaN()),
|
||||
mEnded(PR_FALSE),
|
||||
|
@ -1149,10 +1241,7 @@ nsWaveDecoder::GetCurrentPrincipal()
|
|||
float
|
||||
nsWaveDecoder::GetCurrentTime()
|
||||
{
|
||||
if (mPlaybackStateMachine) {
|
||||
return mPlaybackStateMachine->GetCurrentTime();
|
||||
}
|
||||
return mEndedCurrentTime;
|
||||
return mCurrentTime;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1351,10 +1440,6 @@ nsWaveDecoder::ResourceLoaded()
|
|||
if (mShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mPlaybackStateMachine) {
|
||||
mPlaybackStateMachine->StreamEnded(PR_TRUE);
|
||||
}
|
||||
|
||||
mResourceLoaded = PR_TRUE;
|
||||
|
||||
|
@ -1381,9 +1466,6 @@ nsWaveDecoder::NetworkError()
|
|||
if (mElement) {
|
||||
mElement->NetworkError();
|
||||
}
|
||||
if (mPlaybackStateMachine) {
|
||||
mPlaybackStateMachine->StreamEnded(PR_FALSE);
|
||||
}
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
@ -1530,10 +1612,6 @@ nsWaveDecoder::SeekingStarted()
|
|||
return;
|
||||
}
|
||||
|
||||
if (mPlaybackStateMachine) {
|
||||
mPlaybackStateMachine->UpdateTimeOffset(mTimeOffset);
|
||||
}
|
||||
|
||||
if (mElement) {
|
||||
mElement->SeekStarted();
|
||||
}
|
||||
|
@ -1597,6 +1675,24 @@ nsWaveDecoder::MediaErrorDecode()
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsWaveDecoder::PlaybackPositionChanged()
|
||||
{
|
||||
if (mShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
float lastTime = mCurrentTime;
|
||||
|
||||
if (mPlaybackStateMachine) {
|
||||
mCurrentTime = mPlaybackStateMachine->GetTimeForPositionChange();
|
||||
}
|
||||
|
||||
if (mElement && lastTime != mCurrentTime) {
|
||||
mElement->DispatchSimpleEvent(NS_LITERAL_STRING("timeupdate"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsWaveDecoder::SetDuration(PRInt64 /* aDuration */)
|
||||
{
|
||||
|
|
|
@ -77,6 +77,7 @@ _TEST_FILES += \
|
|||
test_error_on_404.html \
|
||||
test_onloadedmetadata.html \
|
||||
test_load_coalescing.html \
|
||||
test_play.html \
|
||||
test_progress1.html \
|
||||
test_progress3.html \
|
||||
test_source.html \
|
||||
|
@ -99,9 +100,6 @@ _TEST_FILES += \
|
|||
seek.ogv \
|
||||
$(NULL)
|
||||
|
||||
#XXX: disabled for now, see bug 478868
|
||||
# test_play.html \
|
||||
|
||||
ifneq ($(OS_ARCH),WINNT)
|
||||
# These tests are disabled on windows until we
|
||||
# figure out the random failures. See bug 475369.
|
||||
|
|
|
@ -14,16 +14,27 @@ SimpleTest.waitForExplicitFinish();
|
|||
|
||||
var v = document.getElementById("v");
|
||||
|
||||
var playEvents = ["play", "canplay", "playing", "canplaythrough"];
|
||||
var tokens = {
|
||||
0: ["play"],
|
||||
"play": ["canplay"],
|
||||
"canplay": ["playing"],
|
||||
"playing": ["canplay", "canplaythrough"],
|
||||
"canplaythrough": ["canplay", "canplaythrough"]
|
||||
};
|
||||
|
||||
var state = 0;
|
||||
|
||||
function gotPlayEvent(event) {
|
||||
is(event.type, playEvents.shift(), "Check expected event");
|
||||
}
|
||||
for (var i = 0; i < playEvents.length; ++i) {
|
||||
v.addEventListener(playEvents[i], gotPlayEvent, false);
|
||||
ok(tokens[state].indexOf(event.type) >= 0, "Check expected event got " + event.type + " at " + state);
|
||||
state = event.type;
|
||||
}
|
||||
|
||||
["play", "canplay", "playing", "canplaythrough"].forEach(function (e) {
|
||||
v.addEventListener(e, gotPlayEvent, false);
|
||||
});
|
||||
|
||||
function ended() {
|
||||
is(playEvents.length, 0, "Undelivered event " + playEvents[0]);
|
||||
is(state, "canplaythrough", "Last event should be canplaythrough");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
v.addEventListener("ended", ended, false);
|
||||
|
|
|
@ -3812,8 +3812,8 @@ nsSVGElement::NumberInfo nsSVGFEConvolveMatrixElement::sNumberInfo[4] =
|
|||
|
||||
nsSVGElement::IntegerInfo nsSVGFEConvolveMatrixElement::sIntegerInfo[4] =
|
||||
{
|
||||
{ &nsGkAtoms::order, 0 },
|
||||
{ &nsGkAtoms::order, 0 },
|
||||
{ &nsGkAtoms::order, 3 },
|
||||
{ &nsGkAtoms::order, 3 },
|
||||
{ &nsGkAtoms::targetX, 0 },
|
||||
{ &nsGkAtoms::targetY, 0 }
|
||||
};
|
||||
|
|
|
@ -202,6 +202,7 @@ nsSVGPreserveAspectRatio::SetBaseValueString(const nsAString &aValueAsString,
|
|||
}
|
||||
|
||||
mAnimVal = mBaseVal = val;
|
||||
aSVGElement->DidChangePreserveAspectRatio(aDoSetAttr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1292,7 +1292,7 @@ nsSVGSVGElement::GetViewboxToViewportTransform(nsIDOMSVGMatrix **_retval)
|
|||
}
|
||||
|
||||
nsSVGViewBoxRect viewbox;
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
|
||||
if (mViewBox.IsValid()) {
|
||||
viewbox = mViewBox.GetAnimValue();
|
||||
} else {
|
||||
viewbox.x = viewbox.y = 0.0f;
|
||||
|
@ -1461,7 +1461,7 @@ nsSVGSVGElement::GetLength(PRUint8 aCtxType)
|
|||
{
|
||||
float h, w;
|
||||
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::viewBox)) {
|
||||
if (mViewBox.IsValid()) {
|
||||
const nsSVGViewBoxRect& viewbox = mViewBox.GetAnimValue();
|
||||
w = viewbox.width;
|
||||
h = viewbox.height;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Watt <jonathan.watt@strath.ac.uk> (original author)
|
||||
* Craig Topper <craig.topper@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"),
|
||||
|
@ -78,6 +78,7 @@ nsSVGViewBox::Init()
|
|||
{
|
||||
mBaseVal = nsSVGViewBoxRect();
|
||||
mAnimVal = nsnull;
|
||||
mHasBaseVal = PR_FALSE;
|
||||
}
|
||||
|
||||
const nsSVGViewBoxRect&
|
||||
|
@ -94,10 +95,8 @@ nsSVGViewBox::SetBaseValue(float aX, float aY, float aWidth, float aHeight,
|
|||
nsSVGElement *aSVGElement, PRBool aDoSetAttr)
|
||||
{
|
||||
mAnimVal = nsnull;
|
||||
mBaseVal.x = aX;
|
||||
mBaseVal.y = aY;
|
||||
mBaseVal.width = aWidth;
|
||||
mBaseVal.height = aHeight;
|
||||
mBaseVal = nsSVGViewBoxRect(aX, aY, aWidth, aHeight);
|
||||
mHasBaseVal = PR_TRUE;
|
||||
|
||||
aSVGElement->DidChangeViewBox(aDoSetAttr);
|
||||
}
|
||||
|
@ -128,11 +127,7 @@ nsSVGViewBox::SetBaseValueString(const nsAString& aValue,
|
|||
// there was a parse error.
|
||||
rv = NS_ERROR_FAILURE;
|
||||
} else {
|
||||
mAnimVal = nsnull;
|
||||
mBaseVal.x = vals[0];
|
||||
mBaseVal.y = vals[1];
|
||||
mBaseVal.width = vals[2];
|
||||
mBaseVal.height = vals[3];
|
||||
SetBaseValue(vals[0], vals[1], vals[2], vals[3], aSVGElement, aDoSetAttr);
|
||||
}
|
||||
|
||||
nsMemory::Free(str);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Watt <jonathan.watt@strath.ac.uk> (original author)
|
||||
* Craig Topper <craig.topper@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"),
|
||||
|
@ -61,6 +61,10 @@ public:
|
|||
|
||||
void Init();
|
||||
|
||||
// Used by element to tell if viewbox is defined
|
||||
PRBool IsValid() const
|
||||
{ return (mHasBaseVal || mAnimVal); }
|
||||
|
||||
const nsSVGViewBoxRect& GetBaseValue() const
|
||||
{ return mBaseVal; }
|
||||
void SetBaseValue(float aX, float aY, float aWidth, float aHeight,
|
||||
|
@ -80,6 +84,7 @@ private:
|
|||
|
||||
nsSVGViewBoxRect mBaseVal;
|
||||
nsAutoPtr<nsSVGViewBoxRect> mAnimVal;
|
||||
PRPackedBool mHasBaseVal;
|
||||
|
||||
struct DOMBaseVal : public nsIDOMSVGRect
|
||||
{
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Bug - Crash [@ PL_DHashTableOperate] with DOMNodeInserted event listener removing window and frameset contenteditable</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="content" src="data:text/html;charset=utf-8,%3Cscript%3E%0Awindow.addEventListener%28%27DOMNodeInserted%27%2C%20function%28%29%20%7Bwindow.frameElement.parentNode.removeChild%28window.frameElement%29%3B%7D%2C%20true%29%3B%0A%3C/script%3E%0A%3Cframeset%20contenteditable%3D%22true%22%3E"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>testcase2 Bug 432114 – Crash [@ PL_DHashTableOperate] with DOMNodeInserted event listener removing window and frameset contenteditable</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="content" src="data:application/xhtml+xml;charset=utf-8,%3Chtml%20xmlns%3D%22http%3A//www.w3.org/1999/xhtml%22%3E%0A%3Cframeset%20contenteditable%3D%22true%22/%3E%0A%3Cscript%3E%0Afunction%20doExecCommand%28%29%7B%0Adocument.execCommand%28%27insertParagraph%27%2C%20false%2C%20%27%27%29%3B%0A%7D%0AsetTimeout%28doExecCommand%2C100%29%3B%0Awindow.addEventListener%28%27DOMNodeRemoved%27%2C%20function%28%29%20%7Bwindow.frameElement.parentNode.removeChild%28window.frameElement%29%3B%7D%2C%20true%29%3B%0A%3C/script%3E%0A%3C/html%3E" style="width:1000px;height: 200px;"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,4 +1,6 @@
|
|||
load 40929-1.html
|
||||
load 369126-1.html
|
||||
load 403574-1.xhtml
|
||||
load 432114-1.html
|
||||
load 432114-2.html
|
||||
load 436900-1.html
|
||||
|
|
|
@ -590,18 +590,16 @@ nsWebShell::EnsureCommandHandler()
|
|||
{
|
||||
if (!mCommandManager)
|
||||
{
|
||||
mCommandManager = do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
|
||||
if (!mCommandManager) return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsCOMPtr<nsPICommandUpdater> commandUpdater =
|
||||
do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
|
||||
if (!commandUpdater) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsPICommandUpdater> commandUpdater = do_QueryInterface(mCommandManager);
|
||||
if (!commandUpdater) return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(static_cast<nsIInterfaceRequestor *>(this));
|
||||
#ifdef DEBUG
|
||||
nsresult rv =
|
||||
#endif
|
||||
commandUpdater->Init(domWindow);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Initting command manager failed");
|
||||
nsCOMPtr<nsIDOMWindow> domWindow =
|
||||
do_GetInterface(static_cast<nsIInterfaceRequestor *>(this));
|
||||
|
||||
nsresult rv = commandUpdater->Init(domWindow);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mCommandManager = do_QueryInterface(commandUpdater);
|
||||
}
|
||||
|
||||
return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
|
|
@ -4344,7 +4344,7 @@ nsresult nsEditor::EndUpdateViewBatch()
|
|||
// the reflows we caused will get processed before the invalidates.
|
||||
if (flags & nsIPlaintextEditor::eEditorUseAsyncUpdatesMask) {
|
||||
updateFlag = NS_VMREFRESH_DEFERRED;
|
||||
} else {
|
||||
} else if (presShell) {
|
||||
// Flush out layout. Need to do this because if we have no invalidates
|
||||
// to flush the viewmanager code won't flush our reflow here, and we
|
||||
// have selection code that does sync caret scrolling in this case.
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Testcase for bug 448329</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<iframe id="frame448329"></iframe>
|
||||
|
||||
<script>
|
||||
|
||||
function test448329(id,cmd) {
|
||||
|
||||
var elm = document.getElementById(id);
|
||||
var doc = elm.contentDocument;
|
||||
doc.designMode = "On";
|
||||
|
||||
var s = doc.defaultView.getSelection();
|
||||
|
||||
// Test document node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
var range = doc.createRange();
|
||||
range.setStart(doc, 0);
|
||||
range.setEnd(doc, 0);
|
||||
s.addRange(range);
|
||||
doc.queryCommandIndeterm(cmd);
|
||||
|
||||
// Test HTML node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
range.setStart(doc.documentElement, 0);
|
||||
range.setEnd(doc.documentElement, 0);
|
||||
s.addRange(range);
|
||||
doc.queryCommandIndeterm(cmd);
|
||||
|
||||
// Test BODY node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
var body = doc.documentElement.childNodes[1];
|
||||
range.setStart(body, 0);
|
||||
range.setEnd(body, 0);
|
||||
s.addRange(range);
|
||||
doc.queryCommandIndeterm(cmd);
|
||||
|
||||
var text = doc.createTextNode("Hello Kitty");
|
||||
body.insertBefore(text, null)
|
||||
|
||||
// Test TEXT node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
range.setStart(text, 0);
|
||||
range.setEnd(text, 1);
|
||||
s.addRange(range);
|
||||
doc.queryCommandIndeterm(cmd);
|
||||
|
||||
}
|
||||
|
||||
test448329("frame448329", "backcolor")
|
||||
test448329("frame448329", "hilitecolor")
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Testcase for bug 448329</title>
|
||||
<script>
|
||||
function go() {
|
||||
test("myFrame", "backcolor");
|
||||
}
|
||||
function test(id,cmd) {
|
||||
var doc = document.getElementById(id).contentDocument;
|
||||
doc.designMode = "On";
|
||||
|
||||
var s = doc.defaultView.getSelection();
|
||||
s.removeAllRanges();
|
||||
s.addRange(doc.createRange());
|
||||
|
||||
doc.queryCommandIndeterm(cmd);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go()"><iframe id="myFrame"></iframe></body>
|
||||
</html>
|
|
@ -0,0 +1,109 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>Testcase #3 for bug 448329</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<iframe id="frame448329"></iframe>
|
||||
|
||||
<script>
|
||||
|
||||
function test448329(id,cmd,val) {
|
||||
|
||||
var elm = document.getElementById(id);
|
||||
var doc = elm.contentDocument;
|
||||
doc.designMode = "On";
|
||||
|
||||
var s = doc.defaultView.getSelection();
|
||||
|
||||
// Test document node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
var range = doc.createRange();
|
||||
range.setStart(doc, 0);
|
||||
range.setEnd(doc, 0);
|
||||
s.addRange(range);
|
||||
doc.execCommand(cmd,false,val);
|
||||
|
||||
// Test HTML node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
range.setStart(doc.documentElement, 0);
|
||||
range.setEnd(doc.documentElement, 0);
|
||||
s.addRange(range);
|
||||
doc.execCommand(cmd,false,val);
|
||||
|
||||
// Test BODY node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
var body = doc.documentElement.childNodes[1];
|
||||
range.setStart(body, 0);
|
||||
range.setEnd(body, 0);
|
||||
s.addRange(range);
|
||||
doc.execCommand(cmd,false,val);
|
||||
|
||||
var text = doc.createTextNode("Hello Kitty");
|
||||
body.insertBefore(text, null)
|
||||
|
||||
// Test TEXT node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
range.setStart(text, 0);
|
||||
range.setEnd(text, 1);
|
||||
s.addRange(range);
|
||||
doc.execCommand(cmd,false,val);
|
||||
|
||||
// Test BODY[0,0] + TEXT node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
range.setStart(body, 0);
|
||||
range.setEnd(body, 0);
|
||||
s.addRange(range);
|
||||
range = doc.createRange();
|
||||
range.setStart(text, 0);
|
||||
range.setEnd(text, 1);
|
||||
s.addRange(range);
|
||||
doc.execCommand(cmd,false,val);
|
||||
|
||||
// Test BODY[0,1] + TEXT node
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
range.setStart(body, 0);
|
||||
range.setEnd(body, 1);
|
||||
s.addRange(range);
|
||||
range = doc.createRange();
|
||||
range.setStart(text, 0);
|
||||
range.setEnd(text, 1);
|
||||
s.addRange(range);
|
||||
doc.execCommand(cmd,false,val);
|
||||
|
||||
// Test BODY[0,1] + TEXT node without a parent
|
||||
if (s.rangeCount > 0)
|
||||
s.removeAllRanges();
|
||||
range = doc.createRange();
|
||||
range.setStart(body, 0);
|
||||
range.setEnd(body, 1);
|
||||
s.addRange(range);
|
||||
range = doc.createRange();
|
||||
text = doc.createTextNode("Hello Kitty"); // not in doc
|
||||
range.setStart(text, 0);
|
||||
range.setEnd(text, 1);
|
||||
s.addRange(range);
|
||||
doc.execCommand(cmd,false,val);
|
||||
|
||||
}
|
||||
|
||||
test448329("frame448329", "backcolor", "green")
|
||||
test448329("frame448329", "hilitecolor", "green")
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -4,4 +4,7 @@ load 407074-1.html
|
|||
load 407277-1.html
|
||||
load 420439.html
|
||||
load 428489-1.html
|
||||
load 448329-1.html
|
||||
load 448329-2.html
|
||||
load 448329-3.html
|
||||
load 467647-1.html
|
||||
|
|
|
@ -843,6 +843,9 @@ nsHTMLCSSUtils::GetCSSPropertyAtom(nsCSSEditableProperty aProperty, nsIAtom ** a
|
|||
case eCSSEditableProperty_width:
|
||||
*aAtom = nsEditProperty::cssWidth;
|
||||
break;
|
||||
case eCSSEditableProperty_NONE:
|
||||
// intentionally empty
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1406,6 +1409,11 @@ nsHTMLCSSUtils::GetElementContainerOrSelf(nsIDOMNode * aNode, nsIDOMElement ** a
|
|||
nsresult res;
|
||||
res = node->GetNodeType(&type);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (nsIDOMNode::DOCUMENT_NODE == type) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
// loop until we find an element
|
||||
while (node && nsIDOMNode::ELEMENT_NODE != type) {
|
||||
parentNode = node;
|
||||
|
|
|
@ -2365,7 +2365,8 @@ nsHTMLEditor::GetCSSBackgroundColorState(PRBool *aMixed, nsAString &aOutColor, P
|
|||
PRInt32 offset;
|
||||
res = GetStartNodeAndOffset(selection, address_of(parent), &offset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
if (!parent) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// is the selection collapsed?
|
||||
PRBool bCollapsed;
|
||||
res = selection->GetIsCollapsed(&bCollapsed);
|
||||
|
@ -2399,6 +2400,8 @@ nsHTMLEditor::GetCSSBackgroundColorState(PRBool *aMixed, nsAString &aOutColor, P
|
|||
nsCOMPtr<nsIDOMNode> blockParent = nodeToExamine;
|
||||
if (!isBlock) {
|
||||
blockParent = GetBlockNodeParent(nodeToExamine);
|
||||
if (!blockParent)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Make sure to not walk off onto the Document node
|
||||
|
@ -3613,12 +3616,6 @@ nsHTMLEditor::AddOverrideStyleSheet(const nsAString& aURL)
|
|||
// (This checks if already exists)
|
||||
ps->AddOverrideStyleSheet(sheet);
|
||||
|
||||
// Save doc pointer to be able to use nsIStyleSheet::SetEnabled()
|
||||
nsIDocument *document = ps->GetDocument();
|
||||
if (!document)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
sheet->SetOwningDocument(document);
|
||||
|
||||
ps->ReconstructStyleData();
|
||||
|
||||
// Save as the last-loaded sheet
|
||||
|
@ -3683,11 +3680,15 @@ nsHTMLEditor::EnableStyleSheet(const nsAString &aURL, PRBool aEnable)
|
|||
|
||||
nsCOMPtr<nsIDOMStyleSheet> domSheet(do_QueryInterface(sheet));
|
||||
NS_ASSERTION(domSheet, "Sheet not implementing nsIDOMStyleSheet!");
|
||||
|
||||
// Ensure the style sheet is owned by our document.
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocWeak);
|
||||
rv = sheet->SetOwningDocument(doc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return domSheet->SetDisabled(!aEnable);
|
||||
}
|
||||
|
||||
|
||||
PRBool
|
||||
nsHTMLEditor::EnableExistingStyleSheet(const nsAString &aURL)
|
||||
{
|
||||
|
@ -3698,6 +3699,11 @@ nsHTMLEditor::EnableExistingStyleSheet(const nsAString &aURL)
|
|||
// Enable sheet if already loaded.
|
||||
if (sheet)
|
||||
{
|
||||
// Ensure the style sheet is owned by our document.
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocWeak);
|
||||
rv = sheet->SetOwningDocument(doc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMStyleSheet> domSheet(do_QueryInterface(sheet));
|
||||
NS_ASSERTION(domSheet, "Sheet not implementing nsIDOMStyleSheet!");
|
||||
|
||||
|
|
|
@ -1482,9 +1482,7 @@ ChromeTooltipListener::sTooltipCallback(nsITimer *aTimer,
|
|||
if (textFound) {
|
||||
nsString tipText(tooltipText);
|
||||
self->CreateAutoHideTimer();
|
||||
nsIntRect widgetDot(0, 0, 1, 1);
|
||||
nsIntRect screenDot;
|
||||
widget->WidgetToScreen(widgetDot, screenDot);
|
||||
nsIntPoint screenDot = widget->WidgetToScreenOffset();
|
||||
self->ShowTooltip (self->mMouseScreenX - screenDot.x,
|
||||
self->mMouseScreenY - screenDot.y,
|
||||
tipText);
|
||||
|
|
|
@ -111,6 +111,9 @@ struct nsIntPoint {
|
|||
y -= aPoint.y;
|
||||
return *this;
|
||||
}
|
||||
nsIntPoint operator-() const {
|
||||
return nsIntPoint(-x, -y);
|
||||
}
|
||||
void MoveTo(PRInt32 aX, PRInt32 aY) {x = aX; y = aY;}
|
||||
};
|
||||
|
||||
|
|
|
@ -844,11 +844,8 @@ nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
|
|||
if (fromRoot == toRoot) {
|
||||
widgetPoint = aPt + fromOffset - toOffset;
|
||||
} else {
|
||||
nsIntRect widgetRect(0, 0, 0, 0);
|
||||
nsIntRect screenRect;
|
||||
aWidget->WidgetToScreen(widgetRect, screenRect);
|
||||
viewWidget->ScreenToWidget(screenRect, widgetRect);
|
||||
widgetPoint = aPt + widgetRect.TopLeft();
|
||||
nsIntPoint screenPoint = aWidget->WidgetToScreenOffset();
|
||||
widgetPoint = aPt + screenPoint - viewWidget->WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x),
|
||||
|
|
|
@ -5383,11 +5383,12 @@ PresShell::Paint(nsIView* aView,
|
|||
// background color as recorded in the prescontext is guaranteed to
|
||||
// be opaque.
|
||||
|
||||
PRBool needTransparency = PR_FALSE;
|
||||
nscolor backgroundColor = mPresContext->DefaultBackgroundColor();
|
||||
for (nsIView *view = aView; view; view = view->GetParent()) {
|
||||
if (view->HasWidget() &&
|
||||
view->GetWidget()->GetTransparencyMode() != eTransparencyOpaque) {
|
||||
backgroundColor = NS_RGBA(0,0,0,0);
|
||||
needTransparency = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -5408,9 +5409,11 @@ PresShell::Paint(nsIView* aView,
|
|||
// backstop colors.
|
||||
nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
|
||||
if (!frame) {
|
||||
backgroundColor = NS_ComposeColors(backgroundColor, viewDefaultColor);
|
||||
aRenderingContext->SetColor(backgroundColor);
|
||||
aRenderingContext->FillRect(aDirtyRegion.GetBounds());
|
||||
if (!needTransparency) {
|
||||
backgroundColor = NS_ComposeColors(backgroundColor, viewDefaultColor);
|
||||
aRenderingContext->SetColor(backgroundColor);
|
||||
aRenderingContext->FillRect(aDirtyRegion.GetBounds());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5434,7 +5437,8 @@ PresShell::Paint(nsIView* aView,
|
|||
}
|
||||
|
||||
nsLayoutUtils::PaintFrame(aRenderingContext, frame, aDirtyRegion,
|
||||
backgroundColor);
|
||||
needTransparency ? NS_RGBA(0,0,0,0)
|
||||
: backgroundColor);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -6043,9 +6047,8 @@ PresShell::AdjustContextMenuKeyEvent(nsMouseEvent* aEvent)
|
|||
|
||||
nsCOMPtr<nsIWidget> widget = popupFrame->GetWindow();
|
||||
aEvent->widget = widget;
|
||||
nsIntRect widgetRect(0, 0, 1, 1);
|
||||
widget->WidgetToScreen(widgetRect, widgetRect);
|
||||
aEvent->refPoint = itemFrame->GetScreenRect().BottomLeft() - widgetRect.TopLeft();
|
||||
nsIntPoint widgetPoint = widget->WidgetToScreenOffset();
|
||||
aEvent->refPoint = itemFrame->GetScreenRect().BottomLeft() - widgetPoint;
|
||||
|
||||
mCurrentEventContent = itemFrame->GetContent();
|
||||
mCurrentEventFrame = itemFrame;
|
||||
|
|
|
@ -3555,13 +3555,12 @@ nsRect nsIFrame::GetScreenRectInAppUnits() const
|
|||
nsIWidget* widget = view->GetNearestWidget(&toWidgetOffset);
|
||||
|
||||
if (widget) {
|
||||
nsIntRect localRect(0,0,0,0), screenRect;
|
||||
widget->WidgetToScreen(localRect, screenRect);
|
||||
nsIntPoint screenPoint = widget->WidgetToScreenOffset();
|
||||
|
||||
retval = mRect;
|
||||
retval.MoveTo(toViewOffset + toWidgetOffset);
|
||||
retval.x += PresContext()->DevPixelsToAppUnits(screenRect.x);
|
||||
retval.y += PresContext()->DevPixelsToAppUnits(screenRect.y);
|
||||
retval.x += PresContext()->DevPixelsToAppUnits(screenPoint.x);
|
||||
retval.y += PresContext()->DevPixelsToAppUnits(screenPoint.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3831,10 +3831,9 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
|
|||
const nsMouseEvent& mouseEvent =
|
||||
static_cast<const nsMouseEvent&>(anEvent);
|
||||
// Get reference point relative to screen:
|
||||
nsIntRect windowRect(anEvent.refPoint, nsIntSize(1, 1));
|
||||
nsIntRect rootPoint(-1,-1,1,1);
|
||||
nsIntPoint rootPoint(-1,-1);
|
||||
if (widget)
|
||||
widget->WidgetToScreen(windowRect, rootPoint);
|
||||
rootPoint = anEvent.refPoint + widget->WidgetToScreenOffset();
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
Window root = GDK_ROOT_WINDOW();
|
||||
#else
|
||||
|
@ -4739,14 +4738,7 @@ WindowRef nsPluginInstanceOwner::FixUpPluginWindow(PRInt32 inPaintState)
|
|||
// use its native widget (an obj-c object) we have to go
|
||||
// from the widget's screen coordinates to its window coords
|
||||
// instead of straight to window coords.
|
||||
nsIntRect geckoBounds;
|
||||
mWidget->GetBounds(geckoBounds);
|
||||
// we need a rect that is the entire *internal* rect, so the
|
||||
// x and y coords are 0, width is the same.
|
||||
geckoBounds.x = 0;
|
||||
geckoBounds.y = 0;
|
||||
nsIntRect geckoScreenCoords;
|
||||
mWidget->WidgetToScreen(geckoBounds, geckoScreenCoords);
|
||||
nsIntPoint geckoScreenCoords = mWidget->WidgetToScreenOffset();
|
||||
|
||||
Rect windowRect;
|
||||
WindowRef window = (WindowRef)pluginPort->cgPort.window;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<filter id="convoluted_lime" x="0%" y="0%" width="100%" height="100%">
|
||||
<feFlood flood-color="lime"/>
|
||||
<feConvolveMatrix order="3" kernelMatrix="
|
||||
0 0 0
|
||||
0 1 0
|
||||
0 0 0"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<rect x="30" y="30" width="97" height="60" filter="url(#convoluted_lime)"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 339 B |
|
@ -0,0 +1,18 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
<desc>
|
||||
<html:p>When the 'order' attribute of feConvolveMatrix is
|
||||
omitted the effect is the same as if the value "3" were given.
|
||||
Per <html:a href="https://bugzilla.mozilla.org/show_bug.cgi?id=478570">Bug 478570</html:a>
|
||||
discussion and linked spec errata.</html:p>
|
||||
</desc>
|
||||
<defs>
|
||||
<filter id="convoluted_lime" x="0%" y="0%" width="100%" height="100%">
|
||||
<feFlood flood-color="lime"/>
|
||||
<feConvolveMatrix kernelMatrix="
|
||||
0 0 0
|
||||
0 1 0
|
||||
0 0 0"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<rect x="30" y="30" width="97" height="60" fill="red" filter="url(#convoluted_lime)"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 663 B |
|
@ -67,3 +67,4 @@ fails == filter-marked-line-01.svg pass.svg # bug 477704
|
|||
== filter-patterned-rect-01.svg pass.svg
|
||||
== filter-patterned-rect-02.svg pass.svg
|
||||
|
||||
== feConvolveMatrix-order-01.svg feConvolveMatrix-order-01-ref.svg
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
diff --git a/media/libsydneyaudio/src/sydney_audio_waveapi.c b/media/libsydneyaudio/src/sydney_audio_waveapi.c
|
||||
--- a/media/libsydneyaudio/src/sydney_audio_waveapi.c
|
||||
+++ b/media/libsydneyaudio/src/sydney_audio_waveapi.c
|
||||
@@ -147,17 +147,17 @@ int sa_stream_create_pcm(sa_stream_t **s
|
||||
if (format != SA_PCM_FORMAT_S16_NE) {
|
||||
return SA_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (mode != SA_MODE_WRONLY) {
|
||||
return SA_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
- if ((_s = (sa_stream_t*)malloc(sizeof(sa_stream_t))) == NULL) {
|
||||
+ if ((_s = (sa_stream_t*)calloc(1, sizeof(sa_stream_t))) == NULL) {
|
||||
return SA_ERROR_OOM;
|
||||
}
|
||||
|
||||
_s->rwMode = mode;
|
||||
_s->format = format;
|
||||
_s->rate = rate;
|
||||
_s->channels = nchannels;
|
||||
_s->deviceName = DEFAULT_DEVICE_NAME;
|
|
@ -9,3 +9,5 @@ The svn revision number used was r3827.
|
|||
|
||||
The patch from Annodex trac ticket #427 (http://trac.annodex.net/ticket/447)
|
||||
was applied to fix bug #469698.
|
||||
|
||||
Also applied patch for bug 478299.
|
||||
|
|
|
@ -152,7 +152,7 @@ int sa_stream_create_pcm(sa_stream_t **s,
|
|||
return SA_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if ((_s = (sa_stream_t*)malloc(sizeof(sa_stream_t))) == NULL) {
|
||||
if ((_s = (sa_stream_t*)calloc(1, sizeof(sa_stream_t))) == NULL) {
|
||||
return SA_ERROR_OOM;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,3 +6,4 @@ cp $1/include/sydney_audio.h include/sydney_audio.h
|
|||
cp $1/src/*.c src/
|
||||
cp $1/AUTHORS ./AUTHORS
|
||||
patch -p3 < 469698_mac_stream_endian.patch
|
||||
patch -p3 < 478299_zeromem_sa_stream.patch
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
function correctSpelling()
|
||||
{
|
||||
// Note that this code only runs if the page is requested using the
|
||||
// URL containing the correct spelling - e.g. "about:licence".
|
||||
// URL containing the correct spelling - i.e. "about:licence".
|
||||
if (document.location.href.match("icence"))
|
||||
{
|
||||
function acceptNode(node)
|
||||
|
@ -172,10 +172,12 @@
|
|||
<li><a href="about:license#jep">Java Embedding Plugin License</a></li>
|
||||
<li><a href="about:license#jemalloc">jemalloc License</a></li>
|
||||
<li><a href="about:license#hunspell-lt">Lithuanian Spellchecking Dictionary</a></li>
|
||||
<li><a href="about:license#littlecms">Little cms License</a></li>
|
||||
<li><a href="about:license#openvision">OpenVision License</a></li>
|
||||
<li><a href="about:license#xdg">Red Hat xdg_user_dir_lookup License</a></li>
|
||||
<li><a href="about:license#hunspell-ru">Russian Spellchecking Dictionary</a></li>
|
||||
<li><a href="about:license#sparkle">Sparkle License</a></li>
|
||||
<li><a href="about:license#sunsoft">SunSoft License</a></li>
|
||||
<li><a href="about:license#ucal">University of California License</a></li>
|
||||
<li><a href="about:license#hunspell-en-US">US English Spellchecking Dictionary</a></li>
|
||||
<li><a href="about:license#xiph">Xiph.org Foundation License</a></li>
|
||||
|
@ -2142,92 +2144,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="hunspell-en-US"></a>US English Spellchecking Dictionary</h1>
|
||||
|
||||
<p class="correctme">This license applies to certain files in the directory
|
||||
<span class="path">extensions/spellcheck/locales/en-US/hunspell/</span>. (This
|
||||
code only ships in some localized versions of this product.)</p>
|
||||
|
||||
<pre>
|
||||
Different parts of the US English dictionary (SCOWL) are subject to the following licenses as
|
||||
shown below. For additional details, sources, credits, and public domain references, see
|
||||
<a href="http://mxr.mozilla.org/mozilla/source/extensions/spellcheck/locales/en-US/hunspell/README.txt?raw=1">README.txt</a>.
|
||||
The collective work of the Spell Checking Oriented Word Lists (SCOWL) is under the
|
||||
following copyright:
|
||||
Copyright 2000-2007 by Kevin Atkinson
|
||||
Permission to use, copy, modify, distribute and sell these word lists, the associated scripts,
|
||||
the output created from the scripts, and its documentation for any purpose is hereby
|
||||
granted without fee, provided that the above copyright notice appears in all copies and that
|
||||
both that copyright notice and this permission notice appear in supporting documentation.
|
||||
Kevin Atkinson makes no representations about the suitability of this array for any
|
||||
purpose. It is provided "as is" without express or implied warranty.
|
||||
The WordNet database is under the following copyright:
|
||||
This software and database is being provided to you, the LICENSEE, by Princeton
|
||||
University under the following license. By obtaining, using and/or copying this software
|
||||
and database, you agree that you have read, understood, and will comply with these terms
|
||||
and conditions:
|
||||
Permission to use, copy, modify and distribute this software and database and its
|
||||
documentation for any purpose and without fee or royalty is hereby granted, provided that
|
||||
you agree to comply with the following copyright notice and statements, including the
|
||||
disclaimer, and that the same appear on ALL copies of the software, database and
|
||||
documentation, including modifications that you make for internal use or for distribution.
|
||||
WordNet 1.6 Copyright 1997 by Princeton University. All rights reserved.
|
||||
THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON UNIVERSITY
|
||||
MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
|
||||
EXAMPLE, BUT NOT LIMITATION, PRINCETON UNIVERSITY MAKES NO
|
||||
REPRESENTATIONS OR WARRANTIES OF MERCHANT- ABILITY OR FITNESS FOR ANY
|
||||
PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE, DATABASE OR
|
||||
DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
|
||||
TRADEMARKS OR OTHER RIGHTS.
|
||||
The name of Princeton University or Princeton may not be used in advertising or publicity
|
||||
pertaining to distribution of the software and/or database. Title to copyright in this
|
||||
software, database and any associated documentation shall at all times remain with
|
||||
Princeton University and LICENSEE agrees to preserve same.
|
||||
|
||||
The "UK Advanced Cryptics Dictionary" is under the following copyright:
|
||||
Copyright (c) J Ross Beresford 1993-1999. All Rights Reserved.
|
||||
The following restriction is placed on the use of this publication: if The UK Advanced
|
||||
Cryptics Dictionary is used in a software package or redistributed in any form, the
|
||||
copyright notice must be prominently displayed and the text of this document must be
|
||||
included verbatim. There are no other restrictions: I would like to see the list distributed
|
||||
as widely as possible.
|
||||
|
||||
Various parts are under the Ispell copyright:
|
||||
Copyright 1993, Geoff Kuenning, Granada Hills, CA
|
||||
All rights reserved. Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
3. All modifications to the source code must be clearly marked as such. Binary
|
||||
redistributions based on modified source code must be clearly marked as modified
|
||||
versions in the documentation and/or other materials provided with the distribution.
|
||||
(clause 4 removed with permission from Geoff Kuenning)
|
||||
5. The name of Geoff Kuenning may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Additional Contributors:
|
||||
Alan Beale <biljir@pobox.com>
|
||||
M Cooper <thegrendel@theriver.com>
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="expat"></a>Expat License</h1>
|
||||
|
@ -2423,111 +2339,6 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="openvision"></a>OpenVision License</h1>
|
||||
|
||||
<p class="correctme">This license applies to the file
|
||||
<span class="path">extensions/auth/gssapi.h</span>.</p>
|
||||
|
||||
<pre>
|
||||
Copyright 1993 by OpenVision Technologies, Inc.
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software
|
||||
and its documentation for any purpose is hereby granted without fee,
|
||||
provided that the above copyright notice appears in all copies and
|
||||
that both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of OpenVision not be used
|
||||
in advertising or publicity pertaining to distribution of the software
|
||||
without specific, written prior permission. OpenVision makes no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied warranty.
|
||||
|
||||
OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="sparkle"></a>Sparkle License</h1>
|
||||
|
||||
<p class="correctme">This license applies to certain files in the directory
|
||||
<span class="path">camino/sparkle/</span>. (This code only ships in the
|
||||
in the Camino browser or products based on it.)</p>
|
||||
|
||||
<pre>
|
||||
Copyright (c) 2006 Andy Matuschak
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="ucal"></a>University of California License</h1>
|
||||
|
||||
<p class="correctme">This license applies to the following files or, in the case of
|
||||
directories, certain files in those directories:</p>
|
||||
|
||||
<ul>
|
||||
<li class="path">dbm/</li>
|
||||
<li class="path">db/mork/src/morkQuickSort.cpp</li>
|
||||
<li class="path">xpcom/glue/nsQuickSort.cpp</li>
|
||||
</ul>
|
||||
|
||||
<pre>
|
||||
Copyright (c) 1990, 1993
|
||||
The Regents of the University of California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
[3 Deleted as of 22nd July 1999; see
|
||||
<a href="ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change">ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change</a>
|
||||
for details]
|
||||
4. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
|
@ -2570,6 +2381,67 @@ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|||
SUCH DAMAGE.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="littlecms"></a>Little cms License</h1>
|
||||
|
||||
<p class="correctme">This license applies to certain files in the directory
|
||||
<span class="path">modules/lcms/</span>.</p>
|
||||
<pre>
|
||||
Copyright (C) 1998-2007 Marti Maria
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="openvision"></a>OpenVision License</h1>
|
||||
|
||||
<p class="correctme">This license applies to the file
|
||||
<span class="path">extensions/auth/gssapi.h</span>.</p>
|
||||
|
||||
<pre>
|
||||
Copyright 1993 by OpenVision Technologies, Inc.
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software
|
||||
and its documentation for any purpose is hereby granted without fee,
|
||||
provided that the above copyright notice appears in all copies and
|
||||
that both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of OpenVision not be used
|
||||
in advertising or publicity pertaining to distribution of the software
|
||||
without specific, written prior permission. OpenVision makes no
|
||||
representations about the suitability of this software for any
|
||||
purpose. It is provided "as is" without express or implied warranty.
|
||||
|
||||
OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
||||
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="xdg"></a>Red Hat xdg_user_dir_lookup License</h1>
|
||||
|
@ -2641,6 +2513,217 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|||
POSSIBILITY OF SUCH DAMAGE.
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="sparkle"></a>Sparkle License</h1>
|
||||
|
||||
<p class="correctme">This license applies to certain files in the directory
|
||||
<span class="path">camino/sparkle/</span>. (This code only ships in the
|
||||
in the Camino browser or products based on it.)</p>
|
||||
|
||||
<pre>
|
||||
Copyright (c) 2006 Andy Matuschak
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="sunsoft"></a>SunSoft License</h1>
|
||||
|
||||
<p class="correctme">This license applies to the file
|
||||
<span class="path">modules/lcms/include/icc34.h</span>.</p>
|
||||
|
||||
<pre>
|
||||
Copyright (c) 1994-1996 SunSoft, Inc.
|
||||
|
||||
Rights Reserved
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restrict-
|
||||
ion, including without limitation the rights to use, copy, modify,
|
||||
merge, publish distribute, sublicense, and/or sell copies of the
|
||||
Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
|
||||
INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT
|
||||
COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of SunSoft, Inc.
|
||||
shall not be used in advertising or otherwise to promote the
|
||||
sale, use or other dealings in this Software without written
|
||||
authorization from SunSoft Inc.
|
||||
</pre>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="ucal"></a>University of California License</h1>
|
||||
|
||||
<p class="correctme">This license applies to the following files or, in the case of
|
||||
directories, certain files in those directories:</p>
|
||||
|
||||
<ul>
|
||||
<li class="path">dbm/</li>
|
||||
<li class="path">db/mork/src/morkQuickSort.cpp</li>
|
||||
<li class="path">xpcom/glue/nsQuickSort.cpp</li>
|
||||
</ul>
|
||||
|
||||
<pre>
|
||||
Copyright (c) 1990, 1993
|
||||
The Regents of the University of California. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
[3 Deleted as of 22nd July 1999; see
|
||||
<a href="ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change">ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change</a>
|
||||
for details]
|
||||
4. Neither the name of the University nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="hunspell-en-US"></a>US English Spellchecking Dictionary</h1>
|
||||
|
||||
<p class="correctme">This license applies to certain files in the directory
|
||||
<span class="path">extensions/spellcheck/locales/en-US/hunspell/</span>. (This
|
||||
code only ships in some localized versions of this product.)</p>
|
||||
|
||||
<pre>
|
||||
Different parts of the US English dictionary (SCOWL) are subject to the following licenses as
|
||||
shown below. For additional details, sources, credits, and public domain references, see
|
||||
<a href="http://mxr.mozilla.org/mozilla/source/extensions/spellcheck/locales/en-US/hunspell/README.txt?raw=1">README.txt</a>.
|
||||
|
||||
The collective work of the Spell Checking Oriented Word Lists (SCOWL) is under the
|
||||
following copyright:
|
||||
|
||||
Copyright 2000-2007 by Kevin Atkinson
|
||||
Permission to use, copy, modify, distribute and sell these word lists, the associated scripts,
|
||||
the output created from the scripts, and its documentation for any purpose is hereby
|
||||
granted without fee, provided that the above copyright notice appears in all copies and that
|
||||
both that copyright notice and this permission notice appear in supporting documentation.
|
||||
Kevin Atkinson makes no representations about the suitability of this array for any
|
||||
purpose. It is provided "as is" without express or implied warranty.
|
||||
|
||||
The WordNet database is under the following copyright:
|
||||
|
||||
This software and database is being provided to you, the LICENSEE, by Princeton
|
||||
University under the following license. By obtaining, using and/or copying this software
|
||||
and database, you agree that you have read, understood, and will comply with these terms
|
||||
and conditions:
|
||||
Permission to use, copy, modify and distribute this software and database and its
|
||||
documentation for any purpose and without fee or royalty is hereby granted, provided that
|
||||
you agree to comply with the following copyright notice and statements, including the
|
||||
disclaimer, and that the same appear on ALL copies of the software, database and
|
||||
documentation, including modifications that you make for internal use or for distribution.
|
||||
WordNet 1.6 Copyright 1997 by Princeton University. All rights reserved.
|
||||
THIS SOFTWARE AND DATABASE IS PROVIDED "AS IS" AND PRINCETON UNIVERSITY
|
||||
MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF
|
||||
EXAMPLE, BUT NOT LIMITATION, PRINCETON UNIVERSITY MAKES NO
|
||||
REPRESENTATIONS OR WARRANTIES OF MERCHANT- ABILITY OR FITNESS FOR ANY
|
||||
PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE, DATABASE OR
|
||||
DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
|
||||
TRADEMARKS OR OTHER RIGHTS.
|
||||
The name of Princeton University or Princeton may not be used in advertising or publicity
|
||||
pertaining to distribution of the software and/or database. Title to copyright in this
|
||||
software, database and any associated documentation shall at all times remain with
|
||||
Princeton University and LICENSEE agrees to preserve same.
|
||||
|
||||
The "UK Advanced Cryptics Dictionary" is under the following copyright:
|
||||
|
||||
Copyright (c) J Ross Beresford 1993-1999. All Rights Reserved.
|
||||
The following restriction is placed on the use of this publication: if The UK Advanced
|
||||
Cryptics Dictionary is used in a software package or redistributed in any form, the
|
||||
copyright notice must be prominently displayed and the text of this document must be
|
||||
included verbatim. There are no other restrictions: I would like to see the list distributed
|
||||
as widely as possible.
|
||||
|
||||
Various parts are under the Ispell copyright:
|
||||
|
||||
Copyright 1993, Geoff Kuenning, Granada Hills, CA
|
||||
All rights reserved. Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
3. All modifications to the source code must be clearly marked as such. Binary
|
||||
redistributions based on modified source code must be clearly marked as modified
|
||||
versions in the documentation and/or other materials provided with the distribution.
|
||||
(clause 4 removed with permission from Geoff Kuenning)
|
||||
5. The name of Geoff Kuenning may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Additional Contributors:
|
||||
|
||||
Alan Beale <biljir@pobox.com>
|
||||
M Cooper <thegrendel@theriver.com>
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a name="xiph"></a>Xiph.org Foundation License</h1>
|
||||
|
|
|
@ -373,10 +373,9 @@ nsIntRect nsView::CalcWidgetBounds(nsWindowType aType)
|
|||
|
||||
if (parentWidget && aType == eWindowType_popup &&
|
||||
mVis == nsViewVisibility_kShow) {
|
||||
nsIntRect screenRect(0,0,1,1);
|
||||
parentWidget->WidgetToScreen(screenRect, screenRect);
|
||||
viewBounds += nsPoint(NSIntPixelsToAppUnits(screenRect.x, p2a),
|
||||
NSIntPixelsToAppUnits(screenRect.y, p2a));
|
||||
nsIntPoint screenPoint = parentWidget->WidgetToScreenOffset();
|
||||
viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a),
|
||||
NSIntPixelsToAppUnits(screenPoint.y, p2a));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -809,21 +808,19 @@ nsPoint nsIView::GetOffsetTo(const nsIView* aOther) const
|
|||
|
||||
nsIntPoint nsIView::GetScreenPosition() const
|
||||
{
|
||||
nsIntRect screenRect(0,0,0,0);
|
||||
nsIntPoint screenPoint(0,0);
|
||||
nsPoint toWidgetOffset(0,0);
|
||||
nsIWidget* widget = GetNearestWidget(&toWidgetOffset);
|
||||
if (widget) {
|
||||
nsCOMPtr<nsIDeviceContext> dx;
|
||||
mViewManager->GetDeviceContext(*getter_AddRefs(dx));
|
||||
PRInt32 p2a = dx->AppUnitsPerDevPixel();
|
||||
nsIntRect ourRect(NSAppUnitsToIntPixels(toWidgetOffset.x, p2a),
|
||||
NSAppUnitsToIntPixels(toWidgetOffset.y, p2a),
|
||||
0,
|
||||
0);
|
||||
widget->WidgetToScreen(ourRect, screenRect);
|
||||
nsIntPoint ourPoint(NSAppUnitsToIntPixels(toWidgetOffset.x, p2a),
|
||||
NSAppUnitsToIntPixels(toWidgetOffset.y, p2a));
|
||||
screenPoint = ourPoint + widget->WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
return nsIntPoint(screenRect.x, screenRect.y);
|
||||
return screenPoint;
|
||||
}
|
||||
|
||||
nsIWidget* nsIView::GetNearestWidget(nsPoint* aOffset) const
|
||||
|
|
|
@ -97,10 +97,10 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
|
|||
#define NS_NATIVE_TSF_POINTER 100
|
||||
#endif
|
||||
|
||||
// 075a7792-6ba9-454e-b431-25a43fdbd3f6
|
||||
// 0dda48db-4f61-44a7-9f92-041cd92b8a9c
|
||||
#define NS_IWIDGET_IID \
|
||||
{ 0x075a7792, 0x6ba9, 0x454e, \
|
||||
{ 0xb4, 0x31, 0x25, 0xa4, 0x3f, 0xdb, 0xd3, 0xf6 } }
|
||||
{ 0x0dda48db, 0x4f61, 0x44a7, \
|
||||
{ 0x9f, 0x92, 0x04, 0x1c, 0xd9, 0x2b, 0x8a, 0x9c } }
|
||||
|
||||
// Hide the native window systems real window type so as to avoid
|
||||
// including native window system types and APIs. This is necessary
|
||||
|
@ -901,22 +901,12 @@ class nsIWidget : public nsISupports {
|
|||
NS_IMETHOD ShowMenuBar(PRBool aShow) = 0;
|
||||
|
||||
/**
|
||||
* Convert from this widget coordinates to screen coordinates.
|
||||
* Return this widget's origin in screen coordinates.
|
||||
*
|
||||
* @param aOldRect widget coordinates stored in the x,y members
|
||||
* @param aNewRect screen coordinates stored in the x,y members
|
||||
* @return screen coordinates stored in the x,y members
|
||||
*/
|
||||
|
||||
NS_IMETHOD WidgetToScreen(const nsIntRect& aOldRect, nsIntRect& aNewRect) = 0;
|
||||
|
||||
/**
|
||||
* Convert from screen coordinates to this widget's coordinates.
|
||||
*
|
||||
* @param aOldRect screen coordinates stored in the x,y members
|
||||
* @param aNewRect widget's coordinates stored in the x,y members
|
||||
*/
|
||||
|
||||
NS_IMETHOD ScreenToWidget(const nsIntRect& aOldRect, nsIntRect& aNewRect) = 0;
|
||||
virtual nsIntPoint WidgetToScreenOffset() = 0;
|
||||
|
||||
/**
|
||||
* When adjustments are to made to a whole set of child widgets, call this
|
||||
|
|
|
@ -356,8 +356,7 @@ public:
|
|||
virtual void* GetNativeData(PRUint32 aDataType);
|
||||
NS_IMETHOD SetColorMap(nsColorMap *aColorMap);
|
||||
NS_IMETHOD Scroll(PRInt32 aDx, PRInt32 aDy, nsIntRect *aClipRect);
|
||||
NS_IMETHOD WidgetToScreen(const nsIntRect& aOldRect, nsIntRect& aNewRect);
|
||||
NS_IMETHOD ScreenToWidget(const nsIntRect& aOldRect, nsIntRect& aNewRect);
|
||||
virtual nsIntPoint WidgetToScreenOffset();
|
||||
NS_IMETHOD BeginResizingChildren(void);
|
||||
NS_IMETHOD EndResizingChildren(void);
|
||||
virtual PRBool ShowsResizeIndicator(nsIntRect* aResizerRect);
|
||||
|
|
|
@ -2102,68 +2102,33 @@ PRBool nsChildView::PointInWidget(Point aThePoint)
|
|||
#pragma mark -
|
||||
|
||||
|
||||
// Convert the given rect to global coordinates.
|
||||
// @param aLocalRect -- rect in local coordinates of this widget
|
||||
// @param aGlobalRect -- |aLocalRect| in global coordinates
|
||||
NS_IMETHODIMP nsChildView::WidgetToScreen(const nsIntRect& aLocalRect, nsIntRect& aGlobalRect)
|
||||
// Return the offset between this child view and the screen.
|
||||
// @return -- widget origin in screen coordinates
|
||||
nsIntPoint nsChildView::WidgetToScreenOffset()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
NSRect temp;
|
||||
GeckoRectToNSRect(aLocalRect, temp);
|
||||
NSPoint temp;
|
||||
temp.x = 0;
|
||||
temp.y = 0;
|
||||
|
||||
// 1. First translate this rect into window coords. The returned rect is always in
|
||||
// 1. First translate this point into window coords. The returned point is always in
|
||||
// bottom-left coordinates.
|
||||
//
|
||||
// NOTE: convertRect:toView:nil doesn't care if |mView| is a flipped view (with
|
||||
// top-left coords) and so assumes that our passed-in rect's origin is in
|
||||
// bottom-left coordinates. We adjust this further down, by subtracting
|
||||
// the final screen rect's origin by the rect's height, to get the origo
|
||||
// where we want it.
|
||||
temp = [mView convertRect:temp toView:nil];
|
||||
temp = [mView convertPoint:temp toView:nil];
|
||||
|
||||
// 2. We turn the window-coord rect's origin into screen (still bottom-left) coords.
|
||||
temp.origin = [[mView nativeWindow] convertBaseToScreen:temp.origin];
|
||||
temp = [[mView nativeWindow] convertBaseToScreen:temp];
|
||||
|
||||
// 3. Since we're dealing in bottom-left coords, we need to make it top-left coords
|
||||
// before we pass it back to Gecko.
|
||||
FlipCocoaScreenCoordinate(temp.origin);
|
||||
FlipCocoaScreenCoordinate(temp);
|
||||
|
||||
// 4. If this is rect has a size (and is not simply a point), it is important to account
|
||||
// for the fact that convertRect:toView:nil thought our passed-in point was in bottom-left
|
||||
// coords in step #1. Thus, we subtract the rect's height, to get the top-left rect's origin
|
||||
// where we want it.
|
||||
temp.origin.y -= temp.size.height;
|
||||
|
||||
NSRectToGeckoRect(temp, aGlobalRect);
|
||||
return NS_OK;
|
||||
return nsIntPoint(NSToIntRound(temp.x), NSToIntRound(temp.y));
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nsIntPoint(0,0));
|
||||
}
|
||||
|
||||
|
||||
// Convert the given rect to local coordinates.
|
||||
// @param aGlobalRect -- rect in screen coordinates
|
||||
// @param aLocalRect -- |aGlobalRect| in coordinates of this widget
|
||||
NS_IMETHODIMP nsChildView::ScreenToWidget(const nsIntRect& aGlobalRect, nsIntRect& aLocalRect)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
NSRect temp;
|
||||
GeckoRectToNSRect(aGlobalRect, temp);
|
||||
FlipCocoaScreenCoordinate(temp.origin);
|
||||
|
||||
temp.origin = [[mView nativeWindow] convertScreenToBase:temp.origin]; // convert to screen coords
|
||||
temp = [mView convertRect:temp fromView:nil]; // convert to window coords
|
||||
|
||||
NSRectToGeckoRect(temp, aLocalRect);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
|
||||
// Convert the coordinates to some device coordinates so GFX can draw.
|
||||
void nsChildView::ConvertToDeviceCoordinates(nscoord &aX, nscoord &aY)
|
||||
{
|
||||
|
|
|
@ -222,8 +222,7 @@ public:
|
|||
NS_IMETHOD SetMenuBar(void* aMenuBar);
|
||||
virtual nsMenuBarX* GetMenuBar();
|
||||
NS_IMETHOD ShowMenuBar(PRBool aShow);
|
||||
NS_IMETHOD WidgetToScreen(const nsIntRect& aOldRect, nsIntRect& aNewRect);
|
||||
NS_IMETHOD ScreenToWidget(const nsIntRect& aOldRect, nsIntRect& aNewRect);
|
||||
virtual nsIntPoint WidgetToScreenOffset();
|
||||
|
||||
virtual void* GetNativeData(PRUint32 aDataType) ;
|
||||
|
||||
|
|
|
@ -1221,37 +1221,15 @@ NS_IMETHODIMP nsCocoaWindow::ShowMenuBar(PRBool aShow)
|
|||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCocoaWindow::WidgetToScreen(const nsIntRect& aOldRect, nsIntRect& aNewRect)
|
||||
nsIntPoint nsCocoaWindow::WidgetToScreenOffset()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
nsIntRect r = nsCocoaUtils::CocoaRectToGeckoRect([mWindow contentRectForFrameRect:[mWindow frame]]);
|
||||
|
||||
aNewRect.x = r.x + aOldRect.x;
|
||||
aNewRect.y = r.y + aOldRect.y;
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
return r.TopLeft();
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP nsCocoaWindow::ScreenToWidget(const nsIntRect& aOldRect, nsIntRect& aNewRect)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
||||
|
||||
nsIntRect r = nsCocoaUtils::CocoaRectToGeckoRect([mWindow contentRectForFrameRect:[mWindow frame]]);
|
||||
|
||||
aNewRect.x = aOldRect.x - r.x;
|
||||
aNewRect.y = aOldRect.y - r.y;
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nsIntPoint(0,0));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1354,8 +1354,7 @@ nsWindow::SetFocus(PRBool aRaise)
|
|||
NS_IMETHODIMP
|
||||
nsWindow::GetScreenBounds(nsIntRect &aRect)
|
||||
{
|
||||
nsIntRect origin(0, 0, mBounds.width, mBounds.height);
|
||||
WidgetToScreen(origin, aRect);
|
||||
aRect = nsIntRect(WidgetToScreenOffset(), mBounds.Size());
|
||||
LOG(("GetScreenBounds %d %d | %d %d | %d %d\n",
|
||||
aRect.x, aRect.y,
|
||||
mBounds.width, mBounds.height,
|
||||
|
@ -1857,48 +1856,22 @@ nsWindow::ShowMenuBar(PRBool aShow)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::WidgetToScreen(const nsIntRect& aOldRect, nsIntRect& aNewRect)
|
||||
nsIntPoint
|
||||
nsWindow::WidgetToScreenOffset()
|
||||
{
|
||||
gint x = 0, y = 0;
|
||||
|
||||
if (mContainer) {
|
||||
gdk_window_get_root_origin(GTK_WIDGET(mContainer)->window,
|
||||
&x, &y);
|
||||
LOG(("WidgetToScreen (container) %d %d\n", x, y));
|
||||
LOG(("WidgetToScreenOffset (container) %d %d\n", x, y));
|
||||
}
|
||||
else if (mDrawingarea) {
|
||||
gdk_window_get_origin(mDrawingarea->inner_window, &x, &y);
|
||||
LOG(("WidgetToScreen (drawing) %d %d\n", x, y));
|
||||
LOG(("WidgetToScreenOffset (drawing) %d %d\n", x, y));
|
||||
}
|
||||
|
||||
aNewRect.x = x + aOldRect.x;
|
||||
aNewRect.y = y + aOldRect.y;
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::ScreenToWidget(const nsIntRect& aOldRect, nsIntRect& aNewRect)
|
||||
{
|
||||
gint x = 0, y = 0;
|
||||
|
||||
if (mContainer) {
|
||||
gdk_window_get_root_origin(GTK_WIDGET(mContainer)->window,
|
||||
&x, &y);
|
||||
}
|
||||
else if (mDrawingarea) {
|
||||
gdk_window_get_origin(mDrawingarea->inner_window, &x, &y);
|
||||
}
|
||||
|
||||
aNewRect.x = aOldRect.x - x;
|
||||
aNewRect.y = aOldRect.y - y;
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
|
||||
return NS_OK;
|
||||
return nsIntPoint(x, y);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -2390,10 +2363,7 @@ nsWindow::OnConfigureEvent(GtkWidget *aWidget, GdkEventConfigure *aEvent)
|
|||
if (mIsTopLevel) {
|
||||
mPlaced = PR_TRUE;
|
||||
// Need to translate this into the right coordinates
|
||||
nsIntRect oldrect, newrect;
|
||||
WidgetToScreen(oldrect, newrect);
|
||||
mBounds.x = newrect.x;
|
||||
mBounds.y = newrect.y;
|
||||
mBounds.MoveTo(WidgetToScreenOffset());
|
||||
}
|
||||
|
||||
nsGUIEvent event(PR_TRUE, NS_MOVE, this);
|
||||
|
@ -2553,11 +2523,7 @@ nsWindow::OnMotionNotifyEvent(GtkWidget *aWidget, GdkEventMotion *aEvent)
|
|||
mLastMotionPressure = pressure;
|
||||
event.pressure = mLastMotionPressure;
|
||||
|
||||
nsRect windowRect;
|
||||
ScreenToWidget(nsRect(nscoord(cursorX), nscoord(cursorY), 1, 1), windowRect);
|
||||
|
||||
event.refPoint.x = windowRect.x;
|
||||
event.refPoint.y = windowRect.y;
|
||||
event.refPoint = nsIntPoint(cursorX, cursorY) - WidgetToScreenOffset();
|
||||
|
||||
event.isShift = (aEvent->state & GDK_SHIFT_MASK)
|
||||
? PR_TRUE : PR_FALSE;
|
||||
|
@ -2647,11 +2613,8 @@ nsWindow::OnMotionNotifyEvent(GtkWidget *aWidget, GdkEventMotion *aEvent)
|
|||
event.refPoint.x = nscoord(aEvent->x);
|
||||
event.refPoint.y = nscoord(aEvent->y);
|
||||
} else {
|
||||
nsIntRect windowRect;
|
||||
ScreenToWidget(nsIntRect(NSToIntFloor(aEvent->x_root), NSToIntFloor(aEvent->y_root), 1, 1), windowRect);
|
||||
|
||||
event.refPoint.x = windowRect.x;
|
||||
event.refPoint.y = windowRect.y;
|
||||
nsIntPoint point(NSToIntFloor(aEvent->x_root), NSToIntFloor(aEvent->y_root));
|
||||
event.refPoint = point - WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
event.isShift = (aEvent->state & GDK_SHIFT_MASK)
|
||||
|
@ -2678,11 +2641,8 @@ nsWindow::InitButtonEvent(nsMouseEvent &aEvent,
|
|||
aEvent.refPoint.x = nscoord(aGdkEvent->x);
|
||||
aEvent.refPoint.y = nscoord(aGdkEvent->y);
|
||||
} else {
|
||||
nsIntRect windowRect;
|
||||
ScreenToWidget(nsIntRect(NSToIntFloor(aGdkEvent->x_root), NSToIntFloor(aGdkEvent->y_root), 1, 1), windowRect);
|
||||
|
||||
aEvent.refPoint.x = windowRect.x;
|
||||
aEvent.refPoint.y = windowRect.y;
|
||||
nsIntPoint point(NSToIntFloor(aGdkEvent->x_root), NSToIntFloor(aGdkEvent->y_root));
|
||||
aEvent.refPoint = point - WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
aEvent.isShift = (aGdkEvent->state & GDK_SHIFT_MASK) != 0;
|
||||
|
@ -3233,18 +3193,15 @@ nsWindow::OnScrollEvent(GtkWidget *aWidget, GdkEventScroll *aEvent)
|
|||
}
|
||||
|
||||
if (aEvent->window == mDrawingarea->inner_window) {
|
||||
// we are the window that the event happened on so no need for expensive ScreenToWidget
|
||||
// we are the window that the event happened on so no need for expensive WidgetToScreenOffset
|
||||
event.refPoint.x = nscoord(aEvent->x);
|
||||
event.refPoint.y = nscoord(aEvent->y);
|
||||
} else {
|
||||
// XXX we're never quite sure which GdkWindow the event came from due to our custom bubbling
|
||||
// in scroll_event_cb(), so use ScreenToWidget to translate the screen root coordinates into
|
||||
// coordinates relative to this widget.
|
||||
nsIntRect windowRect;
|
||||
ScreenToWidget(nsIntRect(NSToIntFloor(aEvent->x_root), NSToIntFloor(aEvent->y_root), 1, 1), windowRect);
|
||||
|
||||
event.refPoint.x = windowRect.x;
|
||||
event.refPoint.y = windowRect.y;
|
||||
nsIntPoint point(NSToIntFloor(aEvent->x_root), NSToIntFloor(aEvent->y_root));
|
||||
event.refPoint = point - WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
event.isShift = (aEvent->state & GDK_SHIFT_MASK) != 0;
|
||||
|
|
|
@ -208,10 +208,7 @@ public:
|
|||
NS_IMETHOD SetWindowClass(const nsAString& xulWinType);
|
||||
NS_IMETHOD SetMenuBar(void * aMenuBar);
|
||||
NS_IMETHOD ShowMenuBar(PRBool aShow);
|
||||
NS_IMETHOD WidgetToScreen(const nsIntRect& aOldRect,
|
||||
nsIntRect& aNewRect);
|
||||
NS_IMETHOD ScreenToWidget(const nsIntRect& aOldRect,
|
||||
nsIntRect& aNewRect);
|
||||
virtual nsIntPoint WidgetToScreenOffset();
|
||||
NS_IMETHOD BeginResizingChildren(void);
|
||||
NS_IMETHOD EndResizingChildren(void);
|
||||
NS_IMETHOD EnableDragDrop(PRBool aEnable);
|
||||
|
|
|
@ -367,33 +367,15 @@ NS_METHOD nsWindow::EndResizingChildren(void)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD nsWindow::WidgetToScreen(const nsIntRect &aOldRect, nsIntRect &aNewRect)
|
||||
nsIntPoint nsWindow::WidgetToScreenOffset()
|
||||
{
|
||||
POINTL point = { aOldRect.x, aOldRect.y };
|
||||
POINTL point = { 0, 0 };
|
||||
NS2PM( point);
|
||||
|
||||
WinMapWindowPoints( mWnd, HWND_DESKTOP, &point, 1);
|
||||
|
||||
aNewRect.x = point.x;
|
||||
aNewRect.y = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - point.y - 1;
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD nsWindow::ScreenToWidget( const nsIntRect &aOldRect, nsIntRect &aNewRect)
|
||||
{
|
||||
POINTL point = { aOldRect.x,
|
||||
WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - aOldRect.y - 1 };
|
||||
WinMapWindowPoints( HWND_DESKTOP, mWnd, &point, 1);
|
||||
|
||||
PM2NS( point);
|
||||
|
||||
aNewRect.x = point.x;
|
||||
aNewRect.y = point.y;
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
return NS_OK;
|
||||
return nsIntPoint(point.x,
|
||||
WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN) - point.y - 1);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
|
@ -162,8 +162,7 @@ class nsWindow : public nsBaseWidget,
|
|||
|
||||
NS_IMETHOD BeginResizingChildren();
|
||||
NS_IMETHOD EndResizingChildren();
|
||||
NS_IMETHOD WidgetToScreen( const nsIntRect &aOldRect, nsIntRect &aNewRect);
|
||||
NS_IMETHOD ScreenToWidget( const nsIntRect &aOldRect, nsIntRect &aNewRect);
|
||||
virtual nsIntPoint WidgetToScreenOffset();
|
||||
NS_IMETHOD DispatchEvent( struct nsGUIEvent *event, nsEventStatus &aStatus);
|
||||
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent);
|
||||
|
||||
|
|
|
@ -416,13 +416,8 @@ nsWindow::Move(PRInt32 aX, PRInt32 aY)
|
|||
QPoint pos(aX, aY);
|
||||
if (mDrawingArea) {
|
||||
if (mParent && mDrawingArea->windowType() == Qt::Popup) {
|
||||
nsIntRect oldrect, newrect;
|
||||
oldrect.x = aX;
|
||||
oldrect.y = aY;
|
||||
|
||||
mParent->WidgetToScreen(oldrect, newrect);
|
||||
|
||||
pos = QPoint(newrect.x, newrect.y);
|
||||
if (mParent->mDrawingArea)
|
||||
pos = mParent->mDrawingArea->mapToGlobal(pos);
|
||||
#ifdef DEBUG_WIDGETS
|
||||
qDebug("pos is [%d,%d]", pos.x(), pos.y());
|
||||
#endif
|
||||
|
@ -588,8 +583,7 @@ nsWindow::SetFocus(PRBool aRaise)
|
|||
NS_IMETHODIMP
|
||||
nsWindow::GetScreenBounds(nsIntRect &aRect)
|
||||
{
|
||||
nsIntRect origin(0, 0, mBounds.width, mBounds.height);
|
||||
WidgetToScreen(origin, aRect);
|
||||
aRect = nsIntRect(WidgetToScreenOffset(), mBounds.Size());
|
||||
LOG(("GetScreenBounds %d %d | %d %d | %d %d\n",
|
||||
aRect.x, aRect.y,
|
||||
mBounds.width, mBounds.height,
|
||||
|
@ -913,38 +907,17 @@ nsWindow::ShowMenuBar(PRBool aShow)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::WidgetToScreen(const nsIntRect& aOldRect, nsIntRect& aNewRect)
|
||||
nsIntPoint
|
||||
nsWindow::WidgetToScreenOffset()
|
||||
{
|
||||
NS_ENSURE_TRUE(mDrawingArea, NS_OK);
|
||||
NS_ENSURE_TRUE(mDrawingArea, nsIntPoint(0,0));
|
||||
|
||||
QPoint origin(aOldRect.x, aOldRect.y);
|
||||
QPoint origin(0, 0);
|
||||
origin = mDrawingArea->mapToGlobal(origin);
|
||||
|
||||
aNewRect.x = origin.x();
|
||||
aNewRect.y = origin.y();
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
|
||||
return NS_OK;
|
||||
return nsIntPoint(origin.x(), origin.y());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::ScreenToWidget(const nsIntRect& aOldRect, nsIntRect& aNewRect)
|
||||
{
|
||||
NS_ENSURE_TRUE(mDrawingArea, NS_OK);
|
||||
|
||||
QPoint origin(aOldRect.x, aOldRect.y);
|
||||
origin = mDrawingArea->mapFromGlobal(origin);
|
||||
|
||||
aNewRect.x = origin.x();
|
||||
aNewRect.y = origin.y();
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::BeginResizingChildren(void)
|
||||
{
|
||||
|
@ -1225,10 +1198,7 @@ nsWindow::OnMoveEvent(QMoveEvent *aEvent)
|
|||
QPoint pos = aEvent->pos();
|
||||
if (mIsTopLevel) {
|
||||
// Need to translate this into the right coordinates
|
||||
nsIntRect oldrect, newrect;
|
||||
WidgetToScreen(oldrect, newrect);
|
||||
mBounds.x = newrect.x;
|
||||
mBounds.y = newrect.y;
|
||||
mBounds.MoveTo(WidgetToScreenOffset());
|
||||
}
|
||||
|
||||
nsGUIEvent event(PR_TRUE, NS_MOVE, this);
|
||||
|
@ -1905,13 +1875,8 @@ nsWindow::NativeResize(PRInt32 aX, PRInt32 aY,
|
|||
if (mDrawingArea)
|
||||
{
|
||||
if (mParent && mDrawingArea->windowType() == Qt::Popup) {
|
||||
nsIntRect oldrect, newrect;
|
||||
oldrect.x = aX;
|
||||
oldrect.y = aY;
|
||||
|
||||
mParent->WidgetToScreen(oldrect, newrect);
|
||||
|
||||
pos = QPoint(newrect.x, newrect.y);
|
||||
if (mParent->mDrawingArea)
|
||||
pos = mParent->mDrawingArea->mapToGlobal(pos);
|
||||
#ifdef DEBUG_WIDGETS
|
||||
qDebug("pos is [%d,%d]", pos.x(), pos.y());
|
||||
#endif
|
||||
|
@ -2537,13 +2502,8 @@ nsWindow::Resize(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight,
|
|||
// XXXvlad what?
|
||||
#if 0
|
||||
if (mParent && mDrawingArea->windowType() == Qt::Popup) {
|
||||
nsIntRect oldrect, newrect;
|
||||
oldrect.x = aX;
|
||||
oldrect.y = aY;
|
||||
|
||||
mParent->WidgetToScreen(oldrect, newrect);
|
||||
|
||||
pos = QPoint(newrect.x, newrect.y);
|
||||
if (mParent->mDrawingArea)
|
||||
pos = mParent->mDrawingArea->mapToGlobal(pos);
|
||||
#ifdef DEBUG_WIDGETS
|
||||
qDebug("pos is [%d,%d]", pos.x(), pos.y());
|
||||
#endif
|
||||
|
|
|
@ -196,10 +196,7 @@ public:
|
|||
NS_IMETHOD SetIcon(const nsAString& aIconSpec);
|
||||
NS_IMETHOD SetMenuBar(void * aMenuBar) { return NS_ERROR_FAILURE; }
|
||||
NS_IMETHOD ShowMenuBar(PRBool aShow);
|
||||
NS_IMETHOD WidgetToScreen(const nsIntRect& aOldRect,
|
||||
nsIntRect& aNewRect);
|
||||
NS_IMETHOD ScreenToWidget(const nsIntRect& aOldRect,
|
||||
nsIntRect& aNewRect);
|
||||
virtual nsIntPoint WidgetToScreenOffset();
|
||||
NS_IMETHOD BeginResizingChildren(void);
|
||||
NS_IMETHOD EndResizingChildren(void);
|
||||
NS_IMETHOD GetPreferredSize (PRInt32 &aWidth,
|
||||
|
|
|
@ -642,9 +642,7 @@ nsTextStore::GetTextExt(TsViewCookie vcView,
|
|||
refWindow = refWindow->GetTopLevelWindow(PR_FALSE);
|
||||
NS_ENSURE_TRUE(refWindow, E_FAIL);
|
||||
|
||||
nsresult rv = refWindow->WidgetToScreen(event.mReply.mRect,
|
||||
event.mReply.mRect);
|
||||
NS_ENSURE_SUCCESS(rv, E_FAIL);
|
||||
event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
|
||||
// get bounding screen rect to test for clipping
|
||||
HRESULT hr = GetScreenExt(vcView, prc);
|
||||
|
@ -686,10 +684,8 @@ nsTextStore::GetScreenExt(TsViewCookie vcView,
|
|||
|
||||
// Clip frame rect to window rect
|
||||
boundRect.IntersectRect(event.mReply.mRect, boundRect);
|
||||
rv = refWindow->WidgetToScreen(boundRect, boundRect);
|
||||
NS_ENSURE_SUCCESS(rv, E_FAIL);
|
||||
|
||||
if (!boundRect.IsEmpty()) {
|
||||
boundRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
::SetRect(prc, boundRect.x, boundRect.y,
|
||||
boundRect.XMost(), boundRect.YMost());
|
||||
} else {
|
||||
|
|
|
@ -903,30 +903,13 @@ NS_METHOD nsWindow::EndResizingChildren(void)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD nsWindow::WidgetToScreen(const nsIntRect& aOldRect, nsIntRect& aNewRect)
|
||||
nsIntPoint nsWindow::WidgetToScreenOffset()
|
||||
{
|
||||
POINT point;
|
||||
point.x = aOldRect.x;
|
||||
point.y = aOldRect.y;
|
||||
point.x = 0;
|
||||
point.y = 0;
|
||||
::ClientToScreen(mWnd, &point);
|
||||
aNewRect.x = point.x;
|
||||
aNewRect.y = point.y;
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD nsWindow::ScreenToWidget(const nsIntRect& aOldRect, nsIntRect& aNewRect)
|
||||
{
|
||||
POINT point;
|
||||
point.x = aOldRect.x;
|
||||
point.y = aOldRect.y;
|
||||
::ScreenToClient(mWnd, &point);
|
||||
aNewRect.x = point.x;
|
||||
aNewRect.y = point.y;
|
||||
aNewRect.width = aOldRect.width;
|
||||
aNewRect.height = aOldRect.height;
|
||||
return NS_OK;
|
||||
return nsIntPoint(point.x, point.y);
|
||||
}
|
||||
|
||||
LPARAM nsWindow::lParamToScreen(LPARAM lParam)
|
||||
|
@ -6307,11 +6290,7 @@ PRBool nsWindow::DispatchMouseEvent(PRUint32 aEventType, WPARAM wParam,
|
|||
event.isAlt = IS_VK_DOWN(NS_VK_ALT);
|
||||
event.button = aButton;
|
||||
|
||||
nsIntRect mpWidget;
|
||||
nsIntRect mpScreen;
|
||||
mpWidget.x = eventPoint.x;
|
||||
mpWidget.y = eventPoint.y;
|
||||
WidgetToScreen(mpWidget, mpScreen);
|
||||
nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset();
|
||||
|
||||
// Suppress mouse moves caused by widget creation
|
||||
if (aEventType == NS_MOUSE_MOVE)
|
||||
|
@ -7573,10 +7552,10 @@ nsWindow::ResolveIMECaretPos(nsIWidget* aReferenceWidget,
|
|||
return;
|
||||
|
||||
if (aReferenceWidget)
|
||||
aReferenceWidget->WidgetToScreen(aOutRect, aOutRect);
|
||||
aOutRect.MoveBy(aReferenceWidget->WidgetToScreenOffset());
|
||||
|
||||
if (aNewOriginWidget)
|
||||
aNewOriginWidget->ScreenToWidget(aOutRect, aOutRect);
|
||||
aOutRect.MoveBy(-aNewOriginWidget->WidgetToScreenOffset());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -196,8 +196,7 @@ public:
|
|||
NS_IMETHOD SetIcon(const nsAString& aIconSpec);
|
||||
NS_IMETHOD SetMenuBar(void * aMenuBar) { return NS_ERROR_FAILURE; }
|
||||
NS_IMETHOD ShowMenuBar(PRBool aShow) { return NS_ERROR_FAILURE; }
|
||||
NS_IMETHOD WidgetToScreen(const nsIntRect& aOldRect, nsIntRect& aNewRect);
|
||||
NS_IMETHOD ScreenToWidget(const nsIntRect& aOldRect, nsIntRect& aNewRect);
|
||||
virtual nsIntPoint WidgetToScreenOffset();
|
||||
NS_IMETHOD BeginResizingChildren(void);
|
||||
NS_IMETHOD EndResizingChildren(void);
|
||||
NS_IMETHOD GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight);
|
||||
|
|
Загрузка…
Ссылка в новой задаче