mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge in bug 461444: remove cases of excessive recursion in makefiles r=ted
This commit is contained in:
commit
9f8ed3f5da
@ -90,7 +90,7 @@ nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
|
||||
PRBool aIsAsync, EIsFromUserInput aIsFromUserInput,
|
||||
EEventRule aEventRule) :
|
||||
mEventType(aEventType), mEventRule(aEventRule), mIsAsync(aIsAsync),
|
||||
mDOMNode(aDOMNode)
|
||||
mNode(do_QueryInterface(aDOMNode))
|
||||
{
|
||||
CaptureIsFromUserInput(aIsFromUserInput);
|
||||
}
|
||||
@ -138,13 +138,19 @@ nsAccEvent::GetDOMNode(nsIDOMNode **aDOMNode)
|
||||
NS_ENSURE_ARG_POINTER(aDOMNode);
|
||||
*aDOMNode = nsnull;
|
||||
|
||||
if (!mDOMNode) {
|
||||
if (!mNode) {
|
||||
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(mAccessible));
|
||||
NS_ENSURE_TRUE(accessNode, NS_ERROR_FAILURE);
|
||||
accessNode->GetDOMNode(getter_AddRefs(mDOMNode));
|
||||
|
||||
nsCOMPtr<nsIDOMNode> DOMNode;
|
||||
accessNode->GetDOMNode(getter_AddRefs(DOMNode));
|
||||
|
||||
mNode = do_QueryInterface(DOMNode);
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(*aDOMNode = mDOMNode);
|
||||
if (mNode)
|
||||
CallQueryInterface(mNode, aDOMNode);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -175,7 +181,7 @@ nsAccEvent::GetAccessibleDocument(nsIAccessibleDocument **aDocAccessible)
|
||||
already_AddRefed<nsIAccessible>
|
||||
nsAccEvent::GetAccessibleByNode()
|
||||
{
|
||||
if (!mDOMNode)
|
||||
if (!mNode)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIAccessibilityService> accService =
|
||||
@ -183,19 +189,23 @@ nsAccEvent::GetAccessibleByNode()
|
||||
if (!accService)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> DOMNode(do_QueryInterface(mNode));
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
accService->GetAccessibleFor(mDOMNode, getter_AddRefs(accessible));
|
||||
accService->GetAccessibleFor(DOMNode, getter_AddRefs(accessible));
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
// hack for xul tree table. We need a better way for firing delayed event
|
||||
// against xul tree table. see bug 386821.
|
||||
// There will be problem if some day we want to fire delayed event against
|
||||
// the xul tree itself or an unselected treeitem.
|
||||
nsAutoString localName;
|
||||
mDOMNode->GetLocalName(localName);
|
||||
if (localName.EqualsLiteral("tree")) {
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(mNode));
|
||||
if (content && content->NodeInfo()->Equals(nsAccessibilityAtoms::tree,
|
||||
kNameSpaceID_XUL)) {
|
||||
|
||||
nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect =
|
||||
do_QueryInterface(mDOMNode);
|
||||
do_QueryInterface(mNode);
|
||||
|
||||
if (multiSelect) {
|
||||
PRInt32 treeIndex = -1;
|
||||
multiSelect->GetCurrentIndex(&treeIndex);
|
||||
@ -254,160 +264,6 @@ nsAccEvent::CaptureIsFromUserInput(EIsFromUserInput aIsFromUserInput)
|
||||
mIsFromUserInput = esm->IsHandlingUserInputExternal();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEvent: static methods
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsAccEvent::ApplyEventRules(nsTArray<nsRefPtr<nsAccEvent> > &aEventsToFire)
|
||||
{
|
||||
PRUint32 numQueuedEvents = aEventsToFire.Length();
|
||||
PRInt32 tail = numQueuedEvents - 1;
|
||||
|
||||
nsAccEvent* tailEvent = aEventsToFire[tail];
|
||||
switch(tailEvent->mEventRule) {
|
||||
case nsAccEvent::eCoalesceFromSameSubtree:
|
||||
{
|
||||
for (PRInt32 index = 0; index < tail; index ++) {
|
||||
nsAccEvent* thisEvent = aEventsToFire[index];
|
||||
if (thisEvent->mEventType != tailEvent->mEventType)
|
||||
continue; // Different type
|
||||
|
||||
if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
|
||||
thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
|
||||
continue; // Do not need to check
|
||||
|
||||
if (thisEvent->mDOMNode == tailEvent->mDOMNode) {
|
||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||
CoalesceReorderEventsFromSameSource(thisEvent, tailEvent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dupe
|
||||
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
continue;
|
||||
}
|
||||
if (nsCoreUtils::IsAncestorOf(tailEvent->mDOMNode,
|
||||
thisEvent->mDOMNode)) {
|
||||
// thisDOMNode is a descendant of tailDOMNode
|
||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||
CoalesceReorderEventsFromSameTree(tailEvent, thisEvent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not emit thisEvent, also apply this result to sibling
|
||||
// nodes of thisDOMNode.
|
||||
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
ApplyToSiblings(aEventsToFire, 0, index, thisEvent->mEventType,
|
||||
thisEvent->mDOMNode, nsAccEvent::eDoNotEmit);
|
||||
continue;
|
||||
}
|
||||
if (nsCoreUtils::IsAncestorOf(thisEvent->mDOMNode,
|
||||
tailEvent->mDOMNode)) {
|
||||
// tailDOMNode is a descendant of thisDOMNode
|
||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||
CoalesceReorderEventsFromSameTree(thisEvent, tailEvent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not emit tailEvent, also apply this result to sibling
|
||||
// nodes of tailDOMNode.
|
||||
tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
|
||||
tailEvent->mDOMNode, nsAccEvent::eDoNotEmit);
|
||||
break;
|
||||
}
|
||||
} // for (index)
|
||||
|
||||
if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
|
||||
// Not in another event node's subtree, and no other event is in
|
||||
// this event node's subtree.
|
||||
// This event should be emitted
|
||||
// Apply this result to sibling nodes of tailDOMNode
|
||||
ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
|
||||
tailEvent->mDOMNode, nsAccEvent::eAllowDupes);
|
||||
}
|
||||
} break; // case eCoalesceFromSameSubtree
|
||||
|
||||
case nsAccEvent::eRemoveDupes:
|
||||
{
|
||||
// Check for repeat events.
|
||||
for (PRInt32 index = 0; index < tail; index ++) {
|
||||
nsAccEvent* accEvent = aEventsToFire[index];
|
||||
if (accEvent->mEventType == tailEvent->mEventType &&
|
||||
accEvent->mEventRule == tailEvent->mEventRule &&
|
||||
accEvent->mDOMNode == tailEvent->mDOMNode) {
|
||||
accEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
}
|
||||
}
|
||||
} break; // case eRemoveDupes
|
||||
|
||||
default:
|
||||
break; // case eAllowDupes, eDoNotEmit
|
||||
} // switch
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsAccEvent::ApplyToSiblings(nsTArray<nsRefPtr<nsAccEvent> > &aEventsToFire,
|
||||
PRUint32 aStart, PRUint32 aEnd,
|
||||
PRUint32 aEventType, nsIDOMNode* aDOMNode,
|
||||
EEventRule aEventRule)
|
||||
{
|
||||
for (PRUint32 index = aStart; index < aEnd; index ++) {
|
||||
nsAccEvent* accEvent = aEventsToFire[index];
|
||||
if (accEvent->mEventType == aEventType &&
|
||||
accEvent->mEventRule != nsAccEvent::eDoNotEmit &&
|
||||
nsCoreUtils::AreSiblings(accEvent->mDOMNode, aDOMNode)) {
|
||||
accEvent->mEventRule = aEventRule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsAccEvent::CoalesceReorderEventsFromSameSource(nsAccEvent *aAccEvent1,
|
||||
nsAccEvent *aAccEvent2)
|
||||
{
|
||||
// Do not emit event2 if event1 is unconditional.
|
||||
nsCOMPtr<nsAccReorderEvent> reorderEvent1 = do_QueryInterface(aAccEvent1);
|
||||
if (reorderEvent1->IsUnconditionalEvent()) {
|
||||
aAccEvent2->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not emit event1 if event2 is unconditional.
|
||||
nsCOMPtr<nsAccReorderEvent> reorderEvent2 = do_QueryInterface(aAccEvent2);
|
||||
if (reorderEvent2->IsUnconditionalEvent()) {
|
||||
aAccEvent1->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not emit event2 if event1 is valid, otherwise do not emit event1.
|
||||
if (reorderEvent1->HasAccessibleInReasonSubtree())
|
||||
aAccEvent2->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
else
|
||||
aAccEvent1->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEvent::CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
|
||||
nsAccEvent *aDescendantAccEvent)
|
||||
{
|
||||
// Do not emit descendant event if this event is unconditional.
|
||||
nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(aAccEvent);
|
||||
if (reorderEvent->IsUnconditionalEvent()) {
|
||||
aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not emit descendant event if this event is valid otherwise do not emit
|
||||
// this event.
|
||||
if (reorderEvent->HasAccessibleInReasonSubtree())
|
||||
aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
else
|
||||
aAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccReorderEvent
|
||||
|
@ -138,48 +138,10 @@ protected:
|
||||
EEventRule mEventRule;
|
||||
PRPackedBool mIsAsync;
|
||||
nsCOMPtr<nsIAccessible> mAccessible;
|
||||
nsCOMPtr<nsIDOMNode> mDOMNode;
|
||||
nsCOMPtr<nsINode> mNode;
|
||||
nsCOMPtr<nsIAccessibleDocument> mDocAccessible;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Apply event rules to pending events, this method is called in
|
||||
* FlushingPendingEvents().
|
||||
* Result of this method:
|
||||
* Event rule of filtered events will be set to eDoNotEmit.
|
||||
* Events with other event rule are good to emit.
|
||||
*/
|
||||
static void ApplyEventRules(nsTArray<nsRefPtr<nsAccEvent> > &aEventsToFire);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Apply aEventRule to same type event that from sibling nodes of aDOMNode.
|
||||
* @param aEventsToFire array of pending events
|
||||
* @param aStart start index of pending events to be scanned
|
||||
* @param aEnd end index to be scanned (not included)
|
||||
* @param aEventType target event type
|
||||
* @param aDOMNode target are siblings of this node
|
||||
* @param aEventRule the event rule to be applied
|
||||
* (should be eDoNotEmit or eAllowDupes)
|
||||
*/
|
||||
static void ApplyToSiblings(nsTArray<nsRefPtr<nsAccEvent> > &aEventsToFire,
|
||||
PRUint32 aStart, PRUint32 aEnd,
|
||||
PRUint32 aEventType, nsIDOMNode* aDOMNode,
|
||||
EEventRule aEventRule);
|
||||
|
||||
/**
|
||||
* Do not emit one of two given reorder events fired for the same DOM node.
|
||||
*/
|
||||
static void CoalesceReorderEventsFromSameSource(nsAccEvent *aAccEvent1,
|
||||
nsAccEvent *aAccEvent2);
|
||||
|
||||
/**
|
||||
* Do not emit one of two given reorder events fired for DOM nodes in the case
|
||||
* when one DOM node is in parent chain of second one.
|
||||
*/
|
||||
static void CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
|
||||
nsAccEvent *aDescendantAccEvent);
|
||||
friend class nsAccEventQueue;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsAccEvent, NS_ACCEVENT_IMPL_CID)
|
||||
|
@ -75,9 +75,7 @@
|
||||
nsIStringBundle *nsAccessNode::gStringBundle = 0;
|
||||
nsIStringBundle *nsAccessNode::gKeyStringBundle = 0;
|
||||
nsIDOMNode *nsAccessNode::gLastFocusedNode = 0;
|
||||
#ifdef DEBUG
|
||||
PRBool nsAccessNode::gIsAccessibilityActive = PR_FALSE;
|
||||
#endif
|
||||
|
||||
PRBool nsAccessNode::gIsCacheDisabled = PR_FALSE;
|
||||
PRBool nsAccessNode::gIsFormFillEnabled = PR_FALSE;
|
||||
nsAccessNodeHashtable nsAccessNode::gGlobalDocAccessibleCache;
|
||||
@ -230,7 +228,8 @@ NS_IMETHODIMP nsAccessNode::GetOwnerWindow(void **aWindow)
|
||||
already_AddRefed<nsApplicationAccessibleWrap>
|
||||
nsAccessNode::GetApplicationAccessible()
|
||||
{
|
||||
NS_ASSERTION(gIsAccessibilityActive, "Accessibility wasn't initialized!");
|
||||
NS_ASSERTION(!nsAccessibilityService::gIsShutdown,
|
||||
"Accessibility wasn't initialized!");
|
||||
|
||||
if (!gApplicationAccessible) {
|
||||
nsApplicationAccessibleWrap::PreCreate();
|
||||
@ -256,9 +255,6 @@ nsAccessNode::GetApplicationAccessible()
|
||||
|
||||
void nsAccessNode::InitXPAccessibility()
|
||||
{
|
||||
NS_ASSERTION(!gIsAccessibilityActive,
|
||||
"Accessibility was initialized already!");
|
||||
|
||||
nsCOMPtr<nsIStringBundleService> stringBundleService =
|
||||
do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
if (stringBundleService) {
|
||||
@ -279,9 +275,6 @@ void nsAccessNode::InitXPAccessibility()
|
||||
prefBranch->GetBoolPref("browser.formfill.enable", &gIsFormFillEnabled);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
gIsAccessibilityActive = PR_TRUE;
|
||||
#endif
|
||||
NotifyA11yInitOrShutdown(PR_TRUE);
|
||||
}
|
||||
|
||||
@ -304,8 +297,6 @@ void nsAccessNode::ShutdownXPAccessibility()
|
||||
// which happens when xpcom is shutting down
|
||||
// at exit of program
|
||||
|
||||
NS_ASSERTION(gIsAccessibilityActive, "Accessibility was shutdown already!");
|
||||
|
||||
NS_IF_RELEASE(gStringBundle);
|
||||
NS_IF_RELEASE(gKeyStringBundle);
|
||||
NS_IF_RELEASE(gLastFocusedNode);
|
||||
@ -318,9 +309,6 @@ void nsAccessNode::ShutdownXPAccessibility()
|
||||
NS_IF_RELEASE(gApplicationAccessible);
|
||||
gApplicationAccessible = nsnull;
|
||||
|
||||
#ifdef DEBUG
|
||||
gIsAccessibilityActive = PR_FALSE;
|
||||
#endif
|
||||
NotifyA11yInitOrShutdown(PR_FALSE);
|
||||
}
|
||||
|
||||
|
@ -100,11 +100,11 @@ NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x22)
|
||||
PR_END_MACRO
|
||||
|
||||
#define NS_ACCESSNODE_IMPL_CID \
|
||||
{ /* 13555f6e-0c0f-4002-84f6-558d47b8208e */ \
|
||||
0x13555f6e, \
|
||||
0xc0f, \
|
||||
0x4002, \
|
||||
{ 0x84, 0xf6, 0x55, 0x8d, 0x47, 0xb8, 0x20, 0x8e } \
|
||||
{ /* 2b07e3d7-00b3-4379-aa0b-ea22e2c8ffda */ \
|
||||
0x2b07e3d7, \
|
||||
0x00b3, \
|
||||
0x4379, \
|
||||
{ 0xaa, 0x0b, 0xea, 0x22, 0xe2, 0xc8, 0xff, 0xda } \
|
||||
}
|
||||
|
||||
class nsAccessNode: public nsIAccessNode
|
||||
@ -168,9 +168,20 @@ class nsAccessNode: public nsIAccessNode
|
||||
*/
|
||||
virtual nsIFrame* GetFrame();
|
||||
|
||||
/**
|
||||
* Return the corresponding press shell for this accessible.
|
||||
*/
|
||||
already_AddRefed<nsIPresShell> GetPresShell();
|
||||
|
||||
/**
|
||||
* Return true if the accessible still has presentation shell. Light-weight
|
||||
* version of IsDefunct() method.
|
||||
*/
|
||||
PRBool HasWeakShell() const { return !!mWeakShell; }
|
||||
|
||||
protected:
|
||||
nsresult MakeAccessNode(nsIDOMNode *aNode, nsIAccessNode **aAccessNode);
|
||||
already_AddRefed<nsIPresShell> GetPresShell();
|
||||
|
||||
nsPresContext* GetPresContext();
|
||||
already_AddRefed<nsIAccessibleDocument> GetDocAccessible();
|
||||
void LastRelease();
|
||||
@ -191,9 +202,6 @@ protected:
|
||||
static nsIStringBundle *gStringBundle;
|
||||
static nsIStringBundle *gKeyStringBundle;
|
||||
|
||||
#ifdef DEBUG
|
||||
static PRBool gIsAccessibilityActive;
|
||||
#endif
|
||||
static PRBool gIsCacheDisabled;
|
||||
static PRBool gIsFormFillEnabled;
|
||||
|
||||
|
@ -153,6 +153,7 @@ ACCESSIBILITY_ATOM(toolbarspring, "toolbarspring") // XUL
|
||||
ACCESSIBILITY_ATOM(toolbarspacer, "toolbarspacer") // XUL
|
||||
ACCESSIBILITY_ATOM(tooltip, "tooltip") // XUL
|
||||
ACCESSIBILITY_ATOM(tr, "tr")
|
||||
ACCESSIBILITY_ATOM(tree, "tree")
|
||||
ACCESSIBILITY_ATOM(ul, "ul")
|
||||
|
||||
// Alphabetical list of attributes (DOM)
|
||||
|
@ -448,8 +448,8 @@ nsAccessible::GetKeyboardShortcut(nsAString& aAccessKey)
|
||||
// Copy access key from label node unless it is labeled
|
||||
// via an ancestor <label>, in which case that would be redundant
|
||||
nsCOMPtr<nsIContent> labelContent(nsCoreUtils::GetLabelContent(content));
|
||||
nsCOMPtr<nsIDOMNode> labelNode = do_QueryInterface(labelContent);
|
||||
if (labelNode && !nsCoreUtils::IsAncestorOf(labelNode, mDOMNode))
|
||||
nsCOMPtr<nsINode> thisNode = do_QueryInterface(mDOMNode);
|
||||
if (labelContent && !nsCoreUtils::IsAncestorOf(labelContent, thisNode))
|
||||
key = nsCoreUtils::GetAccessKeyFor(labelContent);
|
||||
}
|
||||
|
||||
@ -1708,11 +1708,13 @@ nsAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
|
||||
|
||||
if (nsAccUtils::Role(tabPanel) == nsIAccessibleRole::ROLE_PROPERTYPAGE) {
|
||||
nsCOMPtr<nsIAccessNode> tabPanelAccessNode(do_QueryInterface(tabPanel));
|
||||
nsCOMPtr<nsIDOMNode> tabPanelNode;
|
||||
tabPanelAccessNode->GetDOMNode(getter_AddRefs(tabPanelNode));
|
||||
NS_ENSURE_STATE(tabPanelNode);
|
||||
nsCOMPtr<nsIDOMNode> tabPanelDOMNode;
|
||||
tabPanelAccessNode->GetDOMNode(getter_AddRefs(tabPanelDOMNode));
|
||||
NS_ENSURE_STATE(tabPanelDOMNode);
|
||||
|
||||
if (nsCoreUtils::IsAncestorOf(tabPanelNode, gLastFocusedNode))
|
||||
nsCOMPtr<nsINode> tabPanelNode(do_QueryInterface(tabPanelDOMNode));
|
||||
nsCOMPtr<nsINode> lastFocusedNode(do_QueryInterface(gLastFocusedNode));
|
||||
if (nsCoreUtils::IsAncestorOf(tabPanelNode, lastFocusedNode))
|
||||
*aState |= nsIAccessibleStates::STATE_SELECTED;
|
||||
}
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ nsCaretAccessible::NormalSelectionChanged(nsIDOMDocument *aDoc,
|
||||
mLastCaretOffset = caretOffset;
|
||||
mLastTextAccessible = textAcc;
|
||||
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
nsRefPtr<nsAccEvent> event =
|
||||
new nsAccCaretMoveEvent(textNode);
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
|
@ -313,36 +313,26 @@ nsCoreUtils::GetRoleContent(nsIDOMNode *aDOMNode)
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCoreUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
|
||||
nsIDOMNode *aPossibleDescendantNode)
|
||||
nsCoreUtils::IsAncestorOf(nsINode *aPossibleAncestorNode,
|
||||
nsINode *aPossibleDescendantNode)
|
||||
{
|
||||
NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> loopNode = aPossibleDescendantNode;
|
||||
nsCOMPtr<nsIDOMNode> parentNode;
|
||||
while (NS_SUCCEEDED(loopNode->GetParentNode(getter_AddRefs(parentNode))) &&
|
||||
parentNode) {
|
||||
if (parentNode == aPossibleAncestorNode) {
|
||||
nsINode *parentNode = aPossibleDescendantNode;
|
||||
while ((parentNode = parentNode->GetNodeParent())) {
|
||||
if (parentNode == aPossibleAncestorNode)
|
||||
return PR_TRUE;
|
||||
}
|
||||
loopNode.swap(parentNode);
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsCoreUtils::AreSiblings(nsIDOMNode *aDOMNode1,
|
||||
nsIDOMNode *aDOMNode2)
|
||||
nsCoreUtils::AreSiblings(nsINode *aNode1, nsINode *aNode2)
|
||||
{
|
||||
NS_ENSURE_TRUE(aDOMNode1 && aDOMNode2, PR_FALSE);
|
||||
NS_ENSURE_TRUE(aNode1 && aNode2, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parentNode1, parentNode2;
|
||||
if (NS_SUCCEEDED(aDOMNode1->GetParentNode(getter_AddRefs(parentNode1))) &&
|
||||
NS_SUCCEEDED(aDOMNode2->GetParentNode(getter_AddRefs(parentNode2))) &&
|
||||
parentNode1 == parentNode2) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
return aNode1->GetNodeParent() == aNode2->GetNodeParent();
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -140,19 +140,23 @@ public:
|
||||
/**
|
||||
* Is the first passed in node an ancestor of the second?
|
||||
* Note: A node is not considered to be the ancestor of itself.
|
||||
* @param aPossibleAncestorNode -- node to test for ancestor-ness of aPossibleDescendantNode
|
||||
* @param aPossibleDescendantNode -- node to test for descendant-ness of aPossibleAncestorNode
|
||||
* @return PR_TRUE if aPossibleAncestorNode is an ancestor of aPossibleDescendantNode
|
||||
*
|
||||
* @param aPossibleAncestorNode [in] node to test for ancestor-ness of
|
||||
* aPossibleDescendantNode
|
||||
* @param aPossibleDescendantNode [in] node to test for descendant-ness of
|
||||
* aPossibleAncestorNode
|
||||
* @return PR_TRUE if aPossibleAncestorNode is an ancestor of
|
||||
* aPossibleDescendantNode
|
||||
*/
|
||||
static PRBool IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
|
||||
nsIDOMNode *aPossibleDescendantNode);
|
||||
static PRBool IsAncestorOf(nsINode *aPossibleAncestorNode,
|
||||
nsINode *aPossibleDescendantNode);
|
||||
|
||||
/**
|
||||
* Are the first node and the second siblings?
|
||||
*
|
||||
* @return PR_TRUE if aDOMNode1 and aDOMNode2 have same parent
|
||||
*/
|
||||
static PRBool AreSiblings(nsIDOMNode *aDOMNode1,
|
||||
nsIDOMNode *aDOMNode2);
|
||||
static PRBool AreSiblings(nsINode *aNode1, nsINode *aNode2);
|
||||
|
||||
/**
|
||||
* Helper method to scroll range into view, used for implementation of
|
||||
|
@ -85,8 +85,7 @@ nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull;
|
||||
nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
|
||||
nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
|
||||
mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
|
||||
mIsLoadCompleteFired(PR_FALSE), mInFlushPendingEvents(PR_FALSE),
|
||||
mFireEventTimerStarted(PR_FALSE)
|
||||
mIsLoadCompleteFired(PR_FALSE)
|
||||
{
|
||||
// XXX aaronl should we use an algorithm for the initial cache size?
|
||||
mAccessNodeCache.Init(kDefaultCacheSize);
|
||||
@ -151,17 +150,14 @@ ElementTraverser(const void *aKey, nsIAccessNode *aAccessNode,
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocAccessible)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
PRUint32 i, length = tmp->mEventsToFire.Length();
|
||||
for (i = 0; i < length; ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventsToFire[i]");
|
||||
cb.NoteXPCOMChild(tmp->mEventsToFire[i].get());
|
||||
}
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEventQueue");
|
||||
cb.NoteXPCOMChild(tmp->mEventQueue.get());
|
||||
|
||||
tmp->mAccessNodeCache.EnumerateRead(ElementTraverser, &cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mEventsToFire)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEventQueue)
|
||||
tmp->ClearCache(tmp->mAccessNodeCache);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
@ -609,9 +605,12 @@ nsDocAccessible::Init()
|
||||
nsresult rv = nsHyperTextAccessibleWrap::Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Initialize event queue.
|
||||
mEventQueue = new nsAccEventQueue(this);
|
||||
|
||||
// Fire reorder event to notify new accessible document has been created and
|
||||
// attached to the tree.
|
||||
nsCOMPtr<nsIAccessibleEvent> reorderEvent =
|
||||
nsRefPtr<nsAccEvent> reorderEvent =
|
||||
new nsAccReorderEvent(mParent, PR_FALSE, PR_TRUE, mDOMNode);
|
||||
NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
@ -626,6 +625,9 @@ nsDocAccessible::Shutdown()
|
||||
return NS_OK; // Already shutdown
|
||||
}
|
||||
|
||||
mEventQueue->Shutdown();
|
||||
mEventQueue = nsnull;
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> treeItem =
|
||||
nsCoreUtils::GetDocShellTreeItemFor(mDOMNode);
|
||||
ShutdownChildDocuments(treeItem);
|
||||
@ -641,21 +643,6 @@ nsDocAccessible::Shutdown()
|
||||
|
||||
nsHyperTextAccessibleWrap::Shutdown();
|
||||
|
||||
if (mFireEventTimer) {
|
||||
// Doc being shut down before delayed events were processed.
|
||||
mFireEventTimer->Cancel();
|
||||
mFireEventTimer = nsnull;
|
||||
mEventsToFire.Clear();
|
||||
|
||||
if (mFireEventTimerStarted && !mInFlushPendingEvents) {
|
||||
// Make sure we release the kung fu death grip which is always there when
|
||||
// fire event timer was started but FlushPendingEvents() callback wasn't
|
||||
// triggered yet. If FlushPendingEvents() is in call stack, kung fu death
|
||||
// grip will be released there.
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from the cache after other parts of Shutdown(), so that Shutdown() procedures
|
||||
// can find the doc or root accessible in the cache if they need it.
|
||||
// We don't do this during ShutdownAccessibility() because that is already clearing the cache
|
||||
@ -1101,14 +1088,14 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
|
||||
// Note. We use the attribute instead of the disabled state bit because
|
||||
// ARIA's aria-disabled does not affect the disabled state bit.
|
||||
|
||||
nsCOMPtr<nsIAccessibleEvent> enabledChangeEvent =
|
||||
nsRefPtr<nsAccEvent> enabledChangeEvent =
|
||||
new nsAccStateChangeEvent(targetNode,
|
||||
nsIAccessibleStates::EXT_STATE_ENABLED,
|
||||
PR_TRUE);
|
||||
|
||||
FireDelayedAccessibleEvent(enabledChangeEvent);
|
||||
|
||||
nsCOMPtr<nsIAccessibleEvent> sensitiveChangeEvent =
|
||||
nsRefPtr<nsAccEvent> sensitiveChangeEvent =
|
||||
new nsAccStateChangeEvent(targetNode,
|
||||
nsIAccessibleStates::EXT_STATE_SENSITIVE,
|
||||
PR_TRUE);
|
||||
@ -1184,7 +1171,7 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
|
||||
}
|
||||
|
||||
if (aAttribute == nsAccessibilityAtoms::contenteditable) {
|
||||
nsCOMPtr<nsIAccessibleEvent> editableChangeEvent =
|
||||
nsRefPtr<nsAccEvent> editableChangeEvent =
|
||||
new nsAccStateChangeEvent(targetNode,
|
||||
nsIAccessibleStates::EXT_STATE_EDITABLE,
|
||||
PR_TRUE);
|
||||
@ -1202,7 +1189,7 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
||||
return;
|
||||
|
||||
if (aAttribute == nsAccessibilityAtoms::aria_required) {
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
nsRefPtr<nsAccEvent> event =
|
||||
new nsAccStateChangeEvent(targetNode,
|
||||
nsIAccessibleStates::STATE_REQUIRED,
|
||||
PR_FALSE);
|
||||
@ -1211,7 +1198,7 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
||||
}
|
||||
|
||||
if (aAttribute == nsAccessibilityAtoms::aria_invalid) {
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
nsRefPtr<nsAccEvent> event =
|
||||
new nsAccStateChangeEvent(targetNode,
|
||||
nsIAccessibleStates::STATE_INVALID,
|
||||
PR_FALSE);
|
||||
@ -1245,7 +1232,7 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
||||
const PRUint32 kState = (aAttribute == nsAccessibilityAtoms::aria_checked) ?
|
||||
nsIAccessibleStates::STATE_CHECKED :
|
||||
nsIAccessibleStates::STATE_PRESSED;
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
nsRefPtr<nsAccEvent> event =
|
||||
new nsAccStateChangeEvent(targetNode, kState, PR_FALSE);
|
||||
FireDelayedAccessibleEvent(event);
|
||||
if (targetNode == gLastFocusedNode) {
|
||||
@ -1260,7 +1247,7 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
||||
PRBool isMixed =
|
||||
(nsAccUtils::State(accessible) & nsIAccessibleStates::STATE_MIXED) != 0;
|
||||
if (wasMixed != isMixed) {
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
nsRefPtr<nsAccEvent> event =
|
||||
new nsAccStateChangeEvent(targetNode,
|
||||
nsIAccessibleStates::STATE_MIXED,
|
||||
PR_FALSE, isMixed);
|
||||
@ -1272,7 +1259,7 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
||||
}
|
||||
|
||||
if (aAttribute == nsAccessibilityAtoms::aria_expanded) {
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
nsRefPtr<nsAccEvent> event =
|
||||
new nsAccStateChangeEvent(targetNode,
|
||||
nsIAccessibleStates::STATE_EXPANDED,
|
||||
PR_FALSE);
|
||||
@ -1281,7 +1268,7 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
|
||||
}
|
||||
|
||||
if (aAttribute == nsAccessibilityAtoms::aria_readonly) {
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
nsRefPtr<nsAccEvent> event =
|
||||
new nsAccStateChangeEvent(targetNode,
|
||||
nsIAccessibleStates::STATE_READONLY,
|
||||
PR_FALSE);
|
||||
@ -1447,10 +1434,10 @@ nsDocAccessible::FireValueChangeForTextFields(nsIAccessible *aPossibleTextFieldA
|
||||
return;
|
||||
|
||||
// Dependent value change event for text changes in textfields
|
||||
nsCOMPtr<nsIAccessibleEvent> valueChangeEvent =
|
||||
nsRefPtr<nsAccEvent> valueChangeEvent =
|
||||
new nsAccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, aPossibleTextFieldAccessible,
|
||||
PR_FALSE, eAutoDetect, nsAccEvent::eRemoveDupes);
|
||||
FireDelayedAccessibleEvent(valueChangeEvent );
|
||||
FireDelayedAccessibleEvent(valueChangeEvent);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1545,13 +1532,18 @@ nsDocAccessible::CreateTextChangeEventForNode(nsIAccessible *aContainerAccessibl
|
||||
if (!changeAccessible) {
|
||||
return nsnull; // No descendant content that represents any text in the hypertext parent
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINode> changeNode(do_QueryInterface(aChangeNode));
|
||||
nsCOMPtr<nsIAccessible> child = changeAccessible;
|
||||
while (PR_TRUE) {
|
||||
nsCOMPtr<nsIAccessNode> childAccessNode =
|
||||
do_QueryInterface(changeAccessible);
|
||||
nsCOMPtr<nsIDOMNode> childNode;
|
||||
childAccessNode->GetDOMNode(getter_AddRefs(childNode));
|
||||
if (!nsCoreUtils::IsAncestorOf(aChangeNode, childNode)) {
|
||||
|
||||
nsCOMPtr<nsIDOMNode> childDOMNode;
|
||||
childAccessNode->GetDOMNode(getter_AddRefs(childDOMNode));
|
||||
|
||||
nsCOMPtr<nsINode> childNode(do_QueryInterface(childDOMNode));
|
||||
if (!nsCoreUtils::IsAncestorOf(changeNode, childNode)) {
|
||||
break; // We only want accessibles with DOM nodes as children of this node
|
||||
}
|
||||
length += nsAccUtils::TextLength(child);
|
||||
@ -1601,7 +1593,7 @@ nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType,
|
||||
PRBool aIsAsynch,
|
||||
EIsFromUserInput aIsFromUserInput)
|
||||
{
|
||||
nsCOMPtr<nsIAccessibleEvent> event =
|
||||
nsRefPtr<nsAccEvent> event =
|
||||
new nsAccEvent(aEventType, aDOMNode, aIsAsynch, aIsFromUserInput, aAllowDupes);
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
@ -1610,262 +1602,170 @@ nsDocAccessible::FireDelayedAccessibleEvent(PRUint32 aEventType,
|
||||
|
||||
// nsDocAccessible public member
|
||||
nsresult
|
||||
nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent)
|
||||
nsDocAccessible::FireDelayedAccessibleEvent(nsAccEvent *aEvent)
|
||||
{
|
||||
NS_ENSURE_ARG(aEvent);
|
||||
|
||||
nsRefPtr<nsAccEvent> accEvent = nsAccUtils::QueryObject<nsAccEvent>(aEvent);
|
||||
mEventsToFire.AppendElement(accEvent);
|
||||
if (mEventQueue)
|
||||
mEventQueue->Push(aEvent);
|
||||
|
||||
// Filter events.
|
||||
nsAccEvent::ApplyEventRules(mEventsToFire);
|
||||
|
||||
// Process events.
|
||||
return PreparePendingEventsFlush();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocAccessible::PreparePendingEventsFlush()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Create timer if we don't have it yet.
|
||||
if (!mFireEventTimer) {
|
||||
mFireEventTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// If there are delayed events in the queue and event timer wasn't started
|
||||
// then initialize the timer so that delayed event will be processed in
|
||||
// FlushPendingEvents.
|
||||
if (mEventsToFire.Length() > 0 && !mFireEventTimerStarted) {
|
||||
|
||||
rv = mFireEventTimer->InitWithFuncCallback(FlushEventsCallback,
|
||||
this, 0,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Kung fu death grip to prevent crash in callback.
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
mFireEventTimerStarted = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocAccessible::FlushPendingEvents()
|
||||
{
|
||||
mInFlushPendingEvents = PR_TRUE;
|
||||
nsDocAccessible::ProcessPendingEvent(nsAccEvent *aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
aEvent->GetAccessible(getter_AddRefs(accessible));
|
||||
|
||||
PRUint32 length = mEventsToFire.Length();
|
||||
NS_ASSERTION(length, "How did we get here without events to fire?");
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
if (!presShell)
|
||||
length = 0; // The doc is now shut down, don't fire events in it anymore
|
||||
else {
|
||||
// Flush layout so that all the frame construction, reflow, and styles are
|
||||
// up-to-date. This will ensure we can get frames for the related nodes, as
|
||||
// well as get the most current information for calculating things like
|
||||
// visibility. We don't flush the display because we don't care about
|
||||
// painting. If no flush is necessary the method will simple return.
|
||||
presShell->FlushPendingNotifications(Flush_Layout);
|
||||
nsCOMPtr<nsIDOMNode> domNode;
|
||||
aEvent->GetDOMNode(getter_AddRefs(domNode));
|
||||
|
||||
PRUint32 eventType = aEvent->GetEventType();
|
||||
EIsFromUserInput isFromUserInput =
|
||||
aEvent->IsFromUserInput() ? eFromUserInput : eNoUserInput;
|
||||
|
||||
PRBool isAsync = aEvent->IsAsync();
|
||||
|
||||
if (domNode == gLastFocusedNode && isAsync &&
|
||||
(eventType == nsIAccessibleEvent::EVENT_SHOW ||
|
||||
eventType == nsIAccessibleEvent::EVENT_HIDE)) {
|
||||
// If frame type didn't change for this event, then we don't actually need to invalidate
|
||||
// However, we only keep track of the old frame type for the focus, where it's very
|
||||
// important not to destroy and recreate the accessible for minor style changes,
|
||||
// such as a:focus { overflow: scroll; }
|
||||
nsCOMPtr<nsIContent> focusContent(do_QueryInterface(domNode));
|
||||
if (focusContent) {
|
||||
nsIFrame *focusFrame = focusContent->GetPrimaryFrame();
|
||||
nsIAtom *newFrameType =
|
||||
(focusFrame && focusFrame->GetStyleVisibility()->IsVisible()) ?
|
||||
focusFrame->GetType() : nsnull;
|
||||
|
||||
if (newFrameType == gLastFocusedFrameType) {
|
||||
// Don't need to invalidate this current accessible, but can
|
||||
// just invalidate the children instead
|
||||
FireShowHideEvents(domNode, PR_TRUE, eventType, eNormalEvent,
|
||||
isAsync, isFromUserInput);
|
||||
return;
|
||||
}
|
||||
gLastFocusedFrameType = newFrameType;
|
||||
}
|
||||
}
|
||||
|
||||
// Process only currently queued events. In the meantime, newly appended
|
||||
// events will not be processed.
|
||||
for (PRUint32 index = 0; index < length; index ++) {
|
||||
|
||||
// No presshell means the document was shut down duiring event handling
|
||||
// by AT.
|
||||
if (!mWeakShell)
|
||||
break;
|
||||
if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
|
||||
|
||||
nsAccEvent *accEvent = mEventsToFire[index];
|
||||
nsCOMPtr<nsIAccessible> containerAccessible;
|
||||
if (accessible)
|
||||
accessible->GetParent(getter_AddRefs(containerAccessible));
|
||||
|
||||
if (accEvent->GetEventRule() == nsAccEvent::eDoNotEmit)
|
||||
continue;
|
||||
if (!containerAccessible) {
|
||||
GetAccessibleInParentChain(domNode, PR_TRUE,
|
||||
getter_AddRefs(containerAccessible));
|
||||
if (!containerAccessible)
|
||||
containerAccessible = this;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
accEvent->GetAccessible(getter_AddRefs(accessible));
|
||||
if (isAsync) {
|
||||
// For asynch show, delayed invalidatation of parent's children
|
||||
nsRefPtr<nsAccessible> containerAcc =
|
||||
nsAccUtils::QueryAccessible(containerAccessible);
|
||||
if (containerAcc)
|
||||
containerAcc->InvalidateChildren();
|
||||
|
||||
nsCOMPtr<nsIDOMNode> domNode;
|
||||
accEvent->GetDOMNode(getter_AddRefs(domNode));
|
||||
// Some show events in the subtree may have been removed to
|
||||
// avoid firing redundant events. But, we still need to make sure any
|
||||
// accessibles parenting those shown nodes lose their child references.
|
||||
InvalidateChildrenInSubtree(domNode);
|
||||
}
|
||||
|
||||
PRUint32 eventType = accEvent->GetEventType();
|
||||
EIsFromUserInput isFromUserInput =
|
||||
accEvent->IsFromUserInput() ? eFromUserInput : eNoUserInput;
|
||||
|
||||
PRBool isAsync = accEvent->IsAsync();
|
||||
|
||||
if (domNode == gLastFocusedNode && isAsync &&
|
||||
(eventType == nsIAccessibleEvent::EVENT_SHOW ||
|
||||
eventType == nsIAccessibleEvent::EVENT_HIDE)) {
|
||||
// If frame type didn't change for this event, then we don't actually need to invalidate
|
||||
// However, we only keep track of the old frame type for the focus, where it's very
|
||||
// important not to destroy and recreate the accessible for minor style changes,
|
||||
// such as a:focus { overflow: scroll; }
|
||||
nsCOMPtr<nsIContent> focusContent(do_QueryInterface(domNode));
|
||||
if (focusContent) {
|
||||
nsIFrame *focusFrame = focusContent->GetPrimaryFrame();
|
||||
nsIAtom *newFrameType =
|
||||
(focusFrame && focusFrame->GetStyleVisibility()->IsVisible()) ?
|
||||
focusFrame->GetType() : nsnull;
|
||||
|
||||
if (newFrameType == gLastFocusedFrameType) {
|
||||
// Don't need to invalidate this current accessible, but can
|
||||
// just invalidate the children instead
|
||||
FireShowHideEvents(domNode, PR_TRUE, eventType, eNormalEvent,
|
||||
isAsync, isFromUserInput);
|
||||
continue;
|
||||
}
|
||||
gLastFocusedFrameType = newFrameType;
|
||||
// Also fire text changes if the node being created could affect the text in an nsIAccessibleText parent.
|
||||
// When a node is being made visible or is inserted, the text in an ancestor hyper text will gain characters
|
||||
// At this point we now have the frame and accessible for this node if there is one. That is why we
|
||||
// wait to fire this here, instead of in InvalidateCacheSubtree(), where we wouldn't be able to calculate
|
||||
// the offset, length and text for the text change.
|
||||
if (domNode && domNode != mDOMNode) {
|
||||
nsRefPtr<nsAccEvent> textChangeEvent =
|
||||
CreateTextChangeEventForNode(containerAccessible, domNode, accessible,
|
||||
PR_TRUE, PR_TRUE, isFromUserInput);
|
||||
if (textChangeEvent) {
|
||||
// XXX Queue them up and merge the text change events
|
||||
// XXX We need a way to ignore SplitNode and JoinNode() when they
|
||||
// do not affect the text within the hypertext
|
||||
nsEventShell::FireEvent(textChangeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
|
||||
// Fire show/create events for this node or first accessible descendants of it
|
||||
FireShowHideEvents(domNode, PR_FALSE, eventType, eNormalEvent, isAsync,
|
||||
isFromUserInput);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAccessible> containerAccessible;
|
||||
if (accessible)
|
||||
accessible->GetParent(getter_AddRefs(containerAccessible));
|
||||
if (accessible) {
|
||||
if (eventType == nsIAccessibleEvent::EVENT_INTERNAL_LOAD) {
|
||||
nsRefPtr<nsDocAccessible> docAcc =
|
||||
nsAccUtils::QueryAccessibleDocument(accessible);
|
||||
NS_ASSERTION(docAcc, "No doc accessible for doc load event");
|
||||
|
||||
if (!containerAccessible) {
|
||||
GetAccessibleInParentChain(domNode, PR_TRUE,
|
||||
getter_AddRefs(containerAccessible));
|
||||
if (!containerAccessible)
|
||||
containerAccessible = this;
|
||||
}
|
||||
|
||||
if (isAsync) {
|
||||
// For asynch show, delayed invalidatation of parent's children
|
||||
nsRefPtr<nsAccessible> containerAcc =
|
||||
nsAccUtils::QueryAccessible(containerAccessible);
|
||||
if (containerAcc)
|
||||
containerAcc->InvalidateChildren();
|
||||
|
||||
// Some show events in the subtree may have been removed to
|
||||
// avoid firing redundant events. But, we still need to make sure any
|
||||
// accessibles parenting those shown nodes lose their child references.
|
||||
InvalidateChildrenInSubtree(domNode);
|
||||
}
|
||||
|
||||
// Also fire text changes if the node being created could affect the text in an nsIAccessibleText parent.
|
||||
// When a node is being made visible or is inserted, the text in an ancestor hyper text will gain characters
|
||||
// At this point we now have the frame and accessible for this node if there is one. That is why we
|
||||
// wait to fire this here, instead of in InvalidateCacheSubtree(), where we wouldn't be able to calculate
|
||||
// the offset, length and text for the text change.
|
||||
if (domNode && domNode != mDOMNode) {
|
||||
nsRefPtr<nsAccEvent> textChangeEvent =
|
||||
CreateTextChangeEventForNode(containerAccessible, domNode, accessible,
|
||||
PR_TRUE, PR_TRUE, isFromUserInput);
|
||||
if (textChangeEvent) {
|
||||
// XXX Queue them up and merge the text change events
|
||||
// XXX We need a way to ignore SplitNode and JoinNode() when they
|
||||
// do not affect the text within the hypertext
|
||||
nsEventShell::FireEvent(textChangeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire show/create events for this node or first accessible descendants of it
|
||||
FireShowHideEvents(domNode, PR_FALSE, eventType, eNormalEvent, isAsync,
|
||||
isFromUserInput);
|
||||
continue;
|
||||
if (docAcc)
|
||||
docAcc->FireDocLoadEvents(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
|
||||
}
|
||||
|
||||
if (accessible) {
|
||||
if (eventType == nsIAccessibleEvent::EVENT_INTERNAL_LOAD) {
|
||||
nsRefPtr<nsDocAccessible> docAcc =
|
||||
nsAccUtils::QueryAccessibleDocument(accessible);
|
||||
NS_ASSERTION(docAcc, "No doc accessible for doc load event");
|
||||
|
||||
if (docAcc)
|
||||
docAcc->FireDocLoadEvents(nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE);
|
||||
}
|
||||
else if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
|
||||
nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryInterface(accessible);
|
||||
PRInt32 caretOffset;
|
||||
if (accessibleText && NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) {
|
||||
else if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
|
||||
nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryInterface(accessible);
|
||||
PRInt32 caretOffset;
|
||||
if (accessibleText && NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) {
|
||||
#ifdef DEBUG_A11Y
|
||||
PRUnichar chAtOffset;
|
||||
accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset);
|
||||
printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset);
|
||||
PRUnichar chAtOffset;
|
||||
accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset);
|
||||
printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset);
|
||||
#endif
|
||||
#ifdef DEBUG_CARET
|
||||
// Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
|
||||
// line-number object attribute on it
|
||||
nsCOMPtr<nsIAccessible> accForFocus;
|
||||
GetAccService()->GetAccessibleFor(gLastFocusedNode, getter_AddRefs(accForFocus));
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accForFocus);
|
||||
// Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
|
||||
// line-number object attribute on it
|
||||
nsCOMPtr<nsIAccessible> accForFocus;
|
||||
GetAccService()->GetAccessibleFor(gLastFocusedNode, getter_AddRefs(accForFocus));
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accForFocus);
|
||||
#endif
|
||||
nsRefPtr<nsAccEvent> caretMoveEvent =
|
||||
new nsAccCaretMoveEvent(accessible, caretOffset);
|
||||
if (!caretMoveEvent)
|
||||
break; // Out of memory, break out to release kung fu death grip
|
||||
nsRefPtr<nsAccEvent> caretMoveEvent =
|
||||
new nsAccCaretMoveEvent(accessible, caretOffset);
|
||||
if (!caretMoveEvent)
|
||||
return;
|
||||
|
||||
nsEventShell::FireEvent(caretMoveEvent);
|
||||
nsEventShell::FireEvent(caretMoveEvent);
|
||||
|
||||
PRInt32 selectionCount;
|
||||
accessibleText->GetSelectionCount(&selectionCount);
|
||||
if (selectionCount) { // There's a selection so fire selection change as well
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
|
||||
accessible, PR_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||
// Fire reorder event if it's unconditional (see InvalidateCacheSubtree
|
||||
// method) or if changed node (that is the reason of this reorder event)
|
||||
// is accessible or has accessible children.
|
||||
nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(accEvent);
|
||||
if (reorderEvent->IsUnconditionalEvent() ||
|
||||
reorderEvent->HasAccessibleInReasonSubtree()) {
|
||||
nsEventShell::FireEvent(accEvent);
|
||||
PRInt32 selectionCount;
|
||||
accessibleText->GetSelectionCount(&selectionCount);
|
||||
if (selectionCount) { // There's a selection so fire selection change as well
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
|
||||
accessible, PR_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||
// Fire reorder event if it's unconditional (see InvalidateCacheSubtree
|
||||
// method) or if changed node (that is the reason of this reorder event)
|
||||
// is accessible or has accessible children.
|
||||
nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(aEvent);
|
||||
if (reorderEvent->IsUnconditionalEvent() ||
|
||||
reorderEvent->HasAccessibleInReasonSubtree()) {
|
||||
nsEventShell::FireEvent(aEvent);
|
||||
}
|
||||
else {
|
||||
nsEventShell::FireEvent(accEvent);
|
||||
}
|
||||
else {
|
||||
nsEventShell::FireEvent(aEvent);
|
||||
|
||||
// Post event processing
|
||||
if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
|
||||
// Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in
|
||||
// this subtree.
|
||||
nsCOMPtr<nsIDOMNode> hidingNode;
|
||||
accEvent->GetDOMNode(getter_AddRefs(hidingNode));
|
||||
if (hidingNode) {
|
||||
RefreshNodes(hidingNode); // Will this bite us with asynch events
|
||||
}
|
||||
// Post event processing
|
||||
if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
|
||||
// Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in
|
||||
// this subtree.
|
||||
nsCOMPtr<nsIDOMNode> hidingNode;
|
||||
aEvent->GetDOMNode(getter_AddRefs(hidingNode));
|
||||
if (hidingNode) {
|
||||
RefreshNodes(hidingNode); // Will this bite us with asynch events
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark we are ready to start event processing timer again.
|
||||
mFireEventTimerStarted = PR_FALSE;
|
||||
|
||||
// If the document accessible is alive then remove processed events from the
|
||||
// queue (otherwise they were removed on shutdown already) and reinitialize
|
||||
// queue processing callback if necessary (new events might occur duiring
|
||||
// delayed event processing).
|
||||
if (mWeakShell) {
|
||||
mEventsToFire.RemoveElementsAt(0, length);
|
||||
PreparePendingEventsFlush();
|
||||
}
|
||||
|
||||
mInFlushPendingEvents = PR_FALSE;
|
||||
NS_RELEASE_THIS(); // Release kung fu death grip.
|
||||
}
|
||||
|
||||
void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
nsDocAccessible *accessibleDoc = static_cast<nsDocAccessible*>(aClosure);
|
||||
NS_ASSERTION(accessibleDoc, "How did we get here without an accessible document?");
|
||||
if (accessibleDoc) {
|
||||
// A lot of crashes were happening here, so now we're reffing the doc
|
||||
// now until the events are flushed
|
||||
accessibleDoc->FlushPendingEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void nsDocAccessible::InvalidateChildrenInSubtree(nsIDOMNode *aStartNode)
|
||||
@ -2193,7 +2093,7 @@ nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
|
||||
PRBool isUnconditionalEvent = childAccessible ||
|
||||
aChild && nsAccUtils::HasAccessibleChildren(childNode);
|
||||
|
||||
nsCOMPtr<nsIAccessibleEvent> reorderEvent =
|
||||
nsRefPtr<nsAccEvent> reorderEvent =
|
||||
new nsAccReorderEvent(containerAccessible, isAsynch,
|
||||
isUnconditionalEvent,
|
||||
aChild ? childNode.get() : nsnull);
|
||||
|
@ -56,11 +56,11 @@ class nsIScrollableView;
|
||||
const PRUint32 kDefaultCacheSize = 256;
|
||||
|
||||
#define NS_DOCACCESSIBLE_IMPL_CID \
|
||||
{ /* 11d54d4f-f135-4b1b-80e4-6425a64f703c */ \
|
||||
0x11d54d4f, \
|
||||
0xf135, \
|
||||
0x4b1b, \
|
||||
{ 0x80, 0xe4, 0x64, 0x25, 0xa6, 0x4f, 0x70, 0x3c } \
|
||||
{ /* 5641921c-a093-4292-9dca-0b51813db57d */ \
|
||||
0x5641921c, \
|
||||
0xa093, \
|
||||
0x4292, \
|
||||
{ 0x9d, 0xca, 0x0b, 0x51, 0x81, 0x3d, 0xb5, 0x7d } \
|
||||
}
|
||||
|
||||
class nsDocAccessible : public nsHyperTextAccessibleWrap,
|
||||
@ -135,7 +135,7 @@ public:
|
||||
*
|
||||
* @param aEvent [in] the event to fire
|
||||
*/
|
||||
nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent);
|
||||
nsresult FireDelayedAccessibleEvent(nsAccEvent *aEvent);
|
||||
|
||||
/**
|
||||
* Find the accessible object in the accessibility cache that corresponds to
|
||||
@ -172,9 +172,10 @@ public:
|
||||
virtual void FireDocLoadEvents(PRUint32 aEventType);
|
||||
|
||||
/**
|
||||
* Used to flush pending events, called after timeout. See FlushPendingEvents.
|
||||
* Process the event when the queue of pending events is untwisted. Fire
|
||||
* accessible events as result of the processing.
|
||||
*/
|
||||
static void FlushEventsCallback(nsITimer *aTimer, void *aClosure);
|
||||
void ProcessPendingEvent(nsAccEvent* aEvent);
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -214,16 +215,6 @@ protected:
|
||||
*/
|
||||
void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute);
|
||||
|
||||
/**
|
||||
* Process delayed (pending) events resulted in normal events firing.
|
||||
*/
|
||||
void FlushPendingEvents();
|
||||
|
||||
/**
|
||||
* Start the timer to flush delayed (pending) events.
|
||||
*/
|
||||
nsresult PreparePendingEventsFlush();
|
||||
|
||||
/**
|
||||
* Fire text changed event for character data changed. The method is used
|
||||
* from nsIMutationObserver methods.
|
||||
@ -293,16 +284,13 @@ protected:
|
||||
void *mWnd;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsITimer> mScrollWatchTimer;
|
||||
nsCOMPtr<nsITimer> mFireEventTimer;
|
||||
PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
|
||||
PRPackedBool mIsContentLoaded;
|
||||
PRPackedBool mIsLoadCompleteFired;
|
||||
|
||||
protected:
|
||||
|
||||
PRBool mInFlushPendingEvents;
|
||||
PRBool mFireEventTimerStarted;
|
||||
nsTArray<nsRefPtr<nsAccEvent> > mEventsToFire;
|
||||
nsRefPtr<nsAccEventQueue> mEventQueue;
|
||||
|
||||
static PRUint32 gLastFocusedAccessiblesState;
|
||||
static nsIAtom *gLastFocusedFrameType;
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
#include "nsEventShell.h"
|
||||
|
||||
#include "nsAccessible.h"
|
||||
#include "nsDocAccessible.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsEventShell
|
||||
@ -95,3 +95,313 @@ nsEventShell::GetEventAttributes(nsIDOMNode *aNode,
|
||||
|
||||
PRBool nsEventShell::sEventFromUserInput = PR_FALSE;
|
||||
nsCOMPtr<nsIDOMNode> nsEventShell::sEventTargetNode;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEventQueue
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsAccEventQueue::nsAccEventQueue(nsDocAccessible *aDocument):
|
||||
mProcessingStarted(PR_FALSE), mDocument(aDocument)
|
||||
{
|
||||
}
|
||||
|
||||
nsAccEventQueue::~nsAccEventQueue()
|
||||
{
|
||||
NS_ASSERTION(mDocument, "Queue wasn't shut down!");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEventQueue: nsISupports and cycle collection
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccEventQueue)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAccEventQueue)
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocument");
|
||||
cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mDocument.get()));
|
||||
|
||||
PRUint32 i, length = tmp->mEvents.Length();
|
||||
for (i = 0; i < length; ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvents[i]");
|
||||
cb.NoteXPCOMChild(tmp->mEvents[i].get());
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsAccEventQueue)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAccEventQueue)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAccEventQueue)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEventQueue: public
|
||||
|
||||
void
|
||||
nsAccEventQueue::Push(nsAccEvent *aEvent)
|
||||
{
|
||||
mEvents.AppendElement(aEvent);
|
||||
|
||||
// Filter events.
|
||||
CoalesceEvents();
|
||||
|
||||
// Process events.
|
||||
PrepareFlush();
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::Shutdown()
|
||||
{
|
||||
mDocument = nsnull;
|
||||
mEvents.Clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsAccEventQueue: private
|
||||
|
||||
void
|
||||
nsAccEventQueue::PrepareFlush()
|
||||
{
|
||||
// If there are pending events in the queue and events flush isn't planed
|
||||
// yet start events flush asyncroniously.
|
||||
if (mEvents.Length() > 0 && !mProcessingStarted) {
|
||||
NS_DISPATCH_RUNNABLEMETHOD(Flush, this)
|
||||
mProcessingStarted = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::Flush()
|
||||
{
|
||||
// If the document accessible is now shut down, don't fire events in it
|
||||
// anymore.
|
||||
if (!mDocument)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = mDocument->GetPresShell();
|
||||
if (!presShell)
|
||||
return;
|
||||
|
||||
// Flush layout so that all the frame construction, reflow, and styles are
|
||||
// up-to-date. This will ensure we can get frames for the related nodes, as
|
||||
// well as get the most current information for calculating things like
|
||||
// visibility. We don't flush the display because we don't care about
|
||||
// painting. If no flush is necessary the method will simple return.
|
||||
presShell->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
// Process only currently queued events. Newly appended events duiring events
|
||||
// flusing won't be processed.
|
||||
PRUint32 length = mEvents.Length();
|
||||
NS_ASSERTION(length, "How did we get here without events to fire?");
|
||||
|
||||
for (PRUint32 index = 0; index < length; index ++) {
|
||||
|
||||
// No presshell means the document was shut down duiring event handling
|
||||
// by AT.
|
||||
if (!mDocument || !mDocument->HasWeakShell())
|
||||
break;
|
||||
|
||||
nsAccEvent *accEvent = mEvents[index];
|
||||
if (accEvent->mEventRule != nsAccEvent::eDoNotEmit)
|
||||
mDocument->ProcessPendingEvent(accEvent);
|
||||
}
|
||||
|
||||
// Mark we are ready to start event processing again.
|
||||
mProcessingStarted = PR_FALSE;
|
||||
|
||||
// If the document accessible is alive then remove processed events from the
|
||||
// queue (otherwise they were removed on shutdown already) and reinitialize
|
||||
// queue processing callback if necessary (new events might occur duiring
|
||||
// delayed event processing).
|
||||
if (mDocument && mDocument->HasWeakShell()) {
|
||||
mEvents.RemoveElementsAt(0, length);
|
||||
PrepareFlush();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::CoalesceEvents()
|
||||
{
|
||||
PRUint32 numQueuedEvents = mEvents.Length();
|
||||
PRInt32 tail = numQueuedEvents - 1;
|
||||
|
||||
nsAccEvent* tailEvent = mEvents[tail];
|
||||
switch(tailEvent->mEventRule) {
|
||||
case nsAccEvent::eCoalesceFromSameSubtree:
|
||||
{
|
||||
for (PRInt32 index = 0; index < tail; index ++) {
|
||||
nsAccEvent* thisEvent = mEvents[index];
|
||||
if (thisEvent->mEventType != tailEvent->mEventType)
|
||||
continue; // Different type
|
||||
|
||||
if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
|
||||
thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
|
||||
continue; // Do not need to check
|
||||
|
||||
if (thisEvent->mNode == tailEvent->mNode) {
|
||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||
CoalesceReorderEventsFromSameSource(thisEvent, tailEvent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dupe
|
||||
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
continue;
|
||||
}
|
||||
|
||||
// More older show event target (thisNode) can't be contained by recent
|
||||
// show event target (tailNode), i.e be a descendant of tailNode.
|
||||
// XXX: target of older show event caused by DOM node appending can be
|
||||
// contained by target of recent show event caused by style change.
|
||||
// XXX: target of older show event caused by style change can be
|
||||
// contained by target of recent show event caused by style change.
|
||||
PRBool thisCanBeDescendantOfTail =
|
||||
tailEvent->mEventType != nsIAccessibleEvent::EVENT_SHOW ||
|
||||
tailEvent->mIsAsync;
|
||||
|
||||
if (thisCanBeDescendantOfTail &&
|
||||
nsCoreUtils::IsAncestorOf(tailEvent->mNode, thisEvent->mNode)) {
|
||||
// thisNode is a descendant of tailNode.
|
||||
|
||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||
CoalesceReorderEventsFromSameTree(tailEvent, thisEvent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not emit thisEvent, also apply this result to sibling nodes of
|
||||
// thisNode.
|
||||
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
ApplyToSiblings(0, index, thisEvent->mEventType,
|
||||
thisEvent->mNode, nsAccEvent::eDoNotEmit);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!thisCanBeDescendantOfTail &&
|
||||
nsCoreUtils::IsAncestorOf(tailEvent->mNode, thisEvent->mNode)) {
|
||||
NS_NOTREACHED("Older event target is a descendant of recent event target!");
|
||||
}
|
||||
#endif
|
||||
|
||||
// More older hide event target (thisNode) can't contain recent hide
|
||||
// event target (tailNode), i.e. be ancestor of tailNode.
|
||||
if (tailEvent->mEventType != nsIAccessibleEvent::EVENT_HIDE &&
|
||||
nsCoreUtils::IsAncestorOf(thisEvent->mNode, tailEvent->mNode)) {
|
||||
// tailNode is a descendant of thisNode
|
||||
|
||||
if (thisEvent->mEventType == nsIAccessibleEvent::EVENT_REORDER) {
|
||||
CoalesceReorderEventsFromSameTree(thisEvent, tailEvent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not emit tailEvent, also apply this result to sibling nodes of
|
||||
// tailNode.
|
||||
tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
ApplyToSiblings(0, tail, tailEvent->mEventType,
|
||||
tailEvent->mNode, nsAccEvent::eDoNotEmit);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (tailEvent->mEventType == nsIAccessibleEvent::EVENT_HIDE &&
|
||||
nsCoreUtils::IsAncestorOf(thisEvent->mNode, tailEvent->mNode)) {
|
||||
NS_NOTREACHED("More older hide event target is an ancestor of recent hide event target!");
|
||||
}
|
||||
#endif
|
||||
|
||||
} // for (index)
|
||||
|
||||
if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
|
||||
// Not in another event node's subtree, and no other event is in this
|
||||
// event node's subtree. This event should be emitted. Apply this result
|
||||
// to sibling nodes of tailNode.
|
||||
|
||||
// We should do this in all cases even when tailEvent is hide event and
|
||||
// it's caused by DOM node removal because the rule can applied for
|
||||
// sibling event targets caused by style changes.
|
||||
ApplyToSiblings(0, tail, tailEvent->mEventType,
|
||||
tailEvent->mNode, nsAccEvent::eAllowDupes);
|
||||
}
|
||||
} break; // case eCoalesceFromSameSubtree
|
||||
|
||||
case nsAccEvent::eRemoveDupes:
|
||||
{
|
||||
// Check for repeat events.
|
||||
for (PRInt32 index = 0; index < tail; index ++) {
|
||||
nsAccEvent* accEvent = mEvents[index];
|
||||
if (accEvent->mEventType == tailEvent->mEventType &&
|
||||
accEvent->mEventRule == tailEvent->mEventRule &&
|
||||
accEvent->mNode == tailEvent->mNode) {
|
||||
accEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
}
|
||||
}
|
||||
} break; // case eRemoveDupes
|
||||
|
||||
default:
|
||||
break; // case eAllowDupes, eDoNotEmit
|
||||
} // switch
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
|
||||
PRUint32 aEventType, nsINode* aNode,
|
||||
nsAccEvent::EEventRule aEventRule)
|
||||
{
|
||||
for (PRUint32 index = aStart; index < aEnd; index ++) {
|
||||
nsAccEvent* accEvent = mEvents[index];
|
||||
if (accEvent->mEventType == aEventType &&
|
||||
accEvent->mEventRule != nsAccEvent::eDoNotEmit &&
|
||||
nsCoreUtils::AreSiblings(accEvent->mNode, aNode)) {
|
||||
accEvent->mEventRule = aEventRule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::CoalesceReorderEventsFromSameSource(nsAccEvent *aAccEvent1,
|
||||
nsAccEvent *aAccEvent2)
|
||||
{
|
||||
// Do not emit event2 if event1 is unconditional.
|
||||
nsCOMPtr<nsAccReorderEvent> reorderEvent1 = do_QueryInterface(aAccEvent1);
|
||||
if (reorderEvent1->IsUnconditionalEvent()) {
|
||||
aAccEvent2->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not emit event1 if event2 is unconditional.
|
||||
nsCOMPtr<nsAccReorderEvent> reorderEvent2 = do_QueryInterface(aAccEvent2);
|
||||
if (reorderEvent2->IsUnconditionalEvent()) {
|
||||
aAccEvent1->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not emit event2 if event1 is valid, otherwise do not emit event1.
|
||||
if (reorderEvent1->HasAccessibleInReasonSubtree())
|
||||
aAccEvent2->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
else
|
||||
aAccEvent1->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
}
|
||||
|
||||
void
|
||||
nsAccEventQueue::CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
|
||||
nsAccEvent *aDescendantAccEvent)
|
||||
{
|
||||
// Do not emit descendant event if this event is unconditional.
|
||||
nsCOMPtr<nsAccReorderEvent> reorderEvent = do_QueryInterface(aAccEvent);
|
||||
if (reorderEvent->IsUnconditionalEvent()) {
|
||||
aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not emit descendant event if this event is valid otherwise do not emit
|
||||
// this event.
|
||||
if (reorderEvent->HasAccessibleInReasonSubtree())
|
||||
aDescendantAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
else
|
||||
aAccEvent->mEventRule = nsAccEvent::eDoNotEmit;
|
||||
}
|
||||
|
@ -39,8 +39,12 @@
|
||||
#ifndef _nsEventShell_H_
|
||||
#define _nsEventShell_H_
|
||||
|
||||
#include "nsCoreUtils.h"
|
||||
#include "nsAccEvent.h"
|
||||
|
||||
/**
|
||||
* Used for everything about events.
|
||||
*/
|
||||
class nsEventShell
|
||||
{
|
||||
public:
|
||||
@ -77,4 +81,79 @@ private:
|
||||
static PRBool sEventFromUserInput;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Event queue.
|
||||
*/
|
||||
class nsAccEventQueue : public nsISupports
|
||||
{
|
||||
public:
|
||||
nsAccEventQueue(nsDocAccessible *aDocument);
|
||||
~nsAccEventQueue();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsAccEventQueue)
|
||||
|
||||
/**
|
||||
* Push event to queue, coalesce it if necessary. Start pending processing.
|
||||
*/
|
||||
void Push(nsAccEvent *aEvent);
|
||||
|
||||
/**
|
||||
* Shutdown the queue.
|
||||
*/
|
||||
void Shutdown();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Start pending events procesing asyncroniously.
|
||||
*/
|
||||
void PrepareFlush();
|
||||
|
||||
/**
|
||||
* Process pending events. It calls nsDocAccessible::ProcessPendingEvent()
|
||||
* where the real event processing is happen.
|
||||
*/
|
||||
void Flush();
|
||||
|
||||
NS_DECL_RUNNABLEMETHOD(nsAccEventQueue, Flush)
|
||||
|
||||
/**
|
||||
* Coalesce redurant events from the queue.
|
||||
*/
|
||||
void CoalesceEvents();
|
||||
|
||||
/**
|
||||
* Apply aEventRule to same type event that from sibling nodes of aDOMNode.
|
||||
* @param aEventsToFire array of pending events
|
||||
* @param aStart start index of pending events to be scanned
|
||||
* @param aEnd end index to be scanned (not included)
|
||||
* @param aEventType target event type
|
||||
* @param aDOMNode target are siblings of this node
|
||||
* @param aEventRule the event rule to be applied
|
||||
* (should be eDoNotEmit or eAllowDupes)
|
||||
*/
|
||||
void ApplyToSiblings(PRUint32 aStart, PRUint32 aEnd,
|
||||
PRUint32 aEventType, nsINode* aNode,
|
||||
nsAccEvent::EEventRule aEventRule);
|
||||
|
||||
/**
|
||||
* Do not emit one of two given reorder events fired for the same DOM node.
|
||||
*/
|
||||
void CoalesceReorderEventsFromSameSource(nsAccEvent *aAccEvent1,
|
||||
nsAccEvent *aAccEvent2);
|
||||
|
||||
/**
|
||||
* Do not emit one of two given reorder events fired for DOM nodes in the case
|
||||
* when one DOM node is in parent chain of second one.
|
||||
*/
|
||||
void CoalesceReorderEventsFromSameTree(nsAccEvent *aAccEvent,
|
||||
nsAccEvent *aDescendantAccEvent);
|
||||
|
||||
PRBool mProcessingStarted;
|
||||
nsRefPtr<nsDocAccessible> mDocument;
|
||||
nsTArray<nsRefPtr<nsAccEvent> > mEvents;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -489,7 +489,7 @@ nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
|
||||
}
|
||||
}
|
||||
else if (mCurrentARIAMenubar) {
|
||||
nsCOMPtr<nsIAccessibleEvent> menuEndEvent =
|
||||
nsRefPtr<nsAccEvent> menuEndEvent =
|
||||
new nsAccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar,
|
||||
PR_FALSE, aIsFromUserInput, nsAccEvent::eAllowDupes);
|
||||
if (menuEndEvent) {
|
||||
@ -1141,8 +1141,11 @@ nsRootAccessible::HandlePopupHidingEvent(nsIDOMNode *aNode,
|
||||
// DOMMenuItemActive events inside of a combo box that closes. The real focus
|
||||
// is on the combo box. It's also the case when a popup gets focus in ATK --
|
||||
// when it closes we need to fire an event to restore focus to where it was.
|
||||
nsCOMPtr<nsINode> node(do_QueryInterface(aNode));
|
||||
nsCOMPtr<nsINode> lastFocusedNode(do_QueryInterface(gLastFocusedNode));
|
||||
|
||||
if (gLastFocusedNode &&
|
||||
nsCoreUtils::IsAncestorOf(aNode, gLastFocusedNode)) {
|
||||
nsCoreUtils::IsAncestorOf(node, lastFocusedNode)) {
|
||||
// Focus was on or inside of a popup that's being hidden
|
||||
FireCurrentFocusEvent();
|
||||
}
|
||||
@ -1168,7 +1171,6 @@ nsRootAccessible::HandlePopupHidingEvent(nsIDOMNode *aNode,
|
||||
PR_FALSE, PR_FALSE);
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsRefPtr<nsAccessible> acc(nsAccUtils::QueryAccessible(comboboxAcc));
|
||||
nsEventShell::FireEvent(event);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1602,11 +1602,13 @@ nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
|
||||
|
||||
// No caret if the focused node is not inside this DOM node and this DOM node
|
||||
// is not inside of focused node.
|
||||
nsCOMPtr<nsINode> thisNode(do_QueryInterface(mDOMNode));
|
||||
nsCOMPtr<nsINode> lastFocusedNode(do_QueryInterface(gLastFocusedNode));
|
||||
PRBool isInsideOfFocusedNode =
|
||||
nsCoreUtils::IsAncestorOf(gLastFocusedNode, mDOMNode);
|
||||
nsCoreUtils::IsAncestorOf(lastFocusedNode, thisNode);
|
||||
|
||||
if (!isInsideOfFocusedNode && mDOMNode != gLastFocusedNode &&
|
||||
!nsCoreUtils::IsAncestorOf(mDOMNode, gLastFocusedNode))
|
||||
!nsCoreUtils::IsAncestorOf(thisNode, lastFocusedNode))
|
||||
return NS_OK;
|
||||
|
||||
// Turn the focus node and offset of the selection into caret hypretext
|
||||
@ -1627,10 +1629,12 @@ nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
|
||||
// No caret if this DOM node is inside of focused node but the selection's
|
||||
// focus point is not inside of this DOM node.
|
||||
if (isInsideOfFocusedNode) {
|
||||
nsCOMPtr<nsIDOMNode> resultNode =
|
||||
nsCOMPtr<nsIDOMNode> resultDOMNode =
|
||||
nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
|
||||
if (resultNode != mDOMNode &&
|
||||
!nsCoreUtils::IsAncestorOf(mDOMNode, resultNode))
|
||||
|
||||
nsCOMPtr<nsINode> resultNode(do_QueryInterface(resultDOMNode));
|
||||
if (resultNode != thisNode &&
|
||||
!nsCoreUtils::IsAncestorOf(thisNode, resultNode))
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1653,7 +1657,8 @@ PRInt32 nsHyperTextAccessible::GetCaretLineNumber()
|
||||
nsCOMPtr<nsIDOMNode> caretNode;
|
||||
domSel->GetFocusNode(getter_AddRefs(caretNode));
|
||||
nsCOMPtr<nsIContent> caretContent = do_QueryInterface(caretNode);
|
||||
if (!caretContent || !nsCoreUtils::IsAncestorOf(mDOMNode, caretNode)) {
|
||||
nsCOMPtr<nsINode> thisNode(do_QueryInterface(mDOMNode));
|
||||
if (!caretContent || !nsCoreUtils::IsAncestorOf(thisNode, caretContent)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -593,9 +593,6 @@ __try {
|
||||
|
||||
void nsAccessNodeWrap::InitAccessibility()
|
||||
{
|
||||
NS_ASSERTION(!gIsAccessibilityActive,
|
||||
"Accessibility was initialized already!");
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
if (prefBranch) {
|
||||
prefBranch->GetBoolPref("accessibility.disableenumvariant", &gIsEnumVariantSupportDisabled);
|
||||
@ -622,8 +619,6 @@ void nsAccessNodeWrap::ShutdownAccessibility()
|
||||
NS_IF_RELEASE(gTextEvent);
|
||||
::DestroyCaret();
|
||||
|
||||
NS_ASSERTION(gIsAccessibilityActive, "Accessibility was shutdown already!");
|
||||
|
||||
nsAccessNode::ShutdownXPAccessibility();
|
||||
}
|
||||
|
||||
|
@ -904,7 +904,7 @@ pref("toolbar.customization.usesheet", true);
|
||||
pref("toolbar.customization.usesheet", false);
|
||||
#endif
|
||||
|
||||
pref("dom.ipc.plugins.enabled", false);
|
||||
pref("dom.ipc.plugins.enabled", true);
|
||||
|
||||
#ifdef XP_WIN
|
||||
#ifndef WINCE
|
||||
|
@ -77,10 +77,6 @@
|
||||
label="©LinkCmd.label;"
|
||||
accesskey="©LinkCmd.accesskey;"
|
||||
oncommand="goDoCommand('cmd_copyLink');"/>
|
||||
<menuitem id="context-copylinktext"
|
||||
label="©LinkText2Cmd.label;"
|
||||
accesskey="©LinkText2Cmd.accesskey;"
|
||||
oncommand="gContextMenu.copyLinkText();"/>
|
||||
<menuseparator id="context-sep-copylink"/>
|
||||
<menuitem id="context-media-play"
|
||||
label="&mediaPlay.label;"
|
||||
|
@ -438,8 +438,6 @@ nsContextMenu.prototype = {
|
||||
|
||||
// Copy link location depends on whether we're on a non-mailto link.
|
||||
this.showItem("context-copylink", this.onLink && !this.onMailtoLink);
|
||||
this.showItem("context-copylinktext",
|
||||
this.onLink && !this.onImage && !this.isTextSelected);
|
||||
this.showItem("context-sep-copylink", this.onLink &&
|
||||
(this.onImage || this.onVideo || this.onAudio));
|
||||
|
||||
@ -1180,14 +1178,6 @@ nsContextMenu.prototype = {
|
||||
clipboard.copyString(addresses);
|
||||
},
|
||||
|
||||
copyLinkText: function() {
|
||||
let text = this.linkText();
|
||||
|
||||
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
|
||||
getService(Ci.nsIClipboardHelper);
|
||||
clipboard.copyString(text);
|
||||
},
|
||||
|
||||
///////////////
|
||||
// Utilities //
|
||||
///////////////
|
||||
|
@ -173,16 +173,14 @@ function runTest(testNum) {
|
||||
"context-bookmarklink", true,
|
||||
"context-savelink", true,
|
||||
"context-sendlink", true,
|
||||
"context-copylink", true,
|
||||
"context-copylinktext", true]);
|
||||
"context-copylink", true]);
|
||||
closeContextMenu();
|
||||
openContextMenuFor(mailto); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// Context menu for text mailto-link
|
||||
checkContextMenu(["context-copyemail", true,
|
||||
"context-copylinktext", true]);
|
||||
checkContextMenu(["context-copyemail", true]);
|
||||
closeContextMenu();
|
||||
openContextMenuFor(input); // Invoke context menu for next test.
|
||||
break;
|
||||
|
@ -40,6 +40,7 @@
|
||||
#endif
|
||||
|
||||
[xpcom]
|
||||
@BINPATH@/dependentlibs.list
|
||||
@BINPATH@/@DLL_PREFIX@mozjs@DLL_SUFFIX@
|
||||
@BINPATH@/@DLL_PREFIX@plc4@DLL_SUFFIX@
|
||||
@BINPATH@/@DLL_PREFIX@plds4@DLL_SUFFIX@
|
||||
|
@ -804,7 +804,6 @@ greprefs/security-prefs.js
|
||||
greprefs/xpinstall.js
|
||||
run-mozilla.sh
|
||||
firefox
|
||||
dependentlibs.list
|
||||
components/nsProgressDialog.js
|
||||
libwidget.rsrc
|
||||
#endif
|
||||
|
@ -308,8 +308,6 @@
|
||||
<!ENTITY sendAudioCmd.accesskey "n">
|
||||
<!ENTITY copyLinkCmd.label "Copy Link Location">
|
||||
<!ENTITY copyLinkCmd.accesskey "a">
|
||||
<!ENTITY copyLinkText2Cmd.label "Copy Link Text">
|
||||
<!ENTITY copyLinkText2Cmd.accesskey "x">
|
||||
<!ENTITY copyImageCmd.label "Copy Image Location">
|
||||
<!ENTITY copyImageCmd.accesskey "o">
|
||||
<!ENTITY copyImageContentsCmd.label "Copy Image">
|
||||
|
@ -495,7 +495,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
||||
return ('', False)
|
||||
else:
|
||||
log.error("readWithTimeout got error: %d", err)
|
||||
if l > 0:
|
||||
if l.value > 0:
|
||||
# we're assuming that the output is line-buffered,
|
||||
# which is not unreasonable
|
||||
return (f.readline(), False)
|
||||
@ -508,7 +508,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
|
||||
pHandle = self.ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid)
|
||||
if not pHandle:
|
||||
return False
|
||||
pExitCode = self.wintypes.DWORD()
|
||||
pExitCode = ctypes.wintypes.DWORD()
|
||||
self.ctypes.windll.kernel32.GetExitCodeProcess(pHandle, self.ctypes.byref(pExitCode))
|
||||
self.ctypes.windll.kernel32.CloseHandle(pHandle)
|
||||
if (pExitCode.value == STILL_ACTIVE):
|
||||
|
@ -80,5 +80,7 @@ if __name__ == '__main__':
|
||||
url = "http://localhost:%d/bloatcycle.html" % PORT
|
||||
appPath = os.path.join(SCRIPT_DIR, automation.DEFAULT_APP)
|
||||
status = automation.runApp(url, browserEnv, appPath, PROFILE_DIRECTORY,
|
||||
extraArgs)
|
||||
# leaktest builds are slow, give up and
|
||||
# don't use a timeout.
|
||||
extraArgs, timeout=None)
|
||||
sys.exit(status)
|
||||
|
@ -2377,8 +2377,11 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
||||
break;
|
||||
default:
|
||||
// try variant string
|
||||
rv = aBody->GetAsWString(getter_Copies(serial));
|
||||
PRUnichar* data = nsnull;
|
||||
PRUint32 len = 0;
|
||||
rv = aBody->GetAsWStringWithSize(&len, &data);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
serial.Adopt(data, len);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -337,6 +337,8 @@ _TEST_FILES = test_bug5141.html \
|
||||
file_CSP.sjs \
|
||||
file_CSP_main.html \
|
||||
file_CSP_main.js \
|
||||
test_bug540854.html \
|
||||
bug540854.sjs \
|
||||
$(NULL)
|
||||
|
||||
# Disabled; see bug 492181
|
||||
|
19
content/base/test/bug540854.sjs
Normal file
19
content/base/test/bug540854.sjs
Normal file
@ -0,0 +1,19 @@
|
||||
const CC = Components.Constructor;
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream",
|
||||
"setInputStream");
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
|
||||
var body = new BinaryInputStream(request.bodyInputStream);
|
||||
|
||||
var avail;
|
||||
var bytes = [];
|
||||
while ((avail = body.available()) > 0)
|
||||
Array.prototype.push.apply(bytes, body.readByteArray(avail));
|
||||
|
||||
var data = String.fromCharCode.apply(null, bytes);
|
||||
response.bodyOutputStream.write(data, data.length);
|
||||
}
|
48
content/base/test/test_bug540854.html
Normal file
48
content/base/test/test_bug540854.html
Normal file
@ -0,0 +1,48 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=540854
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 540854</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=540854">Mozilla Bug 540854</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 540854 **/
|
||||
|
||||
|
||||
var x;
|
||||
|
||||
function getUTF8() {
|
||||
return unescape(encodeURIComponent('\0foo'));
|
||||
}
|
||||
|
||||
function xload() {
|
||||
is(this.responseText, getUTF8(), "Unexpected responseText!");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
x = new XMLHttpRequest();
|
||||
x.open("POST", "bug540854.sjs")
|
||||
x.onload = xload;
|
||||
x.send(getUTF8());
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(runTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -208,7 +208,7 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp)
|
||||
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
|
||||
return JS_FALSE;
|
||||
|
||||
if (argc < 3 || (argc > 3 && argc < 9))
|
||||
if (argc < 3)
|
||||
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
||||
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
|
@ -195,18 +195,23 @@ nsMediaChannelStream::OnStartRequest(nsIRequest* aRequest)
|
||||
PRBool acceptsRanges = ranges.EqualsLiteral("bytes");
|
||||
|
||||
if (mOffset == 0) {
|
||||
// Look for duration headers from known Ogg content systems. In the case
|
||||
// of multiple options for obtaining the duration the order of precedence is;
|
||||
// Look for duration headers from known Ogg content systems.
|
||||
// In the case of multiple options for obtaining the duration
|
||||
// the order of precedence is:
|
||||
// 1) The Media resource metadata if possible (done by the decoder itself).
|
||||
// 2) X-Content-Duration.
|
||||
// 3) x-amz-meta-content-duration.
|
||||
// 4) Perform a seek in the decoder to find the value.
|
||||
// 2) Content-Duration message header.
|
||||
// 3) X-AMZ-Meta-Content-Duration.
|
||||
// 4) X-Content-Duration.
|
||||
// 5) Perform a seek in the decoder to find the value.
|
||||
nsCAutoString durationText;
|
||||
PRInt32 ec = 0;
|
||||
rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-Content-Duration"), durationText);
|
||||
rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("Content-Duration"), durationText);
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-AMZ-Meta-Content-Duration"), durationText);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-Content-Duration"), durationText);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
float duration = durationText.ToFloat(&ec);
|
||||
|
@ -193,6 +193,7 @@ _TEST_FILES += \
|
||||
test_contentDuration4.html \
|
||||
test_contentDuration5.html \
|
||||
test_contentDuration6.html \
|
||||
test_contentDuration7.html \
|
||||
test_delay_load.html \
|
||||
test_duration1.html \
|
||||
test_ended1.html \
|
||||
@ -217,6 +218,7 @@ _TEST_FILES += \
|
||||
contentDuration4.sjs \
|
||||
contentDuration5.sjs \
|
||||
contentDuration6.sjs \
|
||||
contentDuration7.sjs \
|
||||
$(NULL)
|
||||
# These tests disabled until we figure out random failures.
|
||||
# Bug 492821:
|
||||
|
@ -15,7 +15,7 @@ function handleRequest(request, response)
|
||||
fis.init(file, -1, -1, false);
|
||||
bis.setInputStream(fis);
|
||||
var bytes = bis.readBytes(bis.available());
|
||||
response.setHeader("X-Content-Duration", "0.233", false);
|
||||
response.setHeader("Content-Duration", "0.233", false);
|
||||
response.setHeader("Content-Length", ""+bytes.length, false);
|
||||
response.setHeader("Content-Type", "video/ogg", false);
|
||||
response.write(bytes, bytes.length);
|
||||
|
@ -16,7 +16,7 @@ function handleRequest(request, response)
|
||||
bis.setInputStream(fis);
|
||||
var bytes = bis.readBytes(bis.available());
|
||||
response.setStatusLine(request.httpVersion, 200, "Content Follows");
|
||||
response.setHeader("X-Content-Duration", "-5", false);
|
||||
response.setHeader("Content-Duration", "-5", false);
|
||||
response.setHeader("Content-Length", ""+bytes.length, false);
|
||||
response.setHeader("Content-Type", "video/ogg", false);
|
||||
response.write(bytes, bytes.length);
|
||||
|
@ -16,7 +16,7 @@ function handleRequest(request, response)
|
||||
bis.setInputStream(fis);
|
||||
var bytes = bis.readBytes(bis.available());
|
||||
response.setStatusLine(request.httpVersion, 200, "Content Follows");
|
||||
response.setHeader("X-Content-Duration", "-6", false);
|
||||
response.setHeader("Content-Duration", "-6", false);
|
||||
response.setHeader("Content-Length", ""+bytes.length, false);
|
||||
response.setHeader("Content-Type", "video/ogg", false);
|
||||
response.write(bytes, bytes.length);
|
||||
|
@ -16,7 +16,7 @@ function handleRequest(request, response)
|
||||
bis.setInputStream(fis);
|
||||
var bytes = bis.readBytes(bis.available());
|
||||
response.setStatusLine(request.httpVersion, 200, "Content Follows");
|
||||
response.setHeader("X-Content-Duration", "Invalid Float Value", false);
|
||||
response.setHeader("Content-Duration", "Invalid Float Value", false);
|
||||
response.setHeader("Content-Length", ""+bytes.length, false);
|
||||
response.setHeader("Content-Type", "video/ogg", false);
|
||||
response.write(bytes, bytes.length);
|
||||
|
23
content/media/test/contentDuration7.sjs
Normal file
23
content/media/test/contentDuration7.sjs
Normal file
@ -0,0 +1,23 @@
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
var file = Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties).
|
||||
get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
|
||||
createInstance(Components.interfaces.nsIBinaryInputStream);
|
||||
var paths = "tests/content/media/test/320x240.ogv";
|
||||
var split = paths.split("/");
|
||||
for(var i = 0; i < split.length; ++i) {
|
||||
file.append(split[i]);
|
||||
}
|
||||
fis.init(file, -1, -1, false);
|
||||
bis.setInputStream(fis);
|
||||
var bytes = bis.readBytes(bis.available());
|
||||
response.setHeader("X-Content-Duration", "0.233", false);
|
||||
response.setHeader("Content-Length", ""+bytes.length, false);
|
||||
response.setHeader("Content-Type", "video/ogg", false);
|
||||
response.write(bytes, bytes.length);
|
||||
bis.close();
|
||||
}
|
@ -13,7 +13,7 @@ var gSmallTests = [
|
||||
// Used by test_mozLoadFrom. Need one test file per decoder backend, plus
|
||||
// anything for testing clone-specific bugs.
|
||||
var gCloneTests = gSmallTests.concat([
|
||||
// Actual duration is ~200ms, we have X-Content-Duration lie about it.
|
||||
// Actual duration is ~200ms, we have Content-Duration lie about it.
|
||||
{ name:"bug520908.ogv", type:"video/ogg", duration:9000 },
|
||||
]);
|
||||
|
||||
|
27
content/media/test/test_contentDuration7.html
Normal file
27
content/media/test/test_contentDuration7.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Media test: X-Content-Duration</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function on_metadataloaded() {
|
||||
var v = document.getElementById('v');
|
||||
var d = Math.round(v.duration*1000);
|
||||
ok(d == 233, "Checking duration: " + d);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</pre>
|
||||
<video id='v'
|
||||
src='contentDuration7.sjs'
|
||||
onloadedmetadata='on_metadataloaded();'></video>
|
||||
</body>
|
||||
</html>
|
@ -223,11 +223,11 @@ nsSVGAngle::GetUnitScaleFactor() const
|
||||
switch (mSpecifiedUnitType) {
|
||||
case nsIDOMSVGAngle::SVG_ANGLETYPE_UNSPECIFIED:
|
||||
case nsIDOMSVGAngle::SVG_ANGLETYPE_DEG:
|
||||
return static_cast<float>(180.0 / M_PI);
|
||||
case nsIDOMSVGAngle::SVG_ANGLETYPE_RAD:
|
||||
return 1;
|
||||
case nsIDOMSVGAngle::SVG_ANGLETYPE_RAD:
|
||||
return static_cast<float>(M_PI / 180.0);
|
||||
case nsIDOMSVGAngle::SVG_ANGLETYPE_GRAD:
|
||||
return static_cast<float>(100.0 / M_PI);
|
||||
return 100.0f / 180.0f;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown unit type");
|
||||
return 0;
|
||||
|
@ -78,19 +78,19 @@ function runTests()
|
||||
|
||||
// angle attribute
|
||||
|
||||
marker.setAttribute("orient", "0.5rad");
|
||||
is(marker.orientAngle.baseVal.value, 0.5, "angle baseVal");
|
||||
is(marker.orientAngle.animVal.value, 0.5, "angle animVal");
|
||||
|
||||
marker.setAttribute("orient", "90deg");
|
||||
is(marker.orientAngle.baseVal.value, 90, "angle baseVal");
|
||||
is(marker.orientAngle.animVal.value, 90, "angle animVal");
|
||||
|
||||
var baseAngle = marker.orientAngle.baseVal;
|
||||
var animAngle = marker.orientAngle.animVal;
|
||||
marker.setAttribute("orient", "0.75rad");
|
||||
is(baseAngle.value, 0.75, "angle baseVal");
|
||||
is(animAngle.value, 0.75, "angle animVal");
|
||||
marker.setAttribute("orient", "45deg");
|
||||
is(baseAngle.value, 45, "angle baseVal");
|
||||
is(animAngle.value, 45, "angle animVal");
|
||||
|
||||
marker.orientAngle.baseVal.value = 0.25;
|
||||
is(marker.orientAngle.animVal.value, 0.25, "angle animVal");
|
||||
is(marker.getAttribute("orient"), "0.25rad", "angle attribute");
|
||||
marker.orientAngle.baseVal.value = 30;
|
||||
is(marker.orientAngle.animVal.value, 30, "angle animVal");
|
||||
is(marker.getAttribute("orient"), "30deg", "angle attribute");
|
||||
|
||||
// boolean attribute
|
||||
|
||||
@ -133,7 +133,7 @@ function runTests()
|
||||
is(marker.preserveAspectRatio.animVal.align, 3, "preserveAspectRatio animVal");
|
||||
is(marker.preserveAspectRatio.animVal.meetOrSlice, 1, "preserveAspectRatio.meetOrSlice animVal");
|
||||
is(marker.getAttribute("preserveAspectRatio"), "xMidYMin meet", "preserveAspectRatio attribute");
|
||||
|
||||
|
||||
var basePreserveAspectRatio = marker.preserveAspectRatio.baseVal;
|
||||
var animPreserveAspectRatio = marker.preserveAspectRatio.animVal;
|
||||
marker.setAttribute("preserveAspectRatio", "xMaxYMid slice");
|
||||
|
@ -87,6 +87,7 @@ BrowserStreamChild::StreamConstructed(
|
||||
{
|
||||
NPError rv = NPERR_NO_ERROR;
|
||||
|
||||
*stype = NP_NORMAL;
|
||||
rv = mInstance->mPluginIface->newstream(
|
||||
&mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
|
||||
&mStream, seekable, stype);
|
||||
|
@ -161,6 +161,12 @@ parent:
|
||||
rpc PPluginStream(nsCString mimeType,
|
||||
nsCString target)
|
||||
returns (NPError result);
|
||||
|
||||
parent:
|
||||
rpc PluginGotFocus();
|
||||
child:
|
||||
rpc SetPluginFocus();
|
||||
rpc UpdateWindow();
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
|
@ -684,6 +684,18 @@ PluginInstanceChild::PluginWindowProc(HWND hWnd,
|
||||
|
||||
NS_ASSERTION(self->mPluginWindowHWND == hWnd, "Wrong window!");
|
||||
|
||||
// The plugin received keyboard focus, let the parent know so the dom is up to date.
|
||||
if (message == WM_MOUSEACTIVATE)
|
||||
self->CallPluginGotFocus();
|
||||
|
||||
// Prevent lockups due to plugins making rpc calls when the parent
|
||||
// is making a synchronous SetFocus api call. (bug 541362) Add more
|
||||
// windowing events as needed for other api.
|
||||
if (message == WM_KILLFOCUS &&
|
||||
((InSendMessageEx(NULL) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND)) {
|
||||
ReplyMessage(0); // Unblock the caller
|
||||
}
|
||||
|
||||
LRESULT res = CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
|
||||
lParam);
|
||||
|
||||
@ -872,6 +884,38 @@ PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy)
|
||||
|
||||
#endif // OS_WIN
|
||||
|
||||
bool
|
||||
PluginInstanceChild::AnswerSetPluginFocus()
|
||||
{
|
||||
PR_LOG(gPluginLog, PR_LOG_DEBUG, ("%s", FULLFUNCTION));
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Parent is letting us know something set focus to the plugin.
|
||||
if (::GetFocus() == mPluginWindowHWND)
|
||||
return true;
|
||||
::SetFocus(mPluginWindowHWND);
|
||||
return true;
|
||||
#else
|
||||
NS_NOTREACHED("PluginInstanceChild::AnswerSetPluginFocus not implemented!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceChild::AnswerUpdateWindow()
|
||||
{
|
||||
PR_LOG(gPluginLog, PR_LOG_DEBUG, ("%s", FULLFUNCTION));
|
||||
|
||||
#if defined(OS_WIN)
|
||||
if (mPluginWindowHWND)
|
||||
UpdateWindow(mPluginWindowHWND);
|
||||
return true;
|
||||
#else
|
||||
NS_NOTREACHED("PluginInstanceChild::AnswerUpdateWindow not implemented!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
PPluginScriptableObjectChild*
|
||||
PluginInstanceChild::AllocPPluginScriptableObject()
|
||||
{
|
||||
|
@ -145,6 +145,12 @@ protected:
|
||||
NS_OVERRIDE virtual bool
|
||||
DeallocPStreamNotify(PStreamNotifyChild* notifyData);
|
||||
|
||||
virtual bool
|
||||
AnswerSetPluginFocus();
|
||||
|
||||
virtual bool
|
||||
AnswerUpdateWindow();
|
||||
|
||||
public:
|
||||
PluginInstanceChild(const NPPluginFuncs* aPluginIface);
|
||||
|
||||
|
@ -48,6 +48,11 @@
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windowsx.h>
|
||||
|
||||
// Plugin focus event for widget.
|
||||
extern const PRUnichar* kOOPPPluginFocusEventId;
|
||||
UINT gOOPPPluginFocusEvent =
|
||||
RegisterWindowMessage(kOOPPPluginFocusEventId);
|
||||
#endif
|
||||
|
||||
using namespace mozilla::plugins;
|
||||
@ -55,10 +60,14 @@ using namespace mozilla::plugins;
|
||||
PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
||||
NPP npp,
|
||||
const NPNetscapeFuncs* npniface)
|
||||
: mParent(parent),
|
||||
mNPP(npp),
|
||||
mNPNIface(npniface),
|
||||
mWindowType(NPWindowTypeWindow)
|
||||
: mParent(parent)
|
||||
, mNPP(npp)
|
||||
, mNPNIface(npniface)
|
||||
, mWindowType(NPWindowTypeWindow)
|
||||
#if defined(OS_WIN)
|
||||
, mPluginHWND(NULL)
|
||||
, mPluginWndProc(NULL)
|
||||
#endif // defined(XP_WIN)
|
||||
{
|
||||
}
|
||||
|
||||
@ -99,6 +108,7 @@ PluginInstanceParent::Destroy()
|
||||
|
||||
#if defined(OS_WIN)
|
||||
SharedSurfaceRelease();
|
||||
UnsubclassPluginWindow();
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
@ -360,6 +370,8 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
|
||||
}
|
||||
}
|
||||
else {
|
||||
SubclassPluginWindow(reinterpret_cast<HWND>(aWindow->window));
|
||||
|
||||
window.window = reinterpret_cast<unsigned long>(aWindow->window);
|
||||
window.x = aWindow->x;
|
||||
window.y = aWindow->y;
|
||||
@ -832,6 +844,86 @@ PluginInstanceParent::AnswerNPN_GetAuthenticationInfo(const nsCString& protocol,
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
/*
|
||||
plugin focus changes between processes
|
||||
|
||||
focus from dom -> child:
|
||||
Focs manager calls on widget to set the focus on the window.
|
||||
We pick up the resulting wm_setfocus event here, and forward
|
||||
that over ipc to the child which calls set focus on itself.
|
||||
|
||||
focus from child -> focus manager:
|
||||
Child picks up the local wm_setfocus and sends it via ipc over
|
||||
here. We then post a custom event to widget/src/windows/nswindow
|
||||
which fires off a gui event letting the browser know.
|
||||
*/
|
||||
|
||||
static const PRUnichar kPluginInstanceParentProperty[] =
|
||||
L"PluginInstanceParentProperty";
|
||||
|
||||
// static
|
||||
LRESULT CALLBACK
|
||||
PluginInstanceParent::PluginWindowHookProc(HWND hWnd,
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
PluginInstanceParent* self = reinterpret_cast<PluginInstanceParent*>(
|
||||
::GetPropW(hWnd, kPluginInstanceParentProperty));
|
||||
if (!self) {
|
||||
NS_NOTREACHED("PluginInstanceParent::PluginWindowHookProc null this ptr!");
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
NS_ASSERTION(self->mPluginHWND == hWnd, "Wrong window!");
|
||||
|
||||
switch (message) {
|
||||
case WM_SETFOCUS:
|
||||
self->CallSetPluginFocus();
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
self->UnsubclassPluginWindow();
|
||||
break;
|
||||
}
|
||||
|
||||
return ::CallWindowProc(self->mPluginWndProc, hWnd, message, wParam,
|
||||
lParam);
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceParent::SubclassPluginWindow(HWND aWnd)
|
||||
{
|
||||
NS_ASSERTION(!(mPluginHWND && aWnd != mPluginHWND),
|
||||
"PluginInstanceParent::SubclassPluginWindow hwnd is not our window!");
|
||||
|
||||
if (!mPluginHWND) {
|
||||
mPluginHWND = aWnd;
|
||||
mPluginWndProc =
|
||||
(WNDPROC)::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
|
||||
reinterpret_cast<LONG>(PluginWindowHookProc));
|
||||
bool bRes = ::SetPropW(mPluginHWND, kPluginInstanceParentProperty, this);
|
||||
NS_ASSERTION(mPluginWndProc,
|
||||
"PluginInstanceParent::SubclassPluginWindow failed to set subclass!");
|
||||
NS_ASSERTION(bRes,
|
||||
"PluginInstanceParent::SubclassPluginWindow failed to set prop!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginInstanceParent::UnsubclassPluginWindow()
|
||||
{
|
||||
if (mPluginHWND && mPluginWndProc) {
|
||||
::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
|
||||
reinterpret_cast<LONG>(mPluginWndProc));
|
||||
|
||||
::RemovePropW(mPluginHWND, kPluginInstanceParentProperty);
|
||||
|
||||
mPluginWndProc = NULL;
|
||||
mPluginHWND = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* windowless drawing helpers */
|
||||
|
||||
/*
|
||||
@ -956,3 +1048,21 @@ PluginInstanceParent::SharedSurfaceAfterPaint(NPEvent* npevent)
|
||||
}
|
||||
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
bool
|
||||
PluginInstanceParent::AnswerPluginGotFocus()
|
||||
{
|
||||
PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
|
||||
|
||||
// Currently only in use on windows - an rpc event we receive from the
|
||||
// child when it's plugin window (or one of it's children) receives keyboard
|
||||
// focus. We forward the event down to widget so the dom/focus manager can
|
||||
// be updated.
|
||||
#if defined(OS_WIN)
|
||||
::SendMessage(mPluginHWND, gOOPPPluginFocusEvent, 0, 0);
|
||||
return true;
|
||||
#else
|
||||
NS_NOTREACHED("PluginInstanceParent::AnswerPluginGotFocus not implemented!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
@ -222,6 +222,9 @@ public:
|
||||
return mNPP;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
AnswerPluginGotFocus();
|
||||
|
||||
private:
|
||||
bool InternalGetValueForNPObject(NPNVariable aVariable,
|
||||
PPluginScriptableObjectParent** aValue,
|
||||
@ -242,11 +245,18 @@ private:
|
||||
void SharedSurfaceBeforePaint(RECT &rect, NPRemoteEvent& npremoteevent);
|
||||
void SharedSurfaceAfterPaint(NPEvent* npevent);
|
||||
void SharedSurfaceRelease();
|
||||
// Used in handling parent/child forwarding of events.
|
||||
static LRESULT CALLBACK PluginWindowHookProc(HWND hWnd, UINT message,
|
||||
WPARAM wParam, LPARAM lParam);
|
||||
void SubclassPluginWindow(HWND aWnd);
|
||||
void UnsubclassPluginWindow();
|
||||
|
||||
private:
|
||||
gfx::SharedDIBWin mSharedSurfaceDib;
|
||||
nsIntRect mPluginPort;
|
||||
nsIntRect mSharedSize;
|
||||
HWND mPluginHWND;
|
||||
WNDPROC mPluginWndProc;
|
||||
#endif // defined(XP_WIN)
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,22 @@
|
||||
#include "nsRegion.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
/*
|
||||
* The SENTINEL values below guaranties that a < or >
|
||||
* comparison with it will be false for all values of the
|
||||
* underlying nscoord type. E.g. this is always false:
|
||||
* aCoord > NS_COORD_GREATER_SENTINEL
|
||||
* Setting the mRectListHead dummy rectangle to these values
|
||||
* allows us to loop without checking for the list end.
|
||||
*/
|
||||
#ifdef NS_COORD_IS_FLOAT
|
||||
#define NS_COORD_LESS_SENTINEL nscoord_MIN
|
||||
#define NS_COORD_GREATER_SENTINEL nscoord_MAX
|
||||
#else
|
||||
#define NS_COORD_LESS_SENTINEL PR_INT32_MIN
|
||||
#define NS_COORD_GREATER_SENTINEL PR_INT32_MAX
|
||||
#endif
|
||||
|
||||
// Fast inline analogues of nsRect methods for nsRegion::nsRectFast.
|
||||
// Check for emptiness is not required - it is guaranteed by caller.
|
||||
|
||||
@ -349,11 +365,11 @@ void nsRegion::InsertInPlace (RgnRect* aRect, PRBool aOptimizeOnFly)
|
||||
{
|
||||
if (aRect->y > mCurRect->y)
|
||||
{
|
||||
mRectListHead.y = PR_INT32_MAX;
|
||||
|
||||
mRectListHead.y = NS_COORD_GREATER_SENTINEL;
|
||||
while (aRect->y > mCurRect->next->y)
|
||||
mCurRect = mCurRect->next;
|
||||
|
||||
mRectListHead.x = NS_COORD_GREATER_SENTINEL;
|
||||
while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
|
||||
mCurRect = mCurRect->next;
|
||||
|
||||
@ -361,11 +377,11 @@ void nsRegion::InsertInPlace (RgnRect* aRect, PRBool aOptimizeOnFly)
|
||||
} else
|
||||
if (aRect->y < mCurRect->y)
|
||||
{
|
||||
mRectListHead.y = PR_INT32_MIN;
|
||||
|
||||
mRectListHead.y = NS_COORD_LESS_SENTINEL;
|
||||
while (aRect->y < mCurRect->prev->y)
|
||||
mCurRect = mCurRect->prev;
|
||||
|
||||
mRectListHead.x = NS_COORD_LESS_SENTINEL;
|
||||
while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
|
||||
mCurRect = mCurRect->prev;
|
||||
|
||||
@ -374,16 +390,14 @@ void nsRegion::InsertInPlace (RgnRect* aRect, PRBool aOptimizeOnFly)
|
||||
{
|
||||
if (aRect->x > mCurRect->x)
|
||||
{
|
||||
mRectListHead.y = PR_INT32_MAX;
|
||||
|
||||
mRectListHead.x = NS_COORD_GREATER_SENTINEL;
|
||||
while (aRect->y == mCurRect->next->y && aRect->x > mCurRect->next->x)
|
||||
mCurRect = mCurRect->next;
|
||||
|
||||
InsertAfter (aRect, mCurRect);
|
||||
} else
|
||||
{
|
||||
mRectListHead.y = PR_INT32_MIN;
|
||||
|
||||
mRectListHead.x = NS_COORD_LESS_SENTINEL;
|
||||
while (aRect->y == mCurRect->prev->y && aRect->x < mCurRect->prev->x)
|
||||
mCurRect = mCurRect->prev;
|
||||
|
||||
@ -671,8 +685,8 @@ nsRegion& nsRegion::And (const nsRegion& aRgn1, const nsRegion& aRgn2)
|
||||
SetToElements (0);
|
||||
pSrcRgn2->SaveLinkChain ();
|
||||
|
||||
pSrcRgn1->mRectListHead.y = PR_INT32_MAX;
|
||||
pSrcRgn2->mRectListHead.y = PR_INT32_MAX;
|
||||
pSrcRgn1->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
|
||||
pSrcRgn2->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
|
||||
|
||||
for (RgnRect* pSrcRect1 = pSrcRgn1->mRectListHead.next ;
|
||||
pSrcRect1->y < pSrcRgn2->mBoundRect.YMost () ; pSrcRect1 = pSrcRect1->next)
|
||||
@ -751,7 +765,7 @@ nsRegion& nsRegion::And (const nsRegion& aRegion, const nsRect& aRect)
|
||||
}
|
||||
|
||||
SetToElements (0);
|
||||
pSrcRegion->mRectListHead.y = PR_INT32_MAX;
|
||||
pSrcRegion->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
|
||||
|
||||
for (const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next ;
|
||||
pSrcRect->y < aRectFast.YMost () ; pSrcRect = pSrcRect->next)
|
||||
@ -1076,7 +1090,7 @@ void nsRegion::SubRect (const nsRectFast& aRect, nsRegion& aResult, nsRegion& aC
|
||||
|
||||
aResult.SetToElements (0);
|
||||
|
||||
(const_cast<nsRegion*>(pSrcRegion))->mRectListHead.y = PR_INT32_MAX;
|
||||
const_cast<nsRegion*>(pSrcRegion)->mRectListHead.y = NS_COORD_GREATER_SENTINEL;
|
||||
const RgnRect* pSrcRect = pSrcRegion->mRectListHead.next;
|
||||
|
||||
for ( ; pSrcRect->y < aRect.YMost () ; pSrcRect = pSrcRect->next)
|
||||
|
@ -449,9 +449,9 @@ gfxCoreTextFont::InitTextRun(gfxTextRun *aTextRun,
|
||||
|
||||
// If there's a possibility of any bidi, we wrap the text with direction overrides
|
||||
// to ensure neutrals or characters that were bidi-overridden in HTML behave properly.
|
||||
const UniChar beginLTR[] = { 0x202d };
|
||||
const UniChar beginRTL[] = { 0x202e };
|
||||
const UniChar endBidiWrap[] = { 0x202c };
|
||||
const UniChar beginLTR[] = { 0x202d, 0x20 };
|
||||
const UniChar beginRTL[] = { 0x202e, 0x20 };
|
||||
const UniChar endBidiWrap[] = { 0x20, 0x202c };
|
||||
|
||||
PRUint32 startOffset;
|
||||
CFStringRef stringObj;
|
||||
@ -638,8 +638,6 @@ gfxCoreTextFont::SetGlyphsFromRun(gfxTextRun *aTextRun,
|
||||
charToGlyph[offset] = NO_GLYPH;
|
||||
for (PRInt32 g = 0; g < numGlyphs; ++g) {
|
||||
PRInt32 loc = glyphToChar[g] - stringRange.location;
|
||||
if (loc == 0 && !isLTR)
|
||||
++loc; // avoid seeing initial surrogate char as "ligated" with direction override
|
||||
if (loc >= 0 && loc < stringRange.length) {
|
||||
charToGlyph[loc] = g;
|
||||
}
|
||||
|
@ -42,35 +42,36 @@ const void *const *StackTrace::Addresses(size_t* count) {
|
||||
namespace mozilla {
|
||||
|
||||
EnvironmentLog::EnvironmentLog(const char* varname)
|
||||
: fd_(NULL)
|
||||
{
|
||||
const char *e = getenv(varname);
|
||||
if (e && *e) {
|
||||
if (!strcmp(e, "-")) {
|
||||
fd_ = fdopen(dup(STDOUT_FILENO), "a");
|
||||
}
|
||||
else {
|
||||
fd_ = fopen(e, "a");
|
||||
}
|
||||
}
|
||||
if (e && *e)
|
||||
fname_ = e;
|
||||
}
|
||||
|
||||
EnvironmentLog::~EnvironmentLog()
|
||||
{
|
||||
if (fd_)
|
||||
fclose(fd_);
|
||||
}
|
||||
|
||||
void
|
||||
EnvironmentLog::print(const char* format, ...)
|
||||
{
|
||||
if (!fname_.size())
|
||||
return;
|
||||
|
||||
FILE* f;
|
||||
if (fname_.compare("-") == 0)
|
||||
f = fdopen(dup(STDOUT_FILENO), "a");
|
||||
else
|
||||
f = fopen(fname_.c_str(), "a");
|
||||
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
va_list a;
|
||||
va_start(a, format);
|
||||
if (fd_) {
|
||||
vfprintf(fd_, format, a);
|
||||
fflush(fd_);
|
||||
}
|
||||
vfprintf(f, format, a);
|
||||
va_end(a);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -78,7 +78,7 @@ public:
|
||||
void print(const char* format, ...);
|
||||
|
||||
private:
|
||||
FILE* fd_;
|
||||
std::string fname_;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(EnvironmentLog);
|
||||
};
|
||||
|
@ -238,6 +238,20 @@ bool ClientConnectToFifo(const std::string &pipe_name, int* client_socket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(CHROMIUM_MOZILLA_BUILD)
|
||||
bool SetCloseOnExec(int fd) {
|
||||
int flags = fcntl(fd, F_GETFD);
|
||||
if (flags == -1)
|
||||
return false;
|
||||
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl(fd, F_SETFD, flags) == -1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -298,6 +312,16 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
|
||||
HANDLE_EINTR(close(pipe_fds[1]));
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(CHROMIUM_MOZILLA_BUILD)
|
||||
if (!SetCloseOnExec(pipe_fds[0]) ||
|
||||
!SetCloseOnExec(pipe_fds[1])) {
|
||||
HANDLE_EINTR(close(pipe_fds[0]));
|
||||
HANDLE_EINTR(close(pipe_fds[1]));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
pipe_ = pipe_fds[0];
|
||||
client_pipe_ = pipe_fds[1];
|
||||
|
||||
|
@ -51,6 +51,48 @@
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template<>
|
||||
struct ParamTraits<PRInt8>
|
||||
{
|
||||
typedef PRInt8 paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
aMsg->WriteBytes(&aParam, sizeof(aParam));
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
const char* outp;
|
||||
if (!aMsg->ReadBytes(aIter, &outp, sizeof(*aResult)))
|
||||
return false;
|
||||
|
||||
*aResult = *reinterpret_cast<const paramType*>(outp);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<PRUint8>
|
||||
{
|
||||
typedef PRUint8 paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam)
|
||||
{
|
||||
aMsg->WriteBytes(&aParam, sizeof(aParam));
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
|
||||
{
|
||||
const char* outp;
|
||||
if (!aMsg->ReadBytes(aIter, &outp, sizeof(*aResult)))
|
||||
return false;
|
||||
|
||||
*aResult = *reinterpret_cast<const paramType*>(outp);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<nsACString>
|
||||
{
|
||||
|
@ -62,7 +62,7 @@ Types = (
|
||||
|
||||
# NSPR types
|
||||
'PRBool',
|
||||
'PRPackedBool'
|
||||
'PRPackedBool',
|
||||
'PRInt8',
|
||||
'PRUint8',
|
||||
'PRInt16',
|
||||
|
@ -6,11 +6,11 @@ namespace _ipdltest {
|
||||
protocol PTestSanity {
|
||||
|
||||
child:
|
||||
Ping(int zero, float zeroPtFive);
|
||||
Ping(int zero, float zeroPtFive, PRInt8 dummy);
|
||||
__delete__();
|
||||
|
||||
parent:
|
||||
Pong(int one, float zeroPtTwoFive);
|
||||
Pong(int one, float zeroPtTwoFive, PRUint8 dummy);
|
||||
|
||||
|
||||
state PING:
|
||||
|
@ -21,13 +21,14 @@ TestSanityParent::~TestSanityParent()
|
||||
void
|
||||
TestSanityParent::Main()
|
||||
{
|
||||
if (!SendPing(0, 0.5f))
|
||||
if (!SendPing(0, 0.5f, 0))
|
||||
fail("sending Ping");
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TestSanityParent::RecvPong(const int& one, const float& zeroPtTwoFive)
|
||||
TestSanityParent::RecvPong(const int& one, const float& zeroPtTwoFive,
|
||||
const PRUint8&/*unused*/)
|
||||
{
|
||||
if (1 != one)
|
||||
fail("invalid argument `%d', should have been `1'", one);
|
||||
@ -55,7 +56,8 @@ TestSanityChild::~TestSanityChild()
|
||||
}
|
||||
|
||||
bool
|
||||
TestSanityChild::RecvPing(const int& zero, const float& zeroPtFive)
|
||||
TestSanityChild::RecvPing(const int& zero, const float& zeroPtFive,
|
||||
const PRInt8&/*unused*/)
|
||||
{
|
||||
if (0 != zero)
|
||||
fail("invalid argument `%d', should have been `0'", zero);
|
||||
@ -63,7 +65,7 @@ TestSanityChild::RecvPing(const int& zero, const float& zeroPtFive)
|
||||
if (0.5f != zeroPtFive)
|
||||
fail("invalid argument `%g', should have been `0.5'", zeroPtFive);
|
||||
|
||||
if (!SendPong(1, 0.25f))
|
||||
if (!SendPong(1, 0.25f, 0))
|
||||
fail("sending Pong");
|
||||
return true;
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ public:
|
||||
|
||||
protected:
|
||||
NS_OVERRIDE
|
||||
virtual bool RecvPong(const int& one, const float& zeroPtTwoFive);
|
||||
virtual bool RecvPong(const int& one, const float& zeroPtTwoFive,
|
||||
const PRUint8& dummy);
|
||||
|
||||
NS_OVERRIDE
|
||||
virtual void ActorDestroy(ActorDestroyReason why)
|
||||
@ -43,7 +44,8 @@ public:
|
||||
|
||||
protected:
|
||||
NS_OVERRIDE
|
||||
virtual bool RecvPing(const int& zero, const float& zeroPtFive);
|
||||
virtual bool RecvPing(const int& zero, const float& zeroPtFive,
|
||||
const PRInt8& dummy);
|
||||
|
||||
NS_OVERRIDE
|
||||
virtual void ActorDestroy(ActorDestroyReason why)
|
||||
|
@ -802,7 +802,7 @@ class TypedArrayTemplate
|
||||
NativeType *dest = static_cast<NativeType*>(data);
|
||||
|
||||
if (ar->isDenseArray()) {
|
||||
JS_ASSERT(ar->fslots[JSSLOT_ARRAY_LENGTH] == len);
|
||||
JS_ASSERT(ar->fslots[JSSLOT_ARRAY_LENGTH] == (jsval)len);
|
||||
|
||||
jsval *src = ar->dslots;
|
||||
|
||||
@ -1215,6 +1215,7 @@ TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, jsval *argv, jsval *
|
||||
|
||||
default:
|
||||
JS_NOT_REACHED("shouldn't have gotten here");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1180,7 +1180,17 @@ UnwrapNW(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
return GetwrappedJSObject(cx, JSVAL_TO_OBJECT(v), vp);
|
||||
XPCWrappedNative *wn;
|
||||
if (!XPCNativeWrapper::GetWrappedNative(cx, JSVAL_TO_OBJECT(v), &wn)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (!wn) {
|
||||
JS_SET_RVAL(cx, vp, JSVAL_NULL);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
return GetwrappedJSObject(cx, wn->GetFlatJSObject(), vp);
|
||||
}
|
||||
|
||||
static JSFunctionSpec static_functions[] = {
|
||||
|
@ -1074,7 +1074,10 @@ InitWebGLTypes(JSContext *aJSContext, JSObject *aGlobalJSObj)
|
||||
"WebGLFloatArray"
|
||||
};
|
||||
|
||||
for(int i = 0; i < NS_ARRAY_LENGTH(webglTypes); ++i) {
|
||||
for(size_t i = 0;
|
||||
i < NS_ARRAY_LENGTH(webglTypes);
|
||||
++i)
|
||||
{
|
||||
if(!JS_GetProperty(aJSContext, aGlobalJSObj, js::TypedArray::slowClasses[webglTypes[i]].name, &v) ||
|
||||
!JS_DefineProperty(aJSContext, aGlobalJSObj, webglNames[i], v,
|
||||
NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE))
|
||||
|
@ -3,9 +3,9 @@
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=500931
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=533596
|
||||
-->
|
||||
<window title="Mozilla Bug 500931"
|
||||
<window title="Mozilla Bug 533596"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
@ -34,6 +34,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=500931
|
||||
var win = $('ifr').contentWindow;
|
||||
var utils = window.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
is(utils.getClassName(win), "XPCNativeWrapper", "win is an XPCNW");
|
||||
ok("x" in XPCNativeWrapper.unwrap(win), "actually unwrapped");
|
||||
is(utils.getClassName(XPCNativeWrapper.unwrap(win)), "XPCSafeJSObjectWrapper",
|
||||
"unwrap on an NW returns the same object");
|
||||
is(utils.getClassName(XPCNativeWrapper.unwrap(new XPCNativeWrapper(win))), "XPCSafeJSObjectWrapper",
|
||||
|
@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Inner frame for bug 500931 mochitest</title>
|
||||
<script>x = 42;</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
|
5
layout/base/crashtests/541869-1.xhtml
Normal file
5
layout/base/crashtests/541869-1.xhtml
Normal file
@ -0,0 +1,5 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" style="right: 10000px; top: 11121164%; position: fixed;"><div>X</div>
|
||||
<script>
|
||||
window.addEventListener("load", function() { document.documentElement.style.letterSpacing = '21em'; }, false);
|
||||
</script>
|
||||
</html>
|
5
layout/base/crashtests/541869-2.html
Normal file
5
layout/base/crashtests/541869-2.html
Normal file
@ -0,0 +1,5 @@
|
||||
<html style="padding: 9007199254740991%;">
|
||||
<body onload="document.getElementById('f').style.border = 'none';" style="display: inline">
|
||||
<iframe id="f"></iframe>
|
||||
</body>
|
||||
</html>
|
@ -275,3 +275,5 @@ load 536623-1.xhtml
|
||||
load 537059-1.xhtml
|
||||
load 537141-1.xhtml
|
||||
load 537562-1.xhtml
|
||||
load 541869-1.xhtml
|
||||
load 541869-2.html
|
||||
|
@ -7502,7 +7502,10 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
|
||||
// can require plugin clipping to change. If we requested a reflow,
|
||||
// we don't need to do this since the reflow will do it for us.
|
||||
nsIFrame* rootFrame = mPresShell->FrameManager()->GetRootFrame();
|
||||
presContext->RootPresContext()->UpdatePluginGeometry(rootFrame);
|
||||
nsRootPresContext* rootPC = presContext->GetRootPresContext();
|
||||
if (rootPC) {
|
||||
rootPC->UpdatePluginGeometry(rootFrame);
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup references and verify the style tree. Note that the latter needs
|
||||
|
@ -991,10 +991,13 @@ void nsCaret::GetViewForRendering(nsIFrame *caretFrame,
|
||||
if (outRelativeView && coordType == eTopLevelWindowCoordinates) {
|
||||
nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
|
||||
if (presShell) {
|
||||
nsIViewManager* vm =
|
||||
presShell->GetPresContext()->RootPresContext()->PresShell()->GetViewManager();
|
||||
if (vm) {
|
||||
vm->GetRootView(*outRelativeView);
|
||||
nsRootPresContext* rootPC =
|
||||
presShell->GetPresContext()->GetRootPresContext();
|
||||
if (rootPC) {
|
||||
nsIViewManager* vm = rootPC->PresShell()->GetViewManager();
|
||||
if (vm) {
|
||||
vm->GetRootView(*outRelativeView);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2191,7 +2191,8 @@ nsLayoutUtils::ComputeWidthDependentValue(
|
||||
return aCoord.GetCoordValue();
|
||||
}
|
||||
if (eStyleUnit_Percent == aCoord.GetUnit()) {
|
||||
return NSToCoordFloor(aContainingBlockWidth * aCoord.GetPercentValue());
|
||||
return NSToCoordFloorClamped(aContainingBlockWidth *
|
||||
aCoord.GetPercentValue());
|
||||
}
|
||||
NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
|
||||
aCoord.GetUnit() == eStyleUnit_Auto,
|
||||
@ -2224,7 +2225,8 @@ nsLayoutUtils::ComputeWidthValue(
|
||||
result -= aContentEdgeToBoxSizing;
|
||||
} else if (eStyleUnit_Percent == aCoord.GetUnit()) {
|
||||
NS_ASSERTION(aCoord.GetPercentValue() >= 0.0f, "width less than zero");
|
||||
result = NSToCoordFloor(aContainingBlockWidth * aCoord.GetPercentValue()) -
|
||||
result = NSToCoordFloorClamped(aContainingBlockWidth *
|
||||
aCoord.GetPercentValue()) -
|
||||
aContentEdgeToBoxSizing;
|
||||
} else if (eStyleUnit_Enumerated == aCoord.GetUnit()) {
|
||||
PRInt32 val = aCoord.GetIntValue();
|
||||
@ -2281,7 +2283,8 @@ nsLayoutUtils::ComputeHeightDependentValue(
|
||||
"unexpected 'containing block height'");
|
||||
|
||||
if (NS_AUTOHEIGHT != aContainingBlockHeight) {
|
||||
return NSToCoordFloor(aContainingBlockHeight * aCoord.GetPercentValue());
|
||||
return NSToCoordFloorClamped(aContainingBlockHeight *
|
||||
aCoord.GetPercentValue());
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(aCoord.GetUnit() == eStyleUnit_None ||
|
||||
|
@ -1050,7 +1050,7 @@ nsPresContext::Observe(nsISupports* aSubject,
|
||||
|
||||
// We may want to replace this with something faster, maybe caching the root prescontext
|
||||
nsRootPresContext*
|
||||
nsPresContext::RootPresContext()
|
||||
nsPresContext::GetRootPresContext()
|
||||
{
|
||||
nsPresContext* pc = this;
|
||||
for (;;) {
|
||||
@ -1064,7 +1064,7 @@ nsPresContext::RootPresContext()
|
||||
}
|
||||
}
|
||||
}
|
||||
return static_cast<nsRootPresContext*>(pc);
|
||||
return pc->IsRoot() ? static_cast<nsRootPresContext*>(pc) : nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,9 +213,13 @@ public:
|
||||
|
||||
nsIPresShell* GetPresShell() const { return mShell; }
|
||||
|
||||
// Find the prescontext for the root of the view manager hierarchy that contains
|
||||
// this prescontext.
|
||||
nsRootPresContext* RootPresContext();
|
||||
/**
|
||||
* Return the presentation context for the root of the view manager
|
||||
* hierarchy that contains this presentation context, or nsnull if it can't
|
||||
* be found (e.g. it's detached).
|
||||
*/
|
||||
nsRootPresContext* GetRootPresContext();
|
||||
virtual PRBool IsRoot() { return PR_FALSE; }
|
||||
|
||||
nsIDocument* Document() const
|
||||
{
|
||||
@ -1175,6 +1179,8 @@ public:
|
||||
*/
|
||||
void DidApplyPluginGeometryUpdates();
|
||||
|
||||
virtual PRBool IsRoot() { return PR_TRUE; }
|
||||
|
||||
private:
|
||||
nsTHashtable<nsPtrHashKey<nsObjectFrame> > mRegisteredPlugins;
|
||||
};
|
||||
|
@ -4562,7 +4562,10 @@ PresShell::UnsuppressAndInvalidate()
|
||||
mCaret->CheckCaretDrawingState();
|
||||
}
|
||||
|
||||
mPresContext->RootPresContext()->UpdatePluginGeometry(rootFrame);
|
||||
nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
|
||||
if (rootPC) {
|
||||
rootPC->UpdatePluginGeometry(rootFrame);
|
||||
}
|
||||
}
|
||||
|
||||
// now that painting is unsuppressed, focus may be set on the document
|
||||
@ -6118,8 +6121,8 @@ PresShell::HandleEvent(nsIView *aView,
|
||||
return NS_OK;
|
||||
|
||||
nsPresContext* framePresContext = frame->PresContext();
|
||||
nsPresContext* rootPresContext = framePresContext->RootPresContext();
|
||||
NS_ASSERTION(rootPresContext == mPresContext->RootPresContext(),
|
||||
nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
|
||||
NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
|
||||
"How did we end up outside the connected prescontext/viewmanager hierarchy?");
|
||||
// If we aren't starting our event dispatch from the root frame of the root prescontext,
|
||||
// then someone must be capturing the mouse. In that case we don't want to search the popup
|
||||
@ -6638,8 +6641,13 @@ PresShell::AdjustContextMenuKeyEvent(nsMouseEvent* aEvent)
|
||||
// Use the root view manager's widget since it's most likely to have one,
|
||||
// and the coordinates returned by GetCurrentItemAndPositionForElement
|
||||
// are relative to the root of the root view manager.
|
||||
mPresContext->RootPresContext()->PresShell()->GetViewManager()->
|
||||
GetRootWidget(getter_AddRefs(aEvent->widget));
|
||||
nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
|
||||
if (rootPC) {
|
||||
rootPC->PresShell()->GetViewManager()->
|
||||
GetRootWidget(getter_AddRefs(aEvent->widget));
|
||||
} else {
|
||||
aEvent->widget = nsnull;
|
||||
}
|
||||
aEvent->refPoint.x = 0;
|
||||
aEvent->refPoint.y = 0;
|
||||
|
||||
@ -7360,7 +7368,10 @@ PresShell::DoReflow(nsIFrame* target, PRBool aInterruptible)
|
||||
PostReflowEvent();
|
||||
}
|
||||
|
||||
mPresContext->RootPresContext()->UpdatePluginGeometry(target);
|
||||
nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
|
||||
if (rootPC) {
|
||||
rootPC->UpdatePluginGeometry(target);
|
||||
}
|
||||
|
||||
return !interrupted;
|
||||
}
|
||||
|
@ -128,6 +128,32 @@ iframe {
|
||||
<div style="height:300px; background:-moz-linear-gradient(top, red, black);"></div>
|
||||
</div>
|
||||
|
||||
<iframe class="testcase" id="testNoBlitInSVG" height="200" width="200"
|
||||
src="data:text/html,<body class='testcase' style='margin:0; height:300px; background:-moz-linear-gradient(top, red, black);'>">
|
||||
</iframe>
|
||||
<script>
|
||||
// We're not in XHTML, so we have to make our SVG elements with script.
|
||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||
var svg = document.createElementNS(SVG_NS, "svg");
|
||||
svg.setAttribute("style", "width: 300px; height: 300px");
|
||||
var g = document.createElementNS(SVG_NS, "g");
|
||||
g.setAttribute("transform", "translate(100,0) rotate(30)");
|
||||
var fo = document.createElementNS(SVG_NS, "foreignObject");
|
||||
fo.setAttribute("x", "0");
|
||||
fo.setAttribute("y", "0");
|
||||
fo.setAttribute("width", "200");
|
||||
fo.setAttribute("height", "200");
|
||||
var iframe = document.getElementById("testNoBlitInSVG");
|
||||
iframe.parentNode.replaceChild(svg, iframe);
|
||||
fo.appendChild(iframe);
|
||||
g.appendChild(fo);
|
||||
svg.appendChild(g);
|
||||
</script>
|
||||
|
||||
<iframe class="testcase" id="testNoBlitInTransform" height="200" width="200" style="-moz-transform-origin: 0 0; -moz-transform: translateX(100px) rotate(30deg)"
|
||||
src="data:text/html,<body class='testcase' style='margin:0; height:300px; background:-moz-linear-gradient(top, red, black);'>">
|
||||
</iframe>
|
||||
|
||||
<script>
|
||||
var testcases = document.querySelectorAll("div.testcase");
|
||||
var tests = [];
|
||||
@ -309,11 +335,41 @@ function testTableNoBackground(blitRegion, paintRegion) {
|
||||
"Should repaint area that was scrolled into view: " + paintRegion.toString());
|
||||
}
|
||||
|
||||
function testNoBlitInSVG(blitRegion, paintRegion) {
|
||||
ok(blitRegion.isEmpty(), "should not blit when in transformed SVG");
|
||||
// We're looking at regions in the coordinates of the inner iframe.
|
||||
// (Not the most useful test, but it does test the particular bug that we
|
||||
// should be repainting rather than blitting.)
|
||||
ok(paintRegion.equalsRegion(new Region([[0,0,200,200]])),
|
||||
"repaint rect must contain area completely inside scrolled region");
|
||||
}
|
||||
|
||||
function testNoBlitInTransform(blitRegion, paintRegion) {
|
||||
ok(blitRegion.isEmpty(), "should not blit when in CSS Transform");
|
||||
// We're looking at regions in the coordinates of the inner iframe.
|
||||
// (Not the most useful test, but it does test the particular bug that we
|
||||
// should be repainting rather than blitting.)
|
||||
ok(paintRegion.equalsRegion(new Region([[0,0,200,200]])),
|
||||
"repaint rect must contain area completely inside scrolled region");
|
||||
}
|
||||
|
||||
function clientRectToRect(cr)
|
||||
{
|
||||
return [cr.left, cr.top, cr.right, cr.bottom];
|
||||
}
|
||||
|
||||
// Return the ancestor-or-self of |container| that is a child of body.
|
||||
function bodyChild(container)
|
||||
{
|
||||
var prev;
|
||||
var next = container;
|
||||
do {
|
||||
prev = next;
|
||||
next = prev.parentNode;
|
||||
} while (next != document.body);
|
||||
return prev;
|
||||
}
|
||||
|
||||
function regionForReason(requests, reason)
|
||||
{
|
||||
var rects = [];
|
||||
@ -347,7 +403,7 @@ function afterPaint(event) {
|
||||
} else {
|
||||
testFunc(blitRegion, paintRegion);
|
||||
}
|
||||
tests[currentTest].container.style.display = 'none';
|
||||
bodyChild(tests[currentTest].container).style.display = 'none';
|
||||
|
||||
nextTest();
|
||||
}
|
||||
@ -360,7 +416,7 @@ function nextTest() {
|
||||
}
|
||||
|
||||
var t = tests[currentTest];
|
||||
t.container.style.display = "";
|
||||
bodyChild(t.container).style.display = "";
|
||||
setTimeout(function() {
|
||||
if (t.scrollable.getAttribute("class").match(/horizontal/)) {
|
||||
t.scrollable.scrollLeft = 20;
|
||||
@ -380,7 +436,7 @@ function runTests() {
|
||||
|
||||
for (var i = 0; i < tests.length; ++i) {
|
||||
var t = tests[i];
|
||||
t.container.style.display = "none";
|
||||
bodyChild(t.container).style.display = "none";
|
||||
// Make sure we don't remember a scroll position from history
|
||||
t.scrollable.scrollTop = 0;
|
||||
t.scrollable.scrollLeft = 0;
|
||||
|
5
layout/generic/crashtests/541277-1.html
Normal file
5
layout/generic/crashtests/541277-1.html
Normal file
@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<span>ﯤ</span><span>וֹ</span><span>ﯦ</span>
|
||||
</body>
|
||||
</html>
|
5
layout/generic/crashtests/541277-2.html
Normal file
5
layout/generic/crashtests/541277-2.html
Normal file
@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
‮X‍ 嵠
|
||||
</body>
|
||||
</html>
|
@ -285,3 +285,5 @@ load 517968.html
|
||||
load 520340.html
|
||||
load 533379-1.html
|
||||
load 533379-2.html
|
||||
load 541277-1.html
|
||||
load 541277-2.html
|
||||
|
@ -1598,7 +1598,7 @@ SortBlitRectsForCopy(nsIntPoint aPixDelta, nsTArray<nsIntRect>* aRects)
|
||||
static PRBool
|
||||
CanScrollWithBlitting(nsIFrame* aFrame)
|
||||
{
|
||||
for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
|
||||
for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
|
||||
if (f->GetStyleDisplay()->HasTransform()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
@ -1614,7 +1614,11 @@ CanScrollWithBlitting(nsIFrame* aFrame)
|
||||
|
||||
void nsGfxScrollFrameInner::ScrollVisual(nsIntPoint aPixDelta)
|
||||
{
|
||||
nsRootPresContext* rootPresContext = mOuter->PresContext()->RootPresContext();
|
||||
nsRootPresContext* rootPresContext =
|
||||
mOuter->PresContext()->GetRootPresContext();
|
||||
if (!rootPresContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsPoint offsetToView;
|
||||
nsPoint offsetToWidget;
|
||||
|
@ -615,8 +615,6 @@ nsObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
(mContent && mContent->GetCurrentDoc()->GetDisplayDocument()),
|
||||
"about to crash due to bug 136927");
|
||||
|
||||
PresContext()->RootPresContext()->UnregisterPluginForGeometryUpdates(this);
|
||||
|
||||
// we need to finish with the plugin before native window is destroyed
|
||||
// doing this in the destructor is too late.
|
||||
StopPluginInternal(PR_TRUE);
|
||||
@ -695,6 +693,9 @@ nsObjectFrame::CreateWidget(nscoord aWidth,
|
||||
viewMan->MoveViewTo(view, origin.x, origin.y);
|
||||
|
||||
if (!aViewOnly && !mWidget && usewidgets) {
|
||||
nsRootPresContext* rpc = PresContext()->GetRootPresContext();
|
||||
if (!rpc)
|
||||
return NS_ERROR_FAILURE;
|
||||
mInnerView = viewMan->CreateView(GetContentRect() - GetPosition(), view);
|
||||
if (!mInnerView) {
|
||||
NS_ERROR("Could not create inner view");
|
||||
@ -707,7 +708,6 @@ nsObjectFrame::CreateWidget(nscoord aWidth,
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsRootPresContext* rpc = PresContext()->RootPresContext();
|
||||
// XXX this breaks plugins in popups ... do we care?
|
||||
nsIWidget* parentWidget =
|
||||
rpc->PresShell()->FrameManager()->GetRootFrame()->GetWindow();
|
||||
@ -1191,16 +1191,18 @@ nsObjectFrame::ComputeWidgetGeometry(const nsRegion& aRegion,
|
||||
if (!mWidget)
|
||||
return;
|
||||
|
||||
nsIWidget::Configuration* configuration =
|
||||
aConfigurations->AppendElement();
|
||||
nsPresContext* presContext = PresContext();
|
||||
nsRootPresContext* rootPC = presContext->GetRootPresContext();
|
||||
if (!rootPC)
|
||||
return;
|
||||
|
||||
nsIWidget::Configuration* configuration = aConfigurations->AppendElement();
|
||||
if (!configuration)
|
||||
return;
|
||||
configuration->mChild = mWidget;
|
||||
|
||||
nsPresContext* presContext = PresContext();
|
||||
PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
nsIFrame* rootFrame =
|
||||
presContext->RootPresContext()->PresShell()->FrameManager()->GetRootFrame();
|
||||
nsIFrame* rootFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
|
||||
nsRect bounds = GetContentRect() + GetParent()->GetOffsetTo(rootFrame);
|
||||
configuration->mBounds = bounds.ToNearestPixels(appUnitsPerDevPixel);
|
||||
|
||||
@ -2254,6 +2256,12 @@ nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWidget) {
|
||||
nsRootPresContext* rootPC = PresContext()->GetRootPresContext();
|
||||
NS_ASSERTION(rootPC, "unable to unregister the plugin frame");
|
||||
rootPC->UnregisterPluginForGeometryUpdates(this);
|
||||
}
|
||||
|
||||
// Transfer the reference to the instance owner onto the stack so
|
||||
// that if we do end up re-entering this code, or if we unwind back
|
||||
// here witha deleted frame (this), we can still continue to stop
|
||||
|
@ -4645,8 +4645,10 @@ nsTypedSelection::DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint)
|
||||
result = mAutoScrollTimer->Stop();
|
||||
|
||||
nsPresContext* presContext = aFrame->PresContext();
|
||||
nsIFrame* rootmostFrame =
|
||||
presContext->RootPresContext()->PresShell()->FrameManager()->GetRootFrame();
|
||||
nsRootPresContext* rootPC = presContext->GetRootPresContext();
|
||||
if (!rootPC)
|
||||
return NS_OK;
|
||||
nsIFrame* rootmostFrame = rootPC->PresShell()->FrameManager()->GetRootFrame();
|
||||
nsPoint globalPoint = aPoint + aFrame->GetOffsetTo(rootmostFrame);
|
||||
|
||||
PRBool didScroll = presContext->PresShell()->
|
||||
|
@ -2102,7 +2102,7 @@ static PRBool IsJustifiableCharacter(const nsTextFragment* aFrag, PRInt32 aPos,
|
||||
PRUnichar ch = aFrag->CharAt(aPos);
|
||||
if (ch == '\n' || ch == '\t')
|
||||
return PR_TRUE;
|
||||
if (ch == ' ') {
|
||||
if (ch == ' ' || ch == CH_NBSP) {
|
||||
// Don't justify spaces that are combined with diacriticals
|
||||
if (!aFrag->Is2b())
|
||||
return PR_TRUE;
|
||||
|
@ -2,8 +2,6 @@
|
||||
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping">
|
||||
<head>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<style>
|
||||
embed { width:200px; height:200px; display:block; }
|
||||
iframe { border:none; }
|
||||
@ -50,6 +48,9 @@ function runTests() {
|
||||
checkClipRegion("p3", [[100, 100, 200, 200]]);
|
||||
checkClipRegion("p4", [[100, 100, 200, 200]]);
|
||||
checkClipRegionForFrame("f1", "p5", [[100, 100, 200, 200]]);
|
||||
|
||||
window.opener.SimpleTest.finish();
|
||||
window.close();
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
|
@ -33,12 +33,12 @@
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
var scroll = document.getElementById("scroll");
|
||||
var zbox = document.getElementById("zbox");
|
||||
var sbox = document.getElementById("sbox");
|
||||
var p1 = document.getElementById("p1");
|
||||
var d2 = document.getElementById("d2");
|
||||
|
||||
function runTests() {
|
||||
var zbox = document.getElementById("zbox");
|
||||
var sbox = document.getElementById("sbox");
|
||||
var p1 = document.getElementById("p1");
|
||||
var d2 = document.getElementById("d2");
|
||||
|
||||
checkClipRegion("p1", [[0, 0, 200, 100]]);
|
||||
checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 150], [150, 50, 200, 150], [0, 150, 200, 200]]);
|
||||
@ -47,15 +47,33 @@ function runTests() {
|
||||
checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 200], [150, 50, 200, 200]]);
|
||||
|
||||
zbox.style.zIndex = -1;
|
||||
|
||||
flush();
|
||||
// A non-zero timeout is needed on X11 (unless an XSync could be performed)
|
||||
// to delay an OOP plugin's X requests enough so that the X server processes
|
||||
// them after the parent processes requests (for the changes above).
|
||||
setTimeout(part2, 1000);
|
||||
}
|
||||
|
||||
function part2() {
|
||||
checkClipRegion("p2", [[0, 0, 200, 100], [0, 100, 50, 200], [150, 100, 200, 200]]);
|
||||
|
||||
sbox.style.background = "";
|
||||
|
||||
flush();
|
||||
setTimeout(part3, 1000);
|
||||
}
|
||||
|
||||
function part3() {
|
||||
checkClipRegion("p2", [[0, 0, 200, 200]]);
|
||||
|
||||
p1.style.zIndex = 1;
|
||||
|
||||
flush();
|
||||
setTimeout(part4, 1000);
|
||||
}
|
||||
|
||||
function part4() {
|
||||
checkClipRegion("p1", [[0, 0, 200, 200]]);
|
||||
checkClipRegion("p2", [[0, 100, 200, 200]]);
|
||||
|
||||
@ -64,8 +82,16 @@ function runTests() {
|
||||
zbox.style.zIndex = 1;
|
||||
zbox.style.top = "50.3px;"
|
||||
d2.style.top = "100.3px";
|
||||
|
||||
flush();
|
||||
setTimeout(done, 1000);
|
||||
}
|
||||
|
||||
function done() {
|
||||
checkClipRegionNoBounds("p2", [[0, 0, 200, 50], [0, 50, 50, 150], [150, 50, 200, 150], [0, 150, 200, 200]]);
|
||||
|
||||
window.opener.SimpleTest.finish();
|
||||
window.close();
|
||||
}
|
||||
|
||||
function flush() {
|
||||
|
@ -2,8 +2,6 @@
|
||||
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Plugins and Tables">
|
||||
<head>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<style>
|
||||
embed { width:300px; height:200px; display:block; }
|
||||
</style>
|
||||
@ -34,6 +32,9 @@ function runTests() {
|
||||
checkClipRegion("p1", [[0, 0, 300, 100]]);
|
||||
// p2 is partially covered by a table with an opaque background
|
||||
checkClipRegion("p2", [[0, 0, 300, 100]]);
|
||||
|
||||
window.opener.SimpleTest.finish();
|
||||
window.close();
|
||||
}
|
||||
|
||||
]]>
|
||||
|
@ -2,8 +2,6 @@
|
||||
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping: Plugins in Transforms">
|
||||
<head>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<style>
|
||||
embed { width:300px; height:200px; display:block; }
|
||||
</style>
|
||||
@ -33,6 +31,9 @@ function runTests() {
|
||||
// p1 and p2 are both in a transformed context so they should be hidden.
|
||||
checkClipRegionNoBounds("p1", []);
|
||||
checkClipRegionNoBounds("p2", []);
|
||||
|
||||
window.opener.SimpleTest.finish();
|
||||
window.close();
|
||||
}
|
||||
|
||||
]]>
|
||||
|
@ -153,9 +153,6 @@ function loaded() {
|
||||
|
||||
// Run actual test code
|
||||
runTests();
|
||||
|
||||
finish();
|
||||
window.close();
|
||||
}
|
||||
|
||||
// Need to run 'loaded' after painting is unsuppressed, or we'll set clip
|
||||
|
@ -66,7 +66,7 @@ function handleEvent(event) {
|
||||
|
||||
if (s.action) {
|
||||
// Do the action after this event cycle is done
|
||||
setTimeout(s.action, 0);
|
||||
setTimeout(s.action, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
13
layout/reftests/text/justification-2c.html
Normal file
13
layout/reftests/text/justification-2c.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
span { display:inline-block; width:100px; height:10px; background:yellow; }
|
||||
</style>
|
||||
</head>
|
||||
<!-- Test that has justification space added. -->
|
||||
<body style="text-align:justify; width:300px;">
|
||||
<span></span> <span></span>
|
||||
<span></span>
|
||||
</body>
|
||||
</html>
|
13
layout/reftests/text/justification-2d.html
Normal file
13
layout/reftests/text/justification-2d.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
span { display:inline-block; width:100px; height:10px; background:yellow; }
|
||||
</style>
|
||||
</head>
|
||||
<!-- Test that U+2007 FIGURE SPACE does not have justification space added. -->
|
||||
<body style="text-align:justify; width:300px;">
|
||||
<span></span> <span></span>
|
||||
<span></span>
|
||||
</body>
|
||||
</html>
|
@ -12,6 +12,8 @@ random-if(MOZ_WIDGET_TOOLKIT!="cocoa") == font-size-adjust-02.html font-size-adj
|
||||
== justification-1.html justification-1-ref.html
|
||||
== justification-2a.html justification-2-ref.html
|
||||
== justification-2b.html justification-2-ref.html
|
||||
== justification-2c.html justification-2-ref.html
|
||||
!= justification-2d.html justification-2-ref.html
|
||||
== line-editing-1a.html line-editing-1-ref.html
|
||||
== line-editing-1b.html line-editing-1-ref.html
|
||||
== line-editing-1c.html line-editing-1-ref.html
|
||||
|
@ -615,10 +615,6 @@ nsSVGForeignObjectFrame::InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter,
|
||||
if (rect.IsEmpty())
|
||||
return;
|
||||
|
||||
// XXX invalidate the entire covered region
|
||||
// See bug 418063
|
||||
rect.UnionRect(rect, mRect);
|
||||
|
||||
rect = nsSVGUtils::FindFilterInvalidation(this, rect);
|
||||
aOuter->InvalidateWithFlags(rect, aFlags);
|
||||
}
|
||||
|
@ -350,7 +350,9 @@ nsXULPopupManager::SetTriggerEvent(nsIDOMEvent* aEvent, nsIContent* aPopup)
|
||||
nsIPresShell* presShell = doc->GetPrimaryShell();
|
||||
if (presShell && presShell->GetPresContext()) {
|
||||
nsPresContext* rootDocPresContext =
|
||||
presShell->GetPresContext()->RootPresContext();
|
||||
presShell->GetPresContext()->GetRootPresContext();
|
||||
if (!rootDocPresContext)
|
||||
return;
|
||||
nsIFrame* rootDocumentRootFrame = rootDocPresContext->
|
||||
PresShell()->FrameManager()->GetRootFrame();
|
||||
if ((event->eventStructType == NS_MOUSE_EVENT ||
|
||||
@ -1020,8 +1022,14 @@ nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup,
|
||||
|
||||
// coordinates are relative to the root widget
|
||||
nsPresContext* rootPresContext =
|
||||
presShell->GetPresContext()->RootPresContext();
|
||||
rootPresContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(event.widget));
|
||||
presShell->GetPresContext()->GetRootPresContext();
|
||||
if (rootPresContext) {
|
||||
rootPresContext->PresShell()->GetViewManager()->
|
||||
GetRootWidget(getter_AddRefs(event.widget));
|
||||
}
|
||||
else {
|
||||
event.widget = nsnull;
|
||||
}
|
||||
|
||||
event.refPoint = mCachedMousePoint;
|
||||
nsEventDispatcher::Dispatch(aPopup, aPresContext, &event, nsnull, &status);
|
||||
|
@ -1041,7 +1041,10 @@ _geturl(NPP npp, const char* relativeURL, const char* target)
|
||||
(strncmp(relativeURL, "ftp:", 4) != 0)) {
|
||||
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *) npp->ndata;
|
||||
|
||||
const char *name = nsPluginHost::GetPluginName(inst);
|
||||
|
||||
const char *name;
|
||||
nsRefPtr<nsPluginHost> host = dont_AddRef(nsPluginHost::GetInst());
|
||||
host->GetPluginName(inst, &name);
|
||||
|
||||
if (name && strstr(name, "Adobe") && strstr(name, "Acrobat")) {
|
||||
return NPERR_NO_ERROR;
|
||||
|
@ -151,6 +151,7 @@
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentErrors.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
#include "windows.h"
|
||||
@ -161,6 +162,8 @@
|
||||
#include <gdk/gdkx.h> // for GDK_DISPLAY()
|
||||
#endif
|
||||
|
||||
using mozilla::TimeStamp;
|
||||
|
||||
// Null out a strong ref to a linked list iteratively to avoid
|
||||
// exhausting the stack (bug 486349).
|
||||
#define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_) \
|
||||
@ -226,8 +229,6 @@ PRLogModuleInfo* nsPluginLogging::gPluginLog = nsnull;
|
||||
|
||||
#define MAGIC_REQUEST_CONTEXT 0x01020304
|
||||
|
||||
static nsPluginInstanceTagList *gActivePluginList;
|
||||
|
||||
#ifdef CALL_SAFETY_ON
|
||||
PRBool gSkipPluginSafeCalls = PR_FALSE;
|
||||
#endif
|
||||
@ -453,8 +454,7 @@ public:
|
||||
|
||||
nsresult InitializeEmbedded(nsIURI *aURL,
|
||||
nsIPluginInstance* aInstance,
|
||||
nsIPluginInstanceOwner *aOwner = nsnull,
|
||||
nsIPluginHost *aHost = nsnull);
|
||||
nsIPluginInstanceOwner *aOwner = nsnull);
|
||||
|
||||
nsresult InitializeFullPage(nsIPluginInstance *aInstance);
|
||||
|
||||
@ -489,7 +489,6 @@ private:
|
||||
char *mMIMEType;
|
||||
PRUint32 mLength;
|
||||
PRInt32 mStreamType;
|
||||
nsIPluginHost *mHost;
|
||||
|
||||
// local cached file, we save the content into local cache if browser cache is not available,
|
||||
// or plugin asks stream as file and it expects file extension until bug 90558 got fixed
|
||||
@ -822,7 +821,6 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
|
||||
mOwner = nsnull;
|
||||
mInstance = nsnull;
|
||||
mPStreamListener = nsnull;
|
||||
mHost = nsnull;
|
||||
mStreamType = NP_NORMAL;
|
||||
mStartBinding = PR_FALSE;
|
||||
mAbort = PR_FALSE;
|
||||
@ -848,7 +846,6 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
|
||||
NS_IF_RELEASE(mOwner);
|
||||
NS_IF_RELEASE(mInstance);
|
||||
NS_IF_RELEASE(mPStreamListener);
|
||||
NS_IF_RELEASE(mHost);
|
||||
|
||||
// close FD of mFileCacheOutputStream if it's still open
|
||||
// or we won't be able to remove the cache file
|
||||
@ -929,12 +926,11 @@ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
|
||||
/* Called by NewEmbeddedPluginStream() - if this is called, we weren't
|
||||
* able to load the plugin, so we need to load it later once we figure
|
||||
* out the mimetype. In order to load it later, we need the plugin
|
||||
* host and instance owner.
|
||||
* instance owner.
|
||||
*/
|
||||
nsresult nsPluginStreamListenerPeer::InitializeEmbedded(nsIURI *aURL,
|
||||
nsIPluginInstance* aInstance,
|
||||
nsIPluginInstanceOwner *aOwner,
|
||||
nsIPluginHost *aHost)
|
||||
nsIPluginInstanceOwner *aOwner)
|
||||
{
|
||||
#ifdef PLUGIN_LOGGING
|
||||
nsCAutoString urlSpec;
|
||||
@ -956,9 +952,6 @@ nsresult nsPluginStreamListenerPeer::InitializeEmbedded(nsIURI *aURL,
|
||||
} else {
|
||||
mOwner = aOwner;
|
||||
NS_IF_ADDREF(mOwner);
|
||||
|
||||
mHost = aHost;
|
||||
NS_IF_ADDREF(mHost);
|
||||
}
|
||||
|
||||
mPluginStreamInfo = new nsPluginStreamInfo();
|
||||
@ -1011,33 +1004,33 @@ nsresult
|
||||
nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
// lets try to reused a file if we already have in the local plugin cache
|
||||
// we loop through all of active plugins
|
||||
// and call |nsPluginStreamInfo::UseExistingPluginCacheFile()| on opened stream
|
||||
// will return RP_TRUE if file exisrs
|
||||
// and some conditions are matched, in this case that file will be use
|
||||
// in |::OnFileAvailable()| calls w/o rewriting the file again.
|
||||
// The file will be deleted in |nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer|
|
||||
|
||||
PRBool useExistingCacheFile = PR_FALSE;
|
||||
nsPluginInstanceTag *pActivePlugins = gActivePluginList->mFirst;
|
||||
while (pActivePlugins && pActivePlugins->mStreams && !useExistingCacheFile) {
|
||||
// most recent streams are at the end of list
|
||||
PRInt32 cnt;
|
||||
pActivePlugins->mStreams->Count((PRUint32*)&cnt);
|
||||
while (--cnt >= 0 && !useExistingCacheFile) {
|
||||
nsPluginStreamListenerPeer *lp =
|
||||
reinterpret_cast<nsPluginStreamListenerPeer *>(pActivePlugins->mStreams->ElementAt(cnt));
|
||||
if (lp) {
|
||||
if (lp->mLocalCachedFile &&
|
||||
lp->mPluginStreamInfo &&
|
||||
(useExistingCacheFile =
|
||||
lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo))) {
|
||||
NS_ADDREF(mLocalCachedFile = lp->mLocalCachedFile);
|
||||
|
||||
nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
|
||||
nsTArray< nsAutoPtr<nsPluginInstanceTag> > *instanceTags = pluginHost->InstanceTagArray();
|
||||
for (PRUint32 i = 0; i < instanceTags->Length(); i++) {
|
||||
nsPluginInstanceTag *instanceTag = (*instanceTags)[i];
|
||||
if (instanceTag->mStreams) {
|
||||
// most recent streams are at the end of list
|
||||
PRInt32 cnt;
|
||||
instanceTag->mStreams->Count((PRUint32*)&cnt);
|
||||
while (--cnt >= 0) {
|
||||
nsPluginStreamListenerPeer *lp =
|
||||
reinterpret_cast<nsPluginStreamListenerPeer*>(instanceTag->mStreams->ElementAt(cnt));
|
||||
if (lp && lp->mLocalCachedFile && lp->mPluginStreamInfo) {
|
||||
useExistingCacheFile = lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo);
|
||||
if (useExistingCacheFile) {
|
||||
mLocalCachedFile = lp->mLocalCachedFile;
|
||||
NS_ADDREF(mLocalCachedFile);
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(lp);
|
||||
}
|
||||
NS_RELEASE(lp);
|
||||
}
|
||||
if (useExistingCacheFile)
|
||||
break;
|
||||
}
|
||||
pActivePlugins = pActivePlugins->mNext;
|
||||
}
|
||||
|
||||
if (!useExistingCacheFile) {
|
||||
@ -1088,15 +1081,15 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
|
||||
// add this listenerPeer to list of stream peers for this instance
|
||||
// it'll delay release of listenerPeer until nsPluginInstanceTag::~nsPluginInstanceTag
|
||||
// and the temp file is going to stay alive until then
|
||||
pActivePlugins = gActivePluginList->find(mInstance);
|
||||
if (pActivePlugins) {
|
||||
if (!pActivePlugins->mStreams &&
|
||||
(NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(pActivePlugins->mStreams))))) {
|
||||
nsPluginInstanceTag *instanceTag = pluginHost->FindInstanceTag(mInstance);
|
||||
if (instanceTag) {
|
||||
if (!instanceTag->mStreams &&
|
||||
(NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(instanceTag->mStreams))))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsISupports* supports = static_cast<nsISupports*>((static_cast<nsIStreamListener*>(this)));
|
||||
pActivePlugins->mStreams->AppendElement(supports);
|
||||
instanceTag->mStreams->AppendElement(supports);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -1225,14 +1218,16 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
|
||||
if (!mInstance && mOwner && !aContentType.IsEmpty()) {
|
||||
mOwner->GetInstance(mInstance);
|
||||
mOwner->GetWindow(window);
|
||||
if (!mInstance && mHost && window) {
|
||||
if (!mInstance && window) {
|
||||
nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
|
||||
|
||||
// determine if we need to try embedded again. FullPage takes a different code path
|
||||
PRInt32 mode;
|
||||
mOwner->GetMode(&mode);
|
||||
if (mode == NP_EMBED)
|
||||
rv = mHost->InstantiateEmbeddedPlugin(aContentType.get(), aURL, mOwner);
|
||||
rv = pluginHost->InstantiateEmbeddedPlugin(aContentType.get(), aURL, mOwner);
|
||||
else
|
||||
rv = mHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
|
||||
rv = pluginHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
|
||||
|
||||
if (NS_OK == rv) {
|
||||
// GetInstance() adds a ref
|
||||
@ -1685,8 +1680,6 @@ nsPluginHost::nsPluginHost()
|
||||
// No need to initialize members to nsnull, PR_FALSE etc because this class
|
||||
// has a zeroing operator new.
|
||||
{
|
||||
gActivePluginList = &mPluginInstanceTagList;
|
||||
|
||||
// check to see if pref is set at startup to let plugins take over in
|
||||
// full page mode for certain image mime types that we handle internally
|
||||
mPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
@ -1708,6 +1701,11 @@ nsPluginHost::nsPluginHost()
|
||||
mDefaultPluginDisabled = tmp;
|
||||
}
|
||||
|
||||
rv = mPrefService->GetBoolPref("plugin.disable", &tmp);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mPluginsDisabled = tmp;
|
||||
}
|
||||
|
||||
#ifdef WINCE
|
||||
mDefaultPluginDisabled = PR_TRUE;
|
||||
#endif
|
||||
@ -1766,32 +1764,17 @@ nsPluginHost::GetInst()
|
||||
return sInst;
|
||||
}
|
||||
|
||||
// static
|
||||
const char *
|
||||
nsPluginHost::GetPluginName(nsIPluginInstance *aPluginInstance)
|
||||
{
|
||||
nsPluginInstanceTag *plugin =
|
||||
gActivePluginList ? gActivePluginList->find(aPluginInstance) : nsnull;
|
||||
|
||||
if (plugin && plugin->mPluginTag)
|
||||
return plugin->mPluginTag->mName.get();
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PRBool nsPluginHost::IsRunningPlugin(nsPluginTag * plugin)
|
||||
{
|
||||
if (!plugin)
|
||||
return PR_FALSE;
|
||||
|
||||
// we can check for mLibrary to be non-zero and then ask nsIPluginInstance
|
||||
// in nsPluginInstanceTagList to see if plugin with matching mime type is not stopped
|
||||
if (!plugin->mLibrary)
|
||||
return PR_FALSE;
|
||||
|
||||
for (int i = 0; i < plugin->mVariants; i++) {
|
||||
nsPluginInstanceTag * p = mPluginInstanceTagList.find(plugin->mMimeTypeArray[i]);
|
||||
if (p && p->mInstance->IsRunning())
|
||||
nsPluginInstanceTag *instanceTag = FindInstanceTag(plugin->mMimeTypeArray[i]);
|
||||
if (instanceTag && instanceTag->mInstance->IsRunning())
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -1802,7 +1785,7 @@ nsresult nsPluginHost::ReloadPlugins(PRBool reloadPages)
|
||||
{
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("nsPluginHost::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n",
|
||||
reloadPages, mPluginInstanceTagList.mCount));
|
||||
reloadPages, mInstanceTags.Length()));
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
@ -1827,18 +1810,14 @@ nsresult nsPluginHost::ReloadPlugins(PRBool reloadPages)
|
||||
return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> instsToReload;
|
||||
|
||||
if (reloadPages) {
|
||||
NS_NewISupportsArray(getter_AddRefs(instsToReload));
|
||||
|
||||
// Then stop any running plugin instances but hold on to the documents in the array
|
||||
// We are going to need to restart the instances in these documents later
|
||||
mPluginInstanceTagList.stopRunning(instsToReload, nsnull);
|
||||
StopRunningInstances(instsToReload, nsnull);
|
||||
}
|
||||
|
||||
// clean active plugin list
|
||||
mPluginInstanceTagList.removeAllStopped();
|
||||
|
||||
// shutdown plugins and kill the list if there are no running plugins
|
||||
nsRefPtr<nsPluginTag> prev;
|
||||
nsRefPtr<nsPluginTag> next;
|
||||
@ -1887,7 +1866,7 @@ nsresult nsPluginHost::ReloadPlugins(PRBool reloadPages)
|
||||
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("nsPluginHost::ReloadPlugins End active_instance_count=%d\n",
|
||||
mPluginInstanceTagList.mCount));
|
||||
mInstanceTags.Length()));
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -2209,10 +2188,7 @@ NS_IMETHODIMP nsPluginHost::Destroy()
|
||||
|
||||
// we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
|
||||
// for those plugins who want it
|
||||
mPluginInstanceTagList.stopRunning(nsnull, nsnull);
|
||||
|
||||
// at this point nsIPlugin::Shutdown calls will be performed if needed
|
||||
mPluginInstanceTagList.shutdown();
|
||||
StopRunningInstances(nsnull, nsnull);
|
||||
|
||||
nsPluginTag *pluginTag;
|
||||
for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
|
||||
@ -2254,6 +2230,29 @@ void nsPluginHost::UnloadUnusedLibraries()
|
||||
mUnusedLibraries.Clear();
|
||||
}
|
||||
|
||||
void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag)
|
||||
{
|
||||
PRBool hasInstance = PR_FALSE;
|
||||
for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
|
||||
if (mInstanceTags[i]->mPluginTag == aPluginTag) {
|
||||
hasInstance = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasInstance) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
||||
PRBool unloadPluginsASAP = PR_FALSE;
|
||||
rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
|
||||
if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
|
||||
aPluginTag->TryUnloadPlugin();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPluginHost::GetPluginTempDir(nsIFile **aDir)
|
||||
{
|
||||
@ -2602,7 +2601,7 @@ nsresult nsPluginHost::FindStoppedPluginForURL(nsIURI* aURL,
|
||||
|
||||
aURL->GetAsciiSpec(url);
|
||||
|
||||
nsPluginInstanceTag *instanceTag = mPluginInstanceTagList.findStopped(url.get());
|
||||
nsPluginInstanceTag *instanceTag = FindStoppedInstanceTag(url.get());
|
||||
|
||||
if (instanceTag && !instanceTag->mInstance->IsRunning()) {
|
||||
NPWindow* window = nsnull;
|
||||
@ -2646,12 +2645,11 @@ nsresult nsPluginHost::AddInstanceToActiveList(nsCOMPtr<nsIPlugin> aPlugin,
|
||||
NS_ASSERTION(pluginTag, "Plugin tag not found");
|
||||
}
|
||||
|
||||
nsPluginInstanceTag * plugin = new nsPluginInstanceTag(pluginTag, aInstance, url.get(), aDefaultPlugin);
|
||||
|
||||
if (!plugin)
|
||||
nsPluginInstanceTag *instanceTag = new nsPluginInstanceTag(pluginTag, aInstance, url.get(), aDefaultPlugin);
|
||||
if (!instanceTag)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mPluginInstanceTagList.add(plugin);
|
||||
mInstanceTags.AppendElement(instanceTag);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -3694,6 +3692,9 @@ NS_IMETHODIMP nsPluginHost::LoadPlugins()
|
||||
if (mPluginsLoaded)
|
||||
return NS_OK;
|
||||
|
||||
if (mPluginsDisabled)
|
||||
return NS_OK;
|
||||
|
||||
PRBool pluginschanged;
|
||||
nsresult rv = FindPlugins(PR_TRUE, &pluginschanged);
|
||||
if (NS_FAILED(rv))
|
||||
@ -3910,8 +3911,7 @@ nsPluginHost::UpdatePluginInfo(nsPluginTag* aPluginTag)
|
||||
|
||||
nsCOMPtr<nsISupportsArray> instsToReload;
|
||||
NS_NewISupportsArray(getter_AddRefs(instsToReload));
|
||||
mPluginInstanceTagList.stopRunning(instsToReload, aPluginTag);
|
||||
mPluginInstanceTagList.removeAllStopped();
|
||||
StopRunningInstances(instsToReload, aPluginTag);
|
||||
|
||||
PRUint32 c;
|
||||
if (instsToReload && NS_SUCCEEDED(instsToReload->Count(&c)) && c > 0) {
|
||||
@ -4539,40 +4539,72 @@ nsPluginHost::StopPluginInstance(nsIPluginInstance* aInstance)
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance));
|
||||
|
||||
nsPluginInstanceTag * plugin = mPluginInstanceTagList.find(aInstance);
|
||||
aInstance->Stop();
|
||||
|
||||
if (plugin) {
|
||||
nsPluginInstanceTag * instanceTag = FindInstanceTag(aInstance);
|
||||
if (instanceTag) {
|
||||
// if the plugin does not want to be 'cached' just remove it
|
||||
PRBool doCache = PR_TRUE;
|
||||
aInstance->ShouldCache(&doCache);
|
||||
if (!doCache) {
|
||||
PRLibrary * library = nsnull;
|
||||
if (plugin->mPluginTag)
|
||||
library = plugin->mPluginTag->mLibrary;
|
||||
|
||||
mPluginInstanceTagList.remove(plugin);
|
||||
} else {
|
||||
// if it is allowed to be cached simply stop it, but first we should check
|
||||
// if we haven't exceeded the maximum allowed number of cached instances
|
||||
|
||||
if (doCache) {
|
||||
// try to get the max cached plugins from a pref or use default
|
||||
PRUint32 max_num;
|
||||
PRUint32 cachedPluginLimit;
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (mPrefService)
|
||||
rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&max_num);
|
||||
rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&cachedPluginLimit);
|
||||
if (NS_FAILED(rv))
|
||||
max_num = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
|
||||
|
||||
if (mPluginInstanceTagList.getStoppedCount() >= max_num) {
|
||||
nsPluginInstanceTag * oldest = mPluginInstanceTagList.findOldestStopped();
|
||||
if (oldest != nsnull)
|
||||
mPluginInstanceTagList.remove(oldest);
|
||||
cachedPluginLimit = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
|
||||
|
||||
if (StoppedInstanceTagCount() >= cachedPluginLimit) {
|
||||
nsPluginInstanceTag * oldestInstanceTag = FindOldestStoppedInstanceTag();
|
||||
if (oldestInstanceTag) {
|
||||
nsPluginTag* pluginTag = oldestInstanceTag->mPluginTag;
|
||||
mInstanceTags.RemoveElement(oldestInstanceTag);
|
||||
OnPluginInstanceDestroyed(pluginTag);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nsPluginTag* pluginTag = instanceTag->mPluginTag;
|
||||
mInstanceTags.RemoveElement(instanceTag);
|
||||
OnPluginInstanceDestroyed(pluginTag);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPluginInstanceTag*
|
||||
nsPluginHost::FindOldestStoppedInstanceTag()
|
||||
{
|
||||
nsPluginInstanceTag *oldestInstanceTag = nsnull;
|
||||
TimeStamp oldestTime = TimeStamp::Now();
|
||||
for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
|
||||
nsPluginInstanceTag *instanceTag = mInstanceTags[i];
|
||||
if (instanceTag->mInstance->IsRunning())
|
||||
continue;
|
||||
|
||||
TimeStamp time = instanceTag->mInstance->LastStopTime();
|
||||
if (time < oldestTime) {
|
||||
oldestTime = time;
|
||||
oldestInstanceTag = instanceTag;
|
||||
}
|
||||
}
|
||||
|
||||
return oldestInstanceTag;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsPluginHost::StoppedInstanceTagCount()
|
||||
{
|
||||
PRUint32 stoppedCount = 0;
|
||||
for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
|
||||
nsPluginInstanceTag *instanceTag = mInstanceTags[i];
|
||||
if (!instanceTag->mInstance->IsRunning())
|
||||
stoppedCount++;
|
||||
}
|
||||
return stoppedCount;
|
||||
}
|
||||
|
||||
nsresult nsPluginHost::NewEmbeddedPluginStreamListener(nsIURI* aURL,
|
||||
nsIPluginInstanceOwner *aOwner,
|
||||
nsIPluginInstance* aInstance,
|
||||
@ -4595,7 +4627,7 @@ nsresult nsPluginHost::NewEmbeddedPluginStreamListener(nsIURI* aURL,
|
||||
if (aInstance != nsnull)
|
||||
rv = listener->InitializeEmbedded(aURL, aInstance);
|
||||
else if (aOwner != nsnull)
|
||||
rv = listener->InitializeEmbedded(aURL, nsnull, aOwner, this);
|
||||
rv = listener->InitializeEmbedded(aURL, nsnull, aOwner);
|
||||
else
|
||||
rv = NS_ERROR_ILLEGAL_VALUE;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
@ -4655,7 +4687,7 @@ nsresult nsPluginHost::NewFullPagePluginStream(nsIStreamListener *&aStreamListen
|
||||
NS_ADDREF(listener);
|
||||
|
||||
// add peer to list of stream peers for this instance
|
||||
nsPluginInstanceTag * p = mPluginInstanceTagList.find(aInstance);
|
||||
nsPluginInstanceTag * p = FindInstanceTag(aInstance);
|
||||
if (p) {
|
||||
if (!p->mStreams && (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(p->mStreams)))))
|
||||
return rv;
|
||||
@ -4677,8 +4709,8 @@ NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
|
||||
}
|
||||
if (!nsCRT::strcmp(NS_PRIVATE_BROWSING_SWITCH_TOPIC, aTopic)) {
|
||||
// inform all active plugins of changed private mode state
|
||||
for (nsPluginInstanceTag* ap = mPluginInstanceTagList.mFirst; ap; ap = ap->mNext) {
|
||||
nsNPAPIPluginInstance* pi = static_cast<nsNPAPIPluginInstance*>(ap->mInstance);
|
||||
for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
|
||||
nsNPAPIPluginInstance* pi = static_cast<nsNPAPIPluginInstance*>(mInstanceTags[i]->mInstance);
|
||||
pi->PrivateModeStateChanged();
|
||||
}
|
||||
}
|
||||
@ -4740,7 +4772,7 @@ nsPluginHost::HandleBadPlugin(PRLibrary* aLibrary, nsIPluginInstance *aInstance)
|
||||
|
||||
// add plugin name to the message
|
||||
nsCString pluginname;
|
||||
nsPluginInstanceTag * p = mPluginInstanceTagList.find(aInstance);
|
||||
nsPluginInstanceTag * p = FindInstanceTag(aInstance);
|
||||
if (p) {
|
||||
nsPluginTag * tag = p->mPluginTag;
|
||||
if (tag) {
|
||||
@ -5066,7 +5098,12 @@ NS_IMETHODIMP
|
||||
nsPluginHost::GetPluginName(nsIPluginInstance *aPluginInstance,
|
||||
const char** aPluginName)
|
||||
{
|
||||
*aPluginName = GetPluginName(aPluginInstance);
|
||||
nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance);
|
||||
if (!instanceTag || !instanceTag->mPluginTag)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aPluginName = instanceTag->mPluginTag->mName.get();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -5076,13 +5113,12 @@ nsPluginHost::GetPluginTagForInstance(nsIPluginInstance *aPluginInstance,
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPluginInstance);
|
||||
NS_ENSURE_ARG_POINTER(aPluginTag);
|
||||
|
||||
nsPluginInstanceTag *plugin =
|
||||
gActivePluginList ? gActivePluginList->find(aPluginInstance) : nsnull;
|
||||
|
||||
NS_ENSURE_TRUE(plugin && plugin->mPluginTag, NS_ERROR_FAILURE);
|
||||
nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance);
|
||||
|
||||
NS_ENSURE_TRUE(instanceTag && instanceTag->mPluginTag, NS_ERROR_FAILURE);
|
||||
|
||||
*aPluginTag = plugin->mPluginTag;
|
||||
*aPluginTag = instanceTag->mPluginTag;
|
||||
NS_ADDREF(*aPluginTag);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -5169,32 +5205,30 @@ NS_IMETHODIMP nsPluginHost::Notify(nsITimer* timer)
|
||||
void
|
||||
nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin)
|
||||
{
|
||||
nsPluginTag* plugin = FindTagForPlugin(aPlugin);
|
||||
if (!plugin) {
|
||||
nsPluginTag* pluginTag = FindTagForPlugin(aPlugin);
|
||||
if (!pluginTag) {
|
||||
NS_WARNING("nsPluginTag not found in nsPluginHost::PluginCrashed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Invalidate each nsPluginInstanceTag for the crashed plugin
|
||||
|
||||
nsPluginInstanceTag** pinstancetag = &mPluginInstanceTagList.mFirst;
|
||||
while (*pinstancetag) {
|
||||
nsPluginInstanceTag* instancetag = *pinstancetag;
|
||||
if (instancetag->mPluginTag == plugin) {
|
||||
for (PRUint32 i = mInstanceTags.Length(); i > 0; i--) {
|
||||
nsPluginInstanceTag* instanceTag = mInstanceTags[i - 1];
|
||||
if (instanceTag->mPluginTag == pluginTag) {
|
||||
// notify the content node (nsIObjectLoadingContent) that the plugin has crashed
|
||||
nsCOMPtr<nsIDOMElement> domElement;
|
||||
instancetag->mInstance->GetDOMElement(getter_AddRefs(domElement));
|
||||
instanceTag->mInstance->GetDOMElement(getter_AddRefs(domElement));
|
||||
nsCOMPtr<nsIObjectLoadingContent> objectContent(do_QueryInterface(domElement));
|
||||
if (objectContent) {
|
||||
objectContent->PluginCrashed();
|
||||
}
|
||||
|
||||
instanceTag->mInstance->Stop();
|
||||
|
||||
instancetag->mInstance->Stop();
|
||||
*pinstancetag = (*pinstancetag)->mNext;
|
||||
delete instancetag;
|
||||
}
|
||||
else {
|
||||
pinstancetag = &(*pinstancetag)->mNext;
|
||||
nsPluginTag* pluginTag = instanceTag->mPluginTag;
|
||||
mInstanceTags.RemoveElement(instanceTag);
|
||||
OnPluginInstanceDestroyed(pluginTag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5202,10 +5236,95 @@ nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin)
|
||||
// out nsPluginTag.mEntryPoint. The next time we try to create an
|
||||
// instance of this plugin we reload it (launch a new plugin process).
|
||||
|
||||
plugin->mEntryPoint = nsnull;
|
||||
pluginTag->mEntryPoint = nsnull;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsPluginInstanceTag*
|
||||
nsPluginHost::FindInstanceTag(nsIPluginInstance *instance)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
|
||||
nsPluginInstanceTag *instanceTag = mInstanceTags[i];
|
||||
if (instanceTag->mInstance == instance)
|
||||
return instanceTag;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsPluginInstanceTag*
|
||||
nsPluginHost::FindInstanceTag(const char *mimetype)
|
||||
{
|
||||
PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
|
||||
|
||||
for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
|
||||
nsPluginInstanceTag* instanceTag = mInstanceTags[i];
|
||||
// give it some special treatment for the default plugin first
|
||||
// because we cannot tell the default plugin by asking instance for a mime type
|
||||
if (defaultplugin && instanceTag->mDefaultPlugin)
|
||||
return instanceTag;
|
||||
|
||||
if (!instanceTag->mInstance)
|
||||
continue;
|
||||
|
||||
const char* mt;
|
||||
nsresult rv = instanceTag->mInstance->GetMIMEType(&mt);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
if (PL_strcasecmp(mt, mimetype) == 0)
|
||||
return instanceTag;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsPluginInstanceTag*
|
||||
nsPluginHost::FindStoppedInstanceTag(const char * url)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) {
|
||||
nsPluginInstanceTag *instanceTag = mInstanceTags[i];
|
||||
if (!PL_strcmp(url, instanceTag->mURL) && !instanceTag->mInstance->IsRunning())
|
||||
return instanceTag;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginHost::StopRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag)
|
||||
{
|
||||
for (PRInt32 i = mInstanceTags.Length(); i > 0; i--) {
|
||||
nsPluginInstanceTag *instanceTag = mInstanceTags[i - 1];
|
||||
nsNPAPIPluginInstance* instance = instanceTag->mInstance;
|
||||
if (instance->IsRunning() && (!aPluginTag || aPluginTag == instanceTag->mPluginTag)) {
|
||||
instance->SetWindow(nsnull);
|
||||
instance->Stop();
|
||||
|
||||
// If we've been passed an array to return, lets collect all our documents,
|
||||
// removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
|
||||
// to kickstart our instances.
|
||||
if (aReloadDocs) {
|
||||
nsCOMPtr<nsIPluginInstanceOwner> owner;
|
||||
instance->GetOwner(getter_AddRefs(owner));
|
||||
if (owner) {
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
owner->GetDocument(getter_AddRefs(doc));
|
||||
if (doc && aReloadDocs->IndexOf(doc) == -1) // don't allow for duplicates
|
||||
aReloadDocs->AppendElement(doc);
|
||||
}
|
||||
}
|
||||
|
||||
nsPluginTag* pluginTag = instanceTag->mPluginTag;
|
||||
mInstanceTags.RemoveElement(instanceTag);
|
||||
OnPluginInstanceDestroyed(pluginTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray< nsAutoPtr<nsPluginInstanceTag> >*
|
||||
nsPluginHost::InstanceTagArray()
|
||||
{
|
||||
return &mInstanceTags;
|
||||
}
|
||||
|
||||
nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
|
||||
nsISupports* aContext)
|
||||
{
|
||||
@ -5447,10 +5566,7 @@ public:
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("Doing delayed destroy of instance %p\n", instance.get()));
|
||||
|
||||
instance->Stop();
|
||||
|
||||
nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
|
||||
|
||||
if (host)
|
||||
host->StopPluginInstance(instance);
|
||||
|
||||
|
@ -81,7 +81,6 @@ public:
|
||||
virtual ~nsPluginHost();
|
||||
|
||||
static nsPluginHost* GetInst();
|
||||
static const char *GetPluginName(nsIPluginInstance *aPluginInstance);
|
||||
|
||||
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
|
||||
|
||||
@ -164,6 +163,16 @@ public:
|
||||
void PluginCrashed(nsNPAPIPlugin* plugin);
|
||||
#endif
|
||||
|
||||
nsPluginInstanceTag *FindInstanceTag(nsIPluginInstance *instance);
|
||||
nsPluginInstanceTag *FindInstanceTag(const char *mimetype);
|
||||
nsPluginInstanceTag *FindStoppedInstanceTag(const char * url);
|
||||
nsPluginInstanceTag *FindOldestStoppedInstanceTag();
|
||||
PRUint32 StoppedInstanceTagCount();
|
||||
|
||||
void StopRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag);
|
||||
|
||||
nsTArray< nsAutoPtr<nsPluginInstanceTag> > *InstanceTagArray();
|
||||
|
||||
private:
|
||||
nsresult
|
||||
TrySetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner);
|
||||
@ -243,7 +252,9 @@ private:
|
||||
|
||||
// calls PostPluginUnloadEvent for each library in mUnusedLibraries
|
||||
void UnloadUnusedLibraries();
|
||||
|
||||
|
||||
void OnPluginInstanceDestroyed(nsPluginTag* aPluginTag);
|
||||
|
||||
nsRefPtr<nsPluginTag> mPlugins;
|
||||
nsRefPtr<nsPluginTag> mCachedPlugins;
|
||||
PRPackedBool mPluginsLoaded;
|
||||
@ -259,7 +270,11 @@ private:
|
||||
// set by pref plugin.default_plugin_disabled
|
||||
PRPackedBool mDefaultPluginDisabled;
|
||||
|
||||
nsPluginInstanceTagList mPluginInstanceTagList;
|
||||
// set by pref plugin.disable
|
||||
PRPackedBool mPluginsDisabled;
|
||||
|
||||
nsTArray< nsAutoPtr<nsPluginInstanceTag> > mInstanceTags;
|
||||
|
||||
nsTArray<PRLibrary*> mUnusedLibraries;
|
||||
|
||||
nsCOMPtr<nsIFile> mPluginRegFile;
|
||||
|
@ -306,17 +306,19 @@ static LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
|
||||
#ifndef WINCE
|
||||
case WM_MOUSEACTIVATE: {
|
||||
// If a child window of this plug-in is already focused,
|
||||
// don't focus the parent to avoid focus dance.
|
||||
// The following WM_SETFOCUS message will give the focus
|
||||
// to the appropriate window anyway.
|
||||
// don't focus the parent to avoid focus dance. We'll
|
||||
// receive a follow up WM_SETFOCUS which will notify
|
||||
// the appropriate window anyway.
|
||||
HWND focusedWnd = ::GetFocus();
|
||||
if (!::IsChild((HWND)win->window, focusedWnd)) {
|
||||
// This seems to be the only way we're
|
||||
// notified when a child window that doesn't have this handler proc
|
||||
// (read as: windows created by plugins like Adobe Acrobat)
|
||||
// has been activated via clicking.
|
||||
// should be handled here because some plugins won't forward
|
||||
// messages to original WinProc.
|
||||
// Notify the dom / focus manager the plugin has focus when one of
|
||||
// it's child windows receives it. OOPP specific - this code is
|
||||
// critical in notifying the dom of focus changes when the plugin
|
||||
// window in the child process receives focus via a mouse click.
|
||||
// WM_MOUSEACTIVATE is sent by nsWindow via a custom window event
|
||||
// sent from PluginInstanceParent in response to focus events sent
|
||||
// from the child. (bug 540052) Note, this gui event could also be
|
||||
// sent directly from widget.
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
win->GetPluginWidget(getter_AddRefs(widget));
|
||||
if (widget) {
|
||||
|
@ -571,7 +571,6 @@ nsPluginInstanceTag::nsPluginInstanceTag(nsPluginTag* aPluginTag,
|
||||
NS_ADDREF(aInstance);
|
||||
mInstance = static_cast<nsNPAPIPluginInstance*>(aInstance);
|
||||
|
||||
mNext = nsnull;
|
||||
mPluginTag = aPluginTag;
|
||||
|
||||
mURL = PL_strdup(url);
|
||||
@ -593,231 +592,3 @@ nsPluginInstanceTag::~nsPluginInstanceTag()
|
||||
|
||||
PL_strfree(mURL);
|
||||
}
|
||||
|
||||
/* nsPluginInstanceTagList */
|
||||
|
||||
nsPluginInstanceTagList::nsPluginInstanceTagList()
|
||||
{
|
||||
mFirst = nsnull;
|
||||
mLast = nsnull;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
nsPluginInstanceTagList::~nsPluginInstanceTagList()
|
||||
{
|
||||
if (!mFirst)
|
||||
return;
|
||||
shutdown();
|
||||
}
|
||||
|
||||
void nsPluginInstanceTagList::shutdown()
|
||||
{
|
||||
if (!mFirst)
|
||||
return;
|
||||
|
||||
for (nsPluginInstanceTag * plugin = mFirst; plugin != nsnull;) {
|
||||
nsPluginInstanceTag * next = plugin->mNext;
|
||||
remove(plugin);
|
||||
plugin = next;
|
||||
}
|
||||
mFirst = nsnull;
|
||||
mLast = nsnull;
|
||||
}
|
||||
|
||||
PRInt32 nsPluginInstanceTagList::add(nsPluginInstanceTag * plugin)
|
||||
{
|
||||
if (!mFirst) {
|
||||
mFirst = plugin;
|
||||
mLast = plugin;
|
||||
mFirst->mNext = nsnull;
|
||||
}
|
||||
else {
|
||||
mLast->mNext = plugin;
|
||||
mLast = plugin;
|
||||
}
|
||||
mLast->mNext = nsnull;
|
||||
mCount++;
|
||||
return mCount;
|
||||
}
|
||||
|
||||
PRBool nsPluginInstanceTagList::IsLastInstance(nsPluginInstanceTag * plugin)
|
||||
{
|
||||
if (!plugin)
|
||||
return PR_FALSE;
|
||||
|
||||
if (!plugin->mPluginTag)
|
||||
return PR_FALSE;
|
||||
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
|
||||
if ((p->mPluginTag == plugin->mPluginTag) && (p != plugin))
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool nsPluginInstanceTagList::remove(nsPluginInstanceTag * plugin)
|
||||
{
|
||||
if (!mFirst)
|
||||
return PR_FALSE;
|
||||
|
||||
nsPluginInstanceTag * prev = nsnull;
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
|
||||
if (p == plugin) {
|
||||
PRBool lastInstance = IsLastInstance(p);
|
||||
|
||||
if (p == mFirst)
|
||||
mFirst = p->mNext;
|
||||
else
|
||||
prev->mNext = p->mNext;
|
||||
|
||||
if (prev && !prev->mNext)
|
||||
mLast = prev;
|
||||
|
||||
if (lastInstance) {
|
||||
nsRefPtr<nsPluginTag> pluginTag = p->mPluginTag;
|
||||
|
||||
delete p;
|
||||
|
||||
if (pluginTag) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRBool unloadPluginsASAP = PR_FALSE;
|
||||
rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
|
||||
if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
|
||||
pluginTag->TryUnloadPlugin();
|
||||
} else {
|
||||
NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown");
|
||||
}
|
||||
} else {
|
||||
delete p;
|
||||
}
|
||||
|
||||
mCount--;
|
||||
return PR_TRUE;
|
||||
}
|
||||
prev = p;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// This method terminates all running instances of plugins and collects their
|
||||
// documents to be returned through an array. This method is used
|
||||
// when we are shutting down or when a plugins.refresh(1) happens.
|
||||
// If aPluginTag is given, then only that plugin is terminated
|
||||
void nsPluginInstanceTagList::stopRunning(nsISupportsArray* aReloadDocs,
|
||||
nsPluginTag* aPluginTag)
|
||||
{
|
||||
if (!mFirst)
|
||||
return;
|
||||
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
|
||||
if (p->mInstance->IsRunning() && (!aPluginTag || aPluginTag == p->mPluginTag)) {
|
||||
p->mInstance->SetWindow(nsnull);
|
||||
p->mInstance->Stop();
|
||||
|
||||
// If we've been passed an array to return, lets collect all our documents,
|
||||
// removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
|
||||
// to kickstart our instances.
|
||||
if (aReloadDocs) {
|
||||
nsCOMPtr<nsIPluginInstanceOwner> owner;
|
||||
p->mInstance->GetOwner(getter_AddRefs(owner));
|
||||
if (owner) {
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
owner->GetDocument(getter_AddRefs(doc));
|
||||
if (doc && aReloadDocs->IndexOf(doc) == -1) // don't allow for duplicates
|
||||
aReloadDocs->AppendElement(doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsPluginInstanceTagList::removeAllStopped()
|
||||
{
|
||||
if (!mFirst)
|
||||
return;
|
||||
|
||||
nsPluginInstanceTag * next = nsnull;
|
||||
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull;) {
|
||||
next = p->mNext;
|
||||
|
||||
if (!p->mInstance->IsRunning())
|
||||
remove(p);
|
||||
|
||||
p = next;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nsPluginInstanceTag * nsPluginInstanceTagList::find(nsIPluginInstance* instance)
|
||||
{
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
|
||||
if (p->mInstance == instance)
|
||||
return p;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsPluginInstanceTag * nsPluginInstanceTagList::find(const char * mimetype)
|
||||
{
|
||||
PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
|
||||
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
|
||||
// give it some special treatment for the default plugin first
|
||||
// because we cannot tell the default plugin by asking instance for a mime type
|
||||
if (defaultplugin && p->mDefaultPlugin)
|
||||
return p;
|
||||
|
||||
if (!p->mInstance)
|
||||
continue;
|
||||
|
||||
const char* mt;
|
||||
nsresult rv = p->mInstance->GetMIMEType(&mt);
|
||||
if (NS_FAILED(rv))
|
||||
continue;
|
||||
|
||||
if (PL_strcasecmp(mt, mimetype) == 0)
|
||||
return p;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsPluginInstanceTag * nsPluginInstanceTagList::findStopped(const char * url)
|
||||
{
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
|
||||
if (!PL_strcmp(url, p->mURL) && !p->mInstance->IsRunning())
|
||||
return p;
|
||||
}
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PRUint32 nsPluginInstanceTagList::getStoppedCount()
|
||||
{
|
||||
PRUint32 stoppedCount = 0;
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
|
||||
if (!p->mInstance->IsRunning())
|
||||
stoppedCount++;
|
||||
}
|
||||
return stoppedCount;
|
||||
}
|
||||
|
||||
nsPluginInstanceTag * nsPluginInstanceTagList::findOldestStopped()
|
||||
{
|
||||
nsPluginInstanceTag * res = nsnull;
|
||||
TimeStamp oldestTime = TimeStamp::Now();
|
||||
for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
|
||||
if (p->mInstance->IsRunning())
|
||||
continue;
|
||||
|
||||
TimeStamp time = p->mInstance->LastStopTime();
|
||||
if (time < oldestTime) {
|
||||
oldestTime = time;
|
||||
res = p;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -125,11 +125,10 @@ private:
|
||||
|
||||
struct nsPluginInstanceTag
|
||||
{
|
||||
nsPluginInstanceTag* mNext;
|
||||
char* mURL;
|
||||
nsRefPtr<nsPluginTag> mPluginTag;
|
||||
nsNPAPIPluginInstance* mInstance; // this must always be valid
|
||||
PRPackedBool mDefaultPlugin;
|
||||
PRBool mDefaultPlugin;
|
||||
// Array holding all opened stream listeners for this entry
|
||||
nsCOMPtr <nsISupportsArray> mStreams;
|
||||
|
||||
@ -140,27 +139,4 @@ struct nsPluginInstanceTag
|
||||
~nsPluginInstanceTag();
|
||||
};
|
||||
|
||||
class nsPluginInstanceTagList
|
||||
{
|
||||
public:
|
||||
nsPluginInstanceTag *mFirst;
|
||||
nsPluginInstanceTag *mLast;
|
||||
PRInt32 mCount;
|
||||
|
||||
nsPluginInstanceTagList();
|
||||
~nsPluginInstanceTagList();
|
||||
|
||||
void shutdown();
|
||||
PRBool add(nsPluginInstanceTag *plugin);
|
||||
PRBool remove(nsPluginInstanceTag *plugin);
|
||||
nsPluginInstanceTag *find(nsIPluginInstance *instance);
|
||||
nsPluginInstanceTag *find(const char *mimetype);
|
||||
nsPluginInstanceTag *findStopped(const char *url);
|
||||
PRUint32 getStoppedCount();
|
||||
nsPluginInstanceTag *findOldestStopped();
|
||||
void removeAllStopped();
|
||||
void stopRunning(nsISupportsArray *aReloadDocs, nsPluginTag *aPluginTag);
|
||||
PRBool IsLastInstance(nsPluginInstanceTag *plugin);
|
||||
};
|
||||
|
||||
#endif // nsPluginTags_h_
|
||||
|
@ -70,10 +70,10 @@ _MOCHITEST_FILES = \
|
||||
test_streamNotify.html \
|
||||
test_instantiation.html \
|
||||
test_cookies.html \
|
||||
test_npn_timers.html \
|
||||
test_npn_asynccall.html \
|
||||
$(NULL)
|
||||
|
||||
# test_npn_timers.html \ disabled for leaking
|
||||
# test_npn_asynccall.html \ disabled for leaking
|
||||
# test_npruntime_npnsetexception.html \ Disabled for e10s
|
||||
|
||||
ifdef MOZ_IPC
|
||||
|
@ -51,27 +51,29 @@
|
||||
var p = iframe.contentDocument.getElementById('plugin1');
|
||||
try {
|
||||
p.setColor('FF00FF00');
|
||||
ok(true, "Reloading worked");
|
||||
ok(true, "Reloading after crash-on-new worked");
|
||||
}
|
||||
catch (e) {
|
||||
ok(false, "Reloading didn't give us a usable plugin");
|
||||
ok(false, "Reloading after crash-on-new didn't give us a usable plugin");
|
||||
}
|
||||
p.crashOnDestroy();
|
||||
// the child crash should happen here
|
||||
p.parentNode.removeChild(p);
|
||||
|
||||
window.frameLoaded = reloaded2;
|
||||
iframe.contentWindow.location.reload();
|
||||
SimpleTest.executeSoon(function() {
|
||||
iframe.contentWindow.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function reloaded2() {
|
||||
var p = iframe.contentDocument.getElementById('plugin1');
|
||||
try {
|
||||
p.setColor('FF00FF00');
|
||||
ok(true, "Reloading worked");
|
||||
ok(true, "Reloading after crash-on-destroy worked");
|
||||
}
|
||||
catch (e) {
|
||||
ok(false, "Reloading didn't give us a usable plugin");
|
||||
ok(false, "Reloading after crash-on-destroy didn't give us a usable plugin");
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
@ -24,12 +24,12 @@ const Cc = Components.classes;
|
||||
function iframeLoad() {
|
||||
var plugin = iframe.contentDocument.getElementById("embedtest");
|
||||
// valid request
|
||||
is(plugin.getAuthInfo("http", "localhost", 8888, "http", "testrealm"),
|
||||
is(plugin.getAuthInfo("http", "localhost", 8888, "basic", "testrealm"),
|
||||
"user1|password1",
|
||||
"correct user/pass retrieved");
|
||||
try {
|
||||
// invalid request -- wrong host
|
||||
is(plugin.getAuthInfo("http", "example.com", 8888, "http", "testrealm"),
|
||||
is(plugin.getAuthInfo("http", "example.com", 8888, "basic", "testrealm"),
|
||||
"user1|password1",
|
||||
"correct user/pass retrieved");
|
||||
ok(false, "no exception was thrown");
|
||||
@ -39,7 +39,7 @@ function iframeLoad() {
|
||||
}
|
||||
try {
|
||||
// invalid request -- wrong port
|
||||
is(plugin.getAuthInfo("http", "localhost", 90, "http", "testrealm"),
|
||||
is(plugin.getAuthInfo("http", "localhost", 90, "basic", "testrealm"),
|
||||
"user1|password1",
|
||||
"correct user/pass retrieved");
|
||||
ok(false, "no exception was thrown");
|
||||
@ -49,7 +49,7 @@ function iframeLoad() {
|
||||
}
|
||||
try {
|
||||
// invalid request -- wrong realm
|
||||
is(plugin.getAuthInfo("http", "localhost", 8888, "http", "wrongrealm"),
|
||||
is(plugin.getAuthInfo("http", "localhost", 8888, "basic", "wrongrealm"),
|
||||
"user1|password1",
|
||||
"correct user/pass retrieved");
|
||||
ok(false, "no exception was thrown");
|
||||
|
@ -64,8 +64,10 @@
|
||||
// Intentional crash
|
||||
//
|
||||
|
||||
static void
|
||||
Crash()
|
||||
int gCrashCount = 0;
|
||||
|
||||
void
|
||||
IntentionalCrash()
|
||||
{
|
||||
char* bloatLog = getenv("XPCOM_MEM_BLOAT_LOG");
|
||||
if (bloatLog) {
|
||||
@ -82,8 +84,9 @@ Crash()
|
||||
fprintf(processfd, "==> process %d will purposefully crash\n", getpid());
|
||||
fclose(processfd);
|
||||
}
|
||||
void (*funcptr)() = NULL;
|
||||
funcptr(); // Crash calling null function pointer
|
||||
int *pi = NULL;
|
||||
*pi = 55; // Crash dereferencing null pointer
|
||||
++gCrashCount;
|
||||
}
|
||||
|
||||
//
|
||||
@ -675,7 +678,7 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*
|
||||
instanceData->npnNewStream = true;
|
||||
}
|
||||
if (strcmp(argn[i], "newcrash") == 0) {
|
||||
Crash();
|
||||
IntentionalCrash();
|
||||
}
|
||||
}
|
||||
|
||||
@ -758,7 +761,7 @@ NPP_Destroy(NPP instance, NPSavedData** save)
|
||||
InstanceData* instanceData = (InstanceData*)(instance->pdata);
|
||||
|
||||
if (instanceData->crashOnDestroy)
|
||||
Crash();
|
||||
IntentionalCrash();
|
||||
|
||||
if (instanceData->streamBuf) {
|
||||
free(instanceData->streamBuf);
|
||||
@ -2101,7 +2104,7 @@ streamTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant*
|
||||
static bool
|
||||
crashPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
|
||||
{
|
||||
Crash();
|
||||
IntentionalCrash();
|
||||
VOID_TO_NPVARIANT(*result);
|
||||
return true;
|
||||
}
|
||||
@ -2425,6 +2428,7 @@ asyncCallback(void* cookie)
|
||||
BOOLEAN_TO_NPVARIANT(id->asyncCallbackResult, arg);
|
||||
NPN_Invoke(npp, windowObject, NPN_GetStringIdentifier(id->asyncTestScriptCallback.c_str()), &arg, 1, &rval);
|
||||
NPN_ReleaseVariantValue(&arg);
|
||||
NPN_ReleaseObject(windowObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user