This commit is contained in:
Boris Zbarsky 2009-02-19 09:19:42 -05:00
Родитель a79385332a 89b78d73e5
Коммит 4fd12ef2e8
99 изменённых файлов: 2386 добавлений и 1673 удалений

Просмотреть файл

@ -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))
// 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)
nsHTMLLabelAccessible::GetNameInternal(nsAString& aName)
{
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;
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,31 +111,47 @@ 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 attr = aRule.getAttribute("attr");
if (attr) {
var name = "";
var attr = aRule.getAttribute("attr");
var attrValue = aElm.getAttribute(attr);
var type = aRule.getAttribute("type");
@ -90,7 +159,7 @@ function testNameForRule(aElm, aRule)
name = attrValue;
} else if (type == "ref") {
var ids = attrValue.split(/\s+/);///\,\s*/);
var ids = attrValue.split(/\s+/);
for (var idx = 0; idx < ids.length; idx++) {
var labelElm = getNode(ids[idx]);
if (name != "")
@ -103,12 +172,15 @@ function testNameForRule(aElm, aRule)
var msg = "Attribute '" + attr + "' test. ";
testName(aElm, name, msg);
aElm.removeAttribute(attr);
return;
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)
{
@ -130,18 +202,23 @@ function testNameForRule(aElm, aRule)
var labelElm = treeWalker.nextNode();
var msg = "Element '" + elm + "' test.";
testName(aElm, labelElm.getAttribute("a11yname"), msg);
labelElm.parentNode.removeChild(labelElm);
return;
var parentNode = labelElm.parentNode;
waitForEvent(EVENT_REORDER, parentNode,
gTestIterator.iterateNext, gTestIterator);
parentNode.removeChild(labelElm);
}
var fromSubtree = aRule.getAttribute("fromsubtree");
if (fromSubtree == "true") {
function testNameForSubtreeRule(aElm, aRule)
{
var msg = "From subtree test.";
testName(aElm, aElm.getAttribute("a11yname"), msg);
waitForEvent(EVENT_REORDER, aElm, gTestIterator.iterateNext, gTestIterator);
while (aElm.firstChild)
aElm.removeChild(aElm.firstChild);
return;
}
}
/**

Просмотреть файл

@ -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,9 +133,20 @@
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
];

Просмотреть файл

@ -24,8 +24,22 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=475006
testAttrs("autocomplete", {"autocomplete" : "true"}, true);
// bug 477876 testAttrs("checked", {"checkable" : "true"}, 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);
var unwrapped;
if (flavor != TAB_DROP_TYPE) {
// There's only ever one in the D&D case.
var unwrapped = PlacesUtils.unwrapNodes(data, flavor)[0];
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);

Просмотреть файл

@ -201,6 +201,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"].
getService(Ci.nsIProperties);
@ -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);
PRUint32 startTime = PR_IntervalToMilliseconds(PR_IntervalNow());
startTime -= AUDIO_BUFFER_LENGTH;
PRIntervalTime lastWakeup = PR_MillisecondsToInterval(startTime);
do {
PRIntervalTime now = PR_IntervalNow();
PRInt32 sleepTime = PR_IntervalToMilliseconds(now - lastWakeup);
lastWakeup = now;
// 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);
}
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);
ChangeState(STATE_BUFFERING);
} else {
// Media stream has ended and there is less data available than a
// single sample so end playback.
ChangeState(STATE_ENDED);
break;
}
} 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;
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);
}
mAudioStream->Write(buf.get(), lengthInSamples);
monitor.Enter();
if (mState == STATE_ENDED) {
got = RoundDownToSample(got);
}
// 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)));
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);
}
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,35 +1150,10 @@ 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))) {
if (!ScanForwardUntil(DATA_CHUNK_MAGIC, &length)) {
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;
}
}
offset = mStream->Tell();
if (!offset) {
NS_WARNING("PCM data offset not found");
@ -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
@ -1352,10 +1441,6 @@ nsWaveDecoder::ResourceLoaded()
return;
}
if (mPlaybackStateMachine) {
mPlaybackStateMachine->StreamEnded(PR_TRUE);
}
mResourceLoaded = PR_TRUE;
if (!mMetadataLoadedReported || mResourceLoadedReported)
@ -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));
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");
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,6 +2365,7 @@ 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;
@ -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
@ -3684,10 +3681,14 @@ 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) {
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 &lt;biljir@pobox.com&gt;
M Cooper &lt;thegrendel@theriver.com&gt;
</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 &lt;biljir@pobox.com&gt;
M Cooper &lt;thegrendel@theriver.com&gt;
</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,65 +2102,30 @@ 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;
return nsIntPoint(NSToIntRound(temp.x), NSToIntRound(temp.y));
NSRectToGeckoRect(temp, aGlobalRect);
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
// 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;
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nsIntPoint(0,0));
}

Просмотреть файл

@ -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,36 +907,15 @@ 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;
}
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;
return nsIntPoint(origin.x(), origin.y());
}
NS_IMETHODIMP
@ -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);