Merge in bug 461444: remove cases of excessive recursion in makefiles r=ted

This commit is contained in:
Dave Townsend 2010-01-27 11:45:36 -08:00
commit 9f8ed3f5da
128 changed files with 2601 additions and 1485 deletions

View File

@ -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

View File

@ -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)

View File

@ -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);
}

View File

@ -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;

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,261 +1602,169 @@ 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()
nsDocAccessible::ProcessPendingEvent(nsAccEvent *aEvent)
{
mInFlushPendingEvents = PR_TRUE;
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 ++) {
if (eventType == nsIAccessibleEvent::EVENT_SHOW) {
// No presshell means the document was shut down duiring event handling
// by AT.
if (!mWeakShell)
break;
nsCOMPtr<nsIAccessible> containerAccessible;
if (accessible)
accessible->GetParent(getter_AddRefs(containerAccessible));
nsAccEvent *accEvent = mEventsToFire[index];
if (!containerAccessible) {
GetAccessibleInParentChain(domNode, PR_TRUE,
getter_AddRefs(containerAccessible));
if (!containerAccessible)
containerAccessible = this;
}
if (accEvent->GetEventRule() == nsAccEvent::eDoNotEmit)
continue;
if (isAsync) {
// For asynch show, delayed invalidatation of parent's children
nsRefPtr<nsAccessible> containerAcc =
nsAccUtils::QueryAccessible(containerAccessible);
if (containerAcc)
containerAcc->InvalidateChildren();
nsCOMPtr<nsIAccessible> accessible;
accEvent->GetAccessible(getter_AddRefs(accessible));
// 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);
}
nsCOMPtr<nsIDOMNode> domNode;
accEvent->GetDOMNode(getter_AddRefs(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);
}
}
else {
nsEventShell::FireEvent(accEvent);
// 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
}
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(aEvent);
// 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();
// 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
}
}
}
}
}
@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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

View File

@ -77,10 +77,6 @@
label="&copyLinkCmd.label;"
accesskey="&copyLinkCmd.accesskey;"
oncommand="goDoCommand('cmd_copyLink');"/>
<menuitem id="context-copylinktext"
label="&copyLinkText2Cmd.label;"
accesskey="&copyLinkText2Cmd.accesskey;"
oncommand="gContextMenu.copyLinkText();"/>
<menuseparator id="context-sep-copylink"/>
<menuitem id="context-media-play"
label="&mediaPlay.label;"

View File

@ -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 //
///////////////

View File

@ -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;

View File

@ -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@

View File

@ -804,7 +804,6 @@ greprefs/security-prefs.js
greprefs/xpinstall.js
run-mozilla.sh
firefox
dependentlibs.list
components/nsProgressDialog.js
libwidget.rsrc
#endif

View File

@ -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">

View File

@ -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):

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View 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);
}

View 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>

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View 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();
}

View File

@ -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 },
]);

View 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>

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -161,6 +161,12 @@ parent:
rpc PPluginStream(nsCString mimeType,
nsCString target)
returns (NPError result);
parent:
rpc PluginGotFocus();
child:
rpc SetPluginFocus();
rpc UpdateWindow();
};
} // namespace plugins

View File

@ -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()
{

View File

@ -145,6 +145,12 @@ protected:
NS_OVERRIDE virtual bool
DeallocPStreamNotify(PStreamNotifyChild* notifyData);
virtual bool
AnswerSetPluginFocus();
virtual bool
AnswerUpdateWindow();
public:
PluginInstanceChild(const NPPluginFuncs* aPluginIface);

View File

@ -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
}

View File

@ -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)
};

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -78,7 +78,7 @@ public:
void print(const char* format, ...);
private:
FILE* fd_;
std::string fname_;
DISALLOW_EVIL_CONSTRUCTORS(EnvironmentLog);
};

View File

@ -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];

View File

@ -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>
{

View File

@ -62,7 +62,7 @@ Types = (
# NSPR types
'PRBool',
'PRPackedBool'
'PRPackedBool',
'PRInt8',
'PRUint8',
'PRInt16',

View File

@ -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:

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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[] = {

View File

@ -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))

View File

@ -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",

View File

@ -1,6 +1,7 @@
<html>
<head>
<title>Inner frame for bug 500931 mochitest</title>
<script>x = 42;</script>
</head>
<body>
</body>

View 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>

View 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>

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
}
}

View File

@ -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 ||

View File

@ -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;
}
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;

View File

@ -0,0 +1,5 @@
<html>
<body>
<span>&#xFBE4;</span><span>&#xFB4B;</span><span>&#xFBE6;</span>
</body>
</html>

View File

@ -0,0 +1,5 @@
<html>
<body>
&#x202E;X&#x200D; &#x5D60;
</body>
</html>

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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()->

View File

@ -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;

View File

@ -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>

View File

@ -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() {

View File

@ -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();
}
]]>

View File

@ -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();
}
]]>

View File

@ -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

View File

@ -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);
}
}

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<style>
span { display:inline-block; width:100px; height:10px; background:yellow; }
</style>
</head>
<!-- Test that &nbsp; has justification space added. -->
<body style="text-align:justify; width:300px;">
<span></span>&nbsp;<span></span>
<span></span>
</body>
</html>

View 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>&#x2007;<span></span>
<span></span>
</body>
</html>

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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;
cachedPluginLimit = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
if (mPluginInstanceTagList.getStoppedCount() >= max_num) {
nsPluginInstanceTag * oldest = mPluginInstanceTagList.findOldestStopped();
if (oldest != nsnull)
mPluginInstanceTagList.remove(oldest);
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;
}
@ -5077,12 +5114,11 @@ nsPluginHost::GetPluginTagForInstance(nsIPluginInstance *aPluginInstance,
NS_ENSURE_ARG_POINTER(aPluginInstance);
NS_ENSURE_ARG_POINTER(aPluginTag);
nsPluginInstanceTag *plugin =
gActivePluginList ? gActivePluginList->find(aPluginInstance) : nsnull;
nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance);
NS_ENSURE_TRUE(plugin && plugin->mPluginTag, NS_ERROR_FAILURE);
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();
*pinstancetag = (*pinstancetag)->mNext;
delete instancetag;
}
else {
pinstancetag = &(*pinstancetag)->mNext;
instanceTag->mInstance->Stop();
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);

View File

@ -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);
@ -244,6 +253,8 @@ 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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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_

View File

@ -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

View File

@ -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();
}

View File

@ -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");

View File

@ -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