diff --git a/accessible/public/nsIAccessibilityService.idl b/accessible/public/nsIAccessibilityService.idl index 989b56de2170..658e76f5cb98 100644 --- a/accessible/public/nsIAccessibilityService.idl +++ b/accessible/public/nsIAccessibilityService.idl @@ -44,7 +44,7 @@ interface nsIFrame; interface nsObjectFrame; interface nsIContent; -[uuid(e0498def-1552-4763-8c47-6c6cc36c7aa0)] +[uuid(84a3ab70-8f7e-4610-9cd8-bd69308b76c5)] interface nsIAccessibilityService : nsIAccessibleRetrieval { nsIAccessible createOuterDocAccessible(in nsIDOMNode aNode); @@ -74,19 +74,6 @@ interface nsIAccessibilityService : nsIAccessibleRetrieval nsIAccessible createHTMLTextFieldAccessible(in nsIFrame aFrame); nsIAccessible createHTMLCaptionAccessible(in nsIFrame aFrame); - /** - * Return an accessible for the given DOM node. - * - * @param aNode [in] the given node - * @param aPresShell [in] the pres shell of the node - * @param aWeakShell [in] the weak shell for the pres shell - * @param aFrameHint [in] the frame of the given node - * @param aIsHidden [out] indicates whether the node's frame is hidden - */ - nsIAccessible getAccessible(in nsIDOMNode aNode, in nsIPresShell aPresShell, - in nsIWeakReference aWeakShell, - in nsIFrame aFrameHint, out boolean aIsHidden); - // For gtk+ native window accessible nsIAccessible addNativeRootAccessible(in voidPtr aAtkAccessible); void removeNativeRootAccessible(in nsIAccessible aRootAccessible); diff --git a/accessible/public/nsIAccessibleRetrieval.idl b/accessible/public/nsIAccessibleRetrieval.idl index fab95f620e6d..4f182cf87d8c 100644 --- a/accessible/public/nsIAccessibleRetrieval.idl +++ b/accessible/public/nsIAccessibleRetrieval.idl @@ -56,7 +56,7 @@ interface nsIDOMDOMStringList; * * @status UNDER_REVIEW */ -[scriptable, uuid(244e4c67-a1d3-44f2-9cab-cdaa31b68046)] +[scriptable, uuid(7eb49afb-6298-4ce6-816f-9615936540f4)] interface nsIAccessibleRetrieval : nsISupports { /** @@ -92,26 +92,6 @@ interface nsIAccessibleRetrieval : nsISupports */ nsIDOMNode getRelevantContentNodeFor(in nsIDOMNode aNode); - /** - * Return an nsIAccessible for a DOM node in pres shell for this DOM window. - * Create a new accessible of the appropriate type if necessary, - * or use one from the accessibility cache if it already exists. - * @param aNode The DOM node to get an accessible for. - * @param aDOMWin The DOM window containing the node. - * @return The nsIAccessible for the given DOM node. - */ - nsIAccessible getAccessibleInWindow(in nsIDOMNode aNode, in nsIDOMWindow aDOMWin); - - /** - * Return an nsIAccessible for a DOM node in the given weak shell. - * Create a new accessible of the appropriate type if necessary, - * or use one from the accessibility cache if it already exists. - * @param aNode The DOM node to get an accessible for. - * @param aPresShell The presentation shell which contains layout info for the DOM node. - * @return The nsIAccessible for the given DOM node. - */ - nsIAccessible getAccessibleInWeakShell(in nsIDOMNode aNode, in nsIWeakReference aPresShell); - /** * Return an nsIAccessible for a DOM node in the given pres shell. * Create a new accessible of the appropriate type if necessary, diff --git a/accessible/src/base/nsAccEvent.cpp b/accessible/src/base/nsAccEvent.cpp index 51ccec661f4d..feaa7c3c43ee 100644 --- a/accessible/src/base/nsAccEvent.cpp +++ b/accessible/src/base/nsAccEvent.cpp @@ -295,8 +295,7 @@ nsAccReorderEvent::HasAccessibleInReasonSubtree() return PR_FALSE; nsCOMPtr accessible; - nsAccessNode::GetAccService()->GetAccessibleFor(mReasonNode, - getter_AddRefs(accessible)); + GetAccService()->GetAccessibleFor(mReasonNode, getter_AddRefs(accessible)); return accessible || nsAccUtils::HasAccessibleChildren(mReasonNode); } diff --git a/accessible/src/base/nsAccUtils.cpp b/accessible/src/base/nsAccUtils.cpp index adfe1a10c2ef..4511e1b28a9e 100644 --- a/accessible/src/base/nsAccUtils.cpp +++ b/accessible/src/base/nsAccUtils.cpp @@ -172,8 +172,7 @@ nsAccUtils::GetPositionAndSizeForXULSelectControlItem(nsIDOMNode *aNode, nsCOMPtr currNode(do_QueryInterface(currItem)); nsCOMPtr itemAcc; - nsAccessNode::GetAccService()->GetAccessibleFor(currNode, - getter_AddRefs(itemAcc)); + GetAccService()->GetAccessibleFor(currNode, getter_AddRefs(itemAcc)); if (!itemAcc || State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) { (*aSetSize)--; @@ -214,8 +213,7 @@ nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIDOMNode *aNode, container->GetItemAtIndex(index, getter_AddRefs(item)); nsCOMPtr itemAcc; - nsAccessNode::GetAccService()->GetAccessibleFor(item, - getter_AddRefs(itemAcc)); + GetAccService()->GetAccessibleFor(item, getter_AddRefs(itemAcc)); if (itemAcc) { PRUint32 itemRole = Role(itemAcc); @@ -236,8 +234,7 @@ nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIDOMNode *aNode, container->GetItemAtIndex(index, getter_AddRefs(item)); nsCOMPtr itemAcc; - nsAccessNode::GetAccService()->GetAccessibleFor(item, - getter_AddRefs(itemAcc)); + GetAccService()->GetAccessibleFor(item, getter_AddRefs(itemAcc)); if (itemAcc) { PRUint32 itemRole = Role(itemAcc); @@ -524,8 +521,7 @@ already_AddRefed nsAccUtils::GetMultiSelectableContainer(nsIDOMNode *aNode) { nsCOMPtr accessible; - nsAccessNode::GetAccService()->GetAccessibleFor(aNode, - getter_AddRefs(accessible)); + GetAccService()->GetAccessibleFor(aNode, getter_AddRefs(accessible)); nsCOMPtr container = GetSelectableContainer(accessible, State(accessible)); @@ -573,25 +569,20 @@ nsAccUtils::GetTextAccessibleFromSelection(nsISelection *aSelection, nsCOMPtr resultNode = nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset); - nsIAccessibilityService *accService = nsAccessNode::GetAccService(); - // Get text accessible containing the result node. while (resultNode) { // Make sure to get the correct starting node for selection events inside // XBL content trees. nsCOMPtr relevantNode; - nsresult rv = accService-> - GetRelevantContentNodeFor(resultNode, getter_AddRefs(relevantNode)); - if (NS_FAILED(rv)) - return nsnull; - + GetAccService()->GetRelevantContentNodeFor(resultNode, + getter_AddRefs(relevantNode)); if (relevantNode) resultNode.swap(relevantNode); nsCOMPtr content = do_QueryInterface(resultNode); if (!content || !content->IsNodeOfType(nsINode::eTEXT)) { nsCOMPtr accessible; - accService->GetAccessibleFor(resultNode, getter_AddRefs(accessible)); + GetAccService()->GetAccessibleFor(resultNode, getter_AddRefs(accessible)); if (accessible) { nsIAccessibleText *textAcc = nsnull; CallQueryInterface(accessible, &textAcc); @@ -956,8 +947,7 @@ PRBool nsAccUtils::IsNodeRelevant(nsIDOMNode *aNode) { nsCOMPtr relevantNode; - nsAccessNode::GetAccService()->GetRelevantContentNodeFor(aNode, - getter_AddRefs(relevantNode)); + GetAccService()->GetRelevantContentNodeFor(aNode, getter_AddRefs(relevantNode)); return aNode == relevantNode; } diff --git a/accessible/src/base/nsAccessNode.cpp b/accessible/src/base/nsAccessNode.cpp index 22fa9ef99e69..87d71114458c 100644 --- a/accessible/src/base/nsAccessNode.cpp +++ b/accessible/src/base/nsAccessNode.cpp @@ -82,12 +82,6 @@ nsAccessNodeHashtable nsAccessNode::gGlobalDocAccessibleCache; nsApplicationAccessibleWrap *nsAccessNode::gApplicationAccessible = nsnull; -nsIAccessibilityService* -nsAccessNode::GetAccService() -{ - return nsAccessibilityService::GetAccessibilityService(); -} - /* * Class nsAccessNode */ @@ -157,13 +151,10 @@ nsAccessNode::Init() if (presShell) { nsCOMPtr docNode(do_QueryInterface(presShell->GetDocument())); if (docNode) { - nsIAccessibilityService *accService = GetAccService(); - if (accService) { - nsCOMPtr accessible; - accService->GetAccessibleInShell(docNode, presShell, - getter_AddRefs(accessible)); - docAccessible = do_QueryInterface(accessible); - } + nsCOMPtr accessible; + GetAccService()->GetAccessibleInShell(docNode, presShell, + getter_AddRefs(accessible)); + docAccessible = do_QueryInterface(accessible); } } NS_ASSERTION(docAccessible, "Cannot cache new nsAccessNode"); @@ -473,16 +464,14 @@ nsAccessNode::MakeAccessNode(nsIDOMNode *aNode, nsIAccessNode **aAccessNode) { *aAccessNode = nsnull; - nsIAccessibilityService *accService = GetAccService(); - NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE); - nsCOMPtr accessNode; - accService->GetCachedAccessNode(aNode, mWeakShell, getter_AddRefs(accessNode)); + GetAccService()->GetCachedAccessNode(aNode, mWeakShell, + getter_AddRefs(accessNode)); if (!accessNode) { nsCOMPtr accessible; - accService->GetAccessibleInWeakShell(aNode, mWeakShell, - getter_AddRefs(accessible)); + GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell, + getter_AddRefs(accessible)); accessNode = do_QueryInterface(accessible); } diff --git a/accessible/src/base/nsAccessNode.h b/accessible/src/base/nsAccessNode.h index 325ca5a9ea3f..243814cc8807 100644 --- a/accessible/src/base/nsAccessNode.h +++ b/accessible/src/base/nsAccessNode.h @@ -56,7 +56,7 @@ #include "nsIStringBundle.h" #include "nsWeakReference.h" #include "nsInterfaceHashtable.h" -#include "nsIAccessibilityService.h" +#include "nsAccessibilityService.h" class nsIPresShell; class nsPresContext; @@ -145,7 +145,7 @@ class nsAccessNode: public nsIAccessNode already_AddRefed GetRootAccessible(); static nsIDOMNode *gLastFocusedNode; - static nsIAccessibilityService* GetAccService(); + already_AddRefed GetCurrentFocus(); /** diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index a45c8a205405..5424c58507c8 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -1173,26 +1173,6 @@ nsAccessibilityService::GetAttachedAccessibleFor(nsIDOMNode *aNode, return GetAccessibleFor(aNode, aAccessible); } -NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWindow(nsIDOMNode *aNode, - nsIDOMWindow *aWin, - nsIAccessible **aAccessible) -{ - NS_ENSURE_ARG_POINTER(aAccessible); - *aAccessible = nsnull; - - NS_ENSURE_ARG(aNode); - NS_ENSURE_ARG(aWin); - - nsCOMPtr webNav(do_GetInterface(aWin)); - nsCOMPtr docShell(do_QueryInterface(webNav)); - if (!docShell) - return NS_ERROR_FAILURE; - - nsCOMPtr presShell; - docShell->GetPresShell(getter_AddRefs(presShell)); - return GetAccessibleInShell(aNode, presShell, aAccessible); -} - NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode, nsIPresShell *aPresShell, nsIAccessible **aAccessible) @@ -1209,9 +1189,10 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode, nsnull, &isHiddenUnused, aAccessible); } -NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode, - nsIWeakReference *aWeakShell, - nsIAccessible **aAccessible) +nsresult +nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode, + nsIWeakReference *aWeakShell, + nsIAccessible **aAccessible) { NS_ENSURE_ARG_POINTER(aAccessible); *aAccessible = nsnull; @@ -1272,12 +1253,13 @@ static PRBool HasRelatedContent(nsIContent *aContent) return PR_FALSE; } -NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode, - nsIPresShell *aPresShell, - nsIWeakReference *aWeakShell, - nsIFrame *aFrameHint, - PRBool *aIsHidden, - nsIAccessible **aAccessible) +nsresult +nsAccessibilityService::GetAccessible(nsIDOMNode *aNode, + nsIPresShell *aPresShell, + nsIWeakReference *aWeakShell, + nsIFrame *aFrameHint, + PRBool *aIsHidden, + nsIAccessible **aAccessible) { NS_ENSURE_ARG_POINTER(aAccessible); *aAccessible = nsnull; @@ -2054,35 +2036,24 @@ nsAccessibilityService::InvalidateSubtreeFor(nsIPresShell *aShell, ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// -nsresult -nsAccessibilityService::GetAccessibilityService(nsIAccessibilityService** aResult) -{ - NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER); - *aResult = nsnull; - - if (!gAccessibilityService) { - gAccessibilityService = new nsAccessibilityService(); - NS_ENSURE_TRUE(gAccessibilityService, NS_ERROR_OUT_OF_MEMORY); - - gIsShutdown = PR_FALSE; - } - - NS_ADDREF(*aResult = gAccessibilityService); - return NS_OK; -} - -nsIAccessibilityService* -nsAccessibilityService::GetAccessibilityService() -{ - NS_ASSERTION(!gIsShutdown, - "Going to deal with shutdown accessibility service!"); - return gAccessibilityService; -} - +/** + * Return accessibility service; creating one if necessary. + */ nsresult NS_GetAccessibilityService(nsIAccessibilityService** aResult) { - return nsAccessibilityService::GetAccessibilityService(aResult); + NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER); + *aResult = nsnull; + + if (!nsAccessibilityService::gAccessibilityService) { + nsAccessibilityService::gAccessibilityService = new nsAccessibilityService(); + NS_ENSURE_TRUE(nsAccessibilityService::gAccessibilityService, NS_ERROR_OUT_OF_MEMORY); + + nsAccessibilityService::gIsShutdown = PR_FALSE; + } + + NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService); + return NS_OK; } nsresult diff --git a/accessible/src/base/nsAccessibilityService.h b/accessible/src/base/nsAccessibilityService.h index 2706cb31d968..6e21ed4013b8 100644 --- a/accessible/src/base/nsAccessibilityService.h +++ b/accessible/src/base/nsAccessibilityService.h @@ -81,21 +81,35 @@ public: static nsresult GetShellFromNode(nsIDOMNode *aNode, nsIWeakReference **weakShell); - /** - * Return accessibility service (static instance of this class). - */ - static nsresult GetAccessibilityService(nsIAccessibilityService** aResult); - - /** - * Return cached accessibility service. - */ - static nsIAccessibilityService* GetAccessibilityService(); - /** * Indicates whether accessibility service was shutdown. */ static PRBool gIsShutdown; + /** + * Return an accessible for the given DOM node. + * + * @param aNode [in] the given node + * @param aPresShell [in] the pres shell of the node + * @param aWeakShell [in] the weak shell for the pres shell + * @param aFrameHint [in] the frame of the given node + * @param aIsHidden [out] indicates whether the node's frame is hidden + */ + nsresult GetAccessible(nsIDOMNode *aNode, nsIPresShell *aPresShell, + nsIWeakReference *aWeakShell, nsIFrame *aFrameHint, + PRBool *aIsHidden, nsIAccessible **aAccessible); + + /** + * Return an accessible for a DOM node in the given pres shell. + * + * @param aNode [in] the given node. + * @param aPresShell [in] the presentation shell of the given node. + * @param aAccessible [out] the nsIAccessible for the given node. + */ + nsresult GetAccessibleInWeakShell(nsIDOMNode *aNode, + nsIWeakReference *aPresShell, + nsIAccessible **aAccessible); + private: /** * Return presentation shell, DOM node for the given frame. @@ -170,10 +184,24 @@ private: */ void ProcessDocLoadEvent(nsIWebProgress *aWebProgress, PRUint32 aEventType); + friend nsAccessibilityService* GetAccService(); + + friend nsresult NS_GetAccessibilityService(nsIAccessibilityService** aResult); + + NS_DECL_RUNNABLEMETHOD_ARG2(nsAccessibilityService, ProcessDocLoadEvent, nsCOMPtr, PRUint32) }; +/** + * Return the accessibility service instance. (Handy global function) + */ +inline nsAccessibilityService* +GetAccService() +{ + return nsAccessibilityService::gAccessibilityService; +} + /** * Map nsIAccessibleRole constants to strings. Used by * nsIAccessibleRetrieval::getStringRole() method. diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index a8917bbb8745..882734c15802 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -3096,13 +3096,13 @@ nsAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError) already_AddRefed nsAccessible::GetFirstAvailableAccessible(nsIDOMNode *aStartNode) { - nsIAccessibilityService *accService = GetAccService(); nsCOMPtr accessible; nsCOMPtr walker; nsCOMPtr currentNode(aStartNode); while (currentNode) { - accService->GetAccessibleInWeakShell(currentNode, mWeakShell, getter_AddRefs(accessible)); // AddRef'd + GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell, + getter_AddRefs(accessible)); if (accessible) return accessible.forget(); diff --git a/accessible/src/base/nsAccessibleTreeWalker.cpp b/accessible/src/base/nsAccessibleTreeWalker.cpp index b6df6491a100..e804f7e2880f 100644 --- a/accessible/src/base/nsAccessibleTreeWalker.cpp +++ b/accessible/src/base/nsAccessibleTreeWalker.cpp @@ -46,11 +46,11 @@ #include "nsIContent.h" #include "nsIDOMXULElement.h" #include "nsIPresShell.h" +#include "nsAccessibilityService.h" #include "nsWeakReference.h" nsAccessibleTreeWalker::nsAccessibleTreeWalker(nsIWeakReference* aPresShell, nsIDOMNode* aNode, PRBool aWalkAnonContent): - mWeakShell(aPresShell), - mAccService(do_GetService("@mozilla.org/accessibilityService;1")), + mWeakShell(aPresShell), mWalkAnonContent(aWalkAnonContent) { mState.domNode = aNode; @@ -294,16 +294,12 @@ nsAccessibleTreeWalker::WalkFrames() */ PRBool nsAccessibleTreeWalker::GetAccessible() { - if (!mAccService) { - return PR_FALSE; - } - mState.accessible = nsnull; nsCOMPtr presShell(do_QueryReferent(mWeakShell)); - mAccService->GetAccessible(mState.domNode, presShell, mWeakShell, - mState.frame.GetFrame(), &mState.isHidden, - getter_AddRefs(mState.accessible)); + GetAccService()->GetAccessible(mState.domNode, presShell, mWeakShell, + mState.frame.GetFrame(), &mState.isHidden, + getter_AddRefs(mState.accessible)); return mState.accessible ? PR_TRUE : PR_FALSE; } diff --git a/accessible/src/base/nsAccessibleTreeWalker.h b/accessible/src/base/nsAccessibleTreeWalker.h index 2467b9110ac3..73e0a05e6504 100644 --- a/accessible/src/base/nsAccessibleTreeWalker.h +++ b/accessible/src/base/nsAccessibleTreeWalker.h @@ -48,7 +48,6 @@ #include "nsIAccessible.h" #include "nsIDOMNode.h" #include "nsIDOMNodeList.h" -#include "nsIAccessibilityService.h" #include "nsIWeakReference.h" #include "nsIFrame.h" @@ -132,7 +131,6 @@ protected: void GetNextDOMNode(); nsCOMPtr mWeakShell; - nsCOMPtr mAccService; PRBool mWalkAnonContent; }; diff --git a/accessible/src/base/nsDocAccessible.cpp b/accessible/src/base/nsDocAccessible.cpp index bc58f2047731..839b9695d5cc 100644 --- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -2113,9 +2113,6 @@ nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode, nsCOMPtr currentNode(aNode), parentNode; nsCOMPtr accessNode; - nsIAccessibilityService *accService = GetAccService(); - NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE); - do { currentNode->GetParentNode(getter_AddRefs(parentNode)); currentNode = parentNode; @@ -2126,11 +2123,12 @@ nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode, } nsCOMPtr relevantNode; - if (NS_SUCCEEDED(accService->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) { + if (NS_SUCCEEDED(GetAccService()->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) { currentNode = relevantNode; } if (aCanCreate) { - accService->GetAccessibleInWeakShell(currentNode, mWeakShell, aAccessible); + GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell, + aAccessible); } else { // Only return cached accessibles, don't create anything nsCOMPtr accessNode; diff --git a/accessible/src/base/nsRelUtils.cpp b/accessible/src/base/nsRelUtils.cpp index cc4461076d78..da8c4fdd215c 100644 --- a/accessible/src/base/nsRelUtils.cpp +++ b/accessible/src/base/nsRelUtils.cpp @@ -89,11 +89,10 @@ nsRelUtils::AddTargetFromContent(PRUint32 aRelationType, if (!aContent) return NS_OK_NO_RELATION_TARGET; - nsCOMPtr accService = nsAccessNode::GetAccService(); nsCOMPtr node(do_QueryInterface(aContent)); nsCOMPtr accessible; - accService->GetAccessibleFor(node, getter_AddRefs(accessible)); + GetAccService()->GetAccessibleFor(node, getter_AddRefs(accessible)); return AddTarget(aRelationType, aRelation, accessible); } diff --git a/accessible/src/base/nsTextEquivUtils.cpp b/accessible/src/base/nsTextEquivUtils.cpp index e4a7e6ad8654..2558cfa08553 100644 --- a/accessible/src/base/nsTextEquivUtils.cpp +++ b/accessible/src/base/nsTextEquivUtils.cpp @@ -152,14 +152,14 @@ nsTextEquivUtils::AppendTextEquivFromContent(nsIAccessible *aInitiatorAcc, nsIFrame *frame = aContent->GetPrimaryFrame(); PRBool isVisible = frame && frame->GetStyleVisibility()->IsVisible(); - nsresult rv; + nsresult rv = NS_ERROR_FAILURE; PRBool goThroughDOMSubtree = PR_TRUE; if (isVisible) { nsCOMPtr accessible; - rv = nsAccessNode::GetAccService()-> - GetAccessibleInShell(DOMNode, shell, getter_AddRefs(accessible)); - if (NS_SUCCEEDED(rv) && accessible) { + GetAccService()->GetAccessibleInShell(DOMNode, shell, + getter_AddRefs(accessible)); + if (accessible) { rv = AppendFromAccessible(accessible, aString); goThroughDOMSubtree = PR_FALSE; } diff --git a/accessible/src/html/nsHTMLSelectAccessible.cpp b/accessible/src/html/nsHTMLSelectAccessible.cpp index 4e8b4a452996..c355347b864d 100644 --- a/accessible/src/html/nsHTMLSelectAccessible.cpp +++ b/accessible/src/html/nsHTMLSelectAccessible.cpp @@ -110,9 +110,9 @@ void nsHTMLSelectableAccessible::iterator::CalcSelectionCount(PRInt32 *aSelectio (*aSelectionCount)++; } -void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibilityService *aAccService, - nsIMutableArray *aSelectedAccessibles, - nsPresContext *aContext) +void +nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles, + nsPresContext *aContext) { PRBool isSelected = PR_FALSE; nsCOMPtr tempAccess; @@ -121,7 +121,8 @@ void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibil mOption->GetSelected(&isSelected); if (isSelected) { nsCOMPtr optionNode(do_QueryInterface(mOption)); - aAccService->GetAccessibleInWeakShell(optionNode, mWeakShell, getter_AddRefs(tempAccess)); + GetAccService()->GetAccessibleInWeakShell(optionNode, mWeakShell, + getter_AddRefs(tempAccess)); } } @@ -129,10 +130,10 @@ void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibil aSelectedAccessibles->AppendElement(static_cast(tempAccess), PR_FALSE); } -PRBool nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex, - nsIAccessibilityService *aAccService, - nsPresContext *aContext, - nsIAccessible **aAccessible) +PRBool +nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex, + nsPresContext *aContext, + nsIAccessible **aAccessible) { PRBool isSelected = PR_FALSE; @@ -143,7 +144,7 @@ PRBool nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIn if (isSelected) { if (mSelCount == aIndex) { nsCOMPtr optionNode(do_QueryInterface(mOption)); - aAccService->GetAccessibleInWeakShell(optionNode, mWeakShell, aAccessible); + GetAccService()->GetAccessibleInWeakShell(optionNode, mWeakShell, aAccessible); return PR_TRUE; } mSelCount++; @@ -201,10 +202,6 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectedChildren(nsIArray **_retval { *_retval = nsnull; - nsCOMPtr accService(do_GetService("@mozilla.org/accessibilityService;1")); - if (!accService) - return NS_ERROR_FAILURE; - nsCOMPtr selectedAccessibles = do_CreateInstance(NS_ARRAY_CONTRACTID); NS_ENSURE_STATE(selectedAccessibles); @@ -215,7 +212,7 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectedChildren(nsIArray **_retval nsHTMLSelectableAccessible::iterator iter(this, mWeakShell); while (iter.Advance()) - iter.AddAccessibleIfSelected(accService, selectedAccessibles, context); + iter.AddAccessibleIfSelected(selectedAccessibles, context); PRUint32 uLength = 0; selectedAccessibles->GetLength(&uLength); @@ -231,17 +228,13 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccess { *_retval = nsnull; - nsCOMPtr accService(do_GetService("@mozilla.org/accessibilityService;1")); - if (!accService) - return NS_ERROR_FAILURE; - nsPresContext *context = GetPresContext(); if (!context) return NS_ERROR_FAILURE; nsHTMLSelectableAccessible::iterator iter(this, mWeakShell); while (iter.Advance()) - if (iter.GetAccessibleIfSelected(aIndex, accService, context, _retval)) + if (iter.GetAccessibleIfSelected(aIndex, context, _retval)) return NS_OK; // No matched item found @@ -426,7 +419,6 @@ nsHTMLSelectListAccessible::CacheOptSiblings(nsIContent *aParentContent) nsHTMLSelectOptionAccessible::nsHTMLSelectOptionAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell): nsHyperTextAccessibleWrap(aDOMNode, aShell) { - nsCOMPtr accService(do_GetService("@mozilla.org/accessibilityService;1")); nsCOMPtr parentNode; aDOMNode->GetParentNode(getter_AddRefs(parentNode)); nsCOMPtr parentAccessible; @@ -436,7 +428,8 @@ nsHyperTextAccessibleWrap(aDOMNode, aShell) // GetParent would normally return. This is because the // nsHTMLComboboxListAccessible is inserted into the accessible hierarchy // where there is no DOM node for it. - accService->GetAccessibleInWeakShell(parentNode, mWeakShell, getter_AddRefs(parentAccessible)); + GetAccService()->GetAccessibleInWeakShell(parentNode, mWeakShell, + getter_AddRefs(parentAccessible)); if (parentAccessible) { if (nsAccUtils::RoleInternal(parentAccessible) == nsIAccessibleRole::ROLE_COMBOBOX) { @@ -839,14 +832,11 @@ nsIContent* nsHTMLSelectOptionAccessible::GetSelectState(PRUint32* aState, nsCOMPtr selectNode(do_QueryInterface(content)); if (selectNode) { - nsCOMPtr accService = GetAccService(); - if (accService) { - nsCOMPtr selAcc; - accService->GetAccessibleFor(selectNode, getter_AddRefs(selAcc)); - if (selAcc) { - selAcc->GetState(aState, aExtraState); - return content; - } + nsCOMPtr selAcc; + GetAccService()->GetAccessibleFor(selectNode, getter_AddRefs(selAcc)); + if (selAcc) { + selAcc->GetState(aState, aExtraState); + return content; } } return nsnull; @@ -1026,14 +1016,13 @@ nsHTMLComboboxAccessible::GetFocusedOptionAccessible() } nsCOMPtr focusedOptionNode; nsHTMLSelectOptionAccessible::GetFocusedOptionNode(mDOMNode, getter_AddRefs(focusedOptionNode)); - nsIAccessibilityService *accService = GetAccService(); - if (!focusedOptionNode || !accService) { + if (!focusedOptionNode) { return nsnull; } nsIAccessible *optionAccessible; - accService->GetAccessibleInWeakShell(focusedOptionNode, mWeakShell, - &optionAccessible); + GetAccService()->GetAccessibleInWeakShell(focusedOptionNode, mWeakShell, + &optionAccessible); return optionAccessible; } diff --git a/accessible/src/html/nsHTMLSelectAccessible.h b/accessible/src/html/nsHTMLSelectAccessible.h index 7c3e5fe5332e..76e54a569506 100644 --- a/accessible/src/html/nsHTMLSelectAccessible.h +++ b/accessible/src/html/nsHTMLSelectAccessible.h @@ -45,7 +45,6 @@ #include "nsIDOMHTMLOptionsCollection.h" #include "nsIDOMHTMLOptionElement.h" #include "nsIDOMNode.h" -#include "nsIAccessibilityService.h" #include "nsAccessibleTreeWalker.h" class nsIMutableArray; @@ -104,10 +103,10 @@ protected: void CalcSelectionCount(PRInt32 *aSelectionCount); void Select(PRBool aSelect); - void AddAccessibleIfSelected(nsIAccessibilityService *aAccService, - nsIMutableArray *aSelectedAccessibles, + void AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles, nsPresContext *aContext); - PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsIAccessibilityService *aAccService, nsPresContext *aContext, nsIAccessible **_retval); + PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsPresContext *aContext, + nsIAccessible **aAccessible); PRBool Advance(); }; diff --git a/accessible/src/msaa/nsAccessNodeWrap.cpp b/accessible/src/msaa/nsAccessNodeWrap.cpp index e49afadb3caf..945081da9dee 100644 --- a/accessible/src/msaa/nsAccessNodeWrap.cpp +++ b/accessible/src/msaa/nsAccessNodeWrap.cpp @@ -39,7 +39,6 @@ #include "nsAccessNodeWrap.h" #include "ISimpleDOMNode_i.c" #include "nsAccessibilityAtoms.h" -#include "nsIAccessibilityService.h" #include "nsIAccessible.h" #include "nsAttrName.h" #include "nsIDocument.h" @@ -411,13 +410,10 @@ ISimpleDOMNode* nsAccessNodeWrap::MakeAccessNode(nsIDOMNode *node) if (!doc) return NULL; - nsCOMPtr accService(do_GetService("@mozilla.org/accessibilityService;1")); - if (!accService) - return NULL; - ISimpleDOMNode *iNode = NULL; nsCOMPtr nsAcc; - accService->GetAccessibleInWeakShell(node, mWeakShell, getter_AddRefs(nsAcc)); + GetAccService()->GetAccessibleInWeakShell(node, mWeakShell, + getter_AddRefs(nsAcc)); if (nsAcc) { nsCOMPtr accessNode(do_QueryInterface(nsAcc)); NS_ASSERTION(accessNode, "nsIAccessible impl does not inherit from nsIAccessNode"); diff --git a/accessible/src/xforms/nsXFormsAccessible.cpp b/accessible/src/xforms/nsXFormsAccessible.cpp index f8ce8d3d8dec..d783946f9ebe 100644 --- a/accessible/src/xforms/nsXFormsAccessible.cpp +++ b/accessible/src/xforms/nsXFormsAccessible.cpp @@ -125,7 +125,6 @@ nsXFormsAccessible::CacheSelectChildren(nsIDOMNode *aContainerNode) nsCOMPtr accessible; nsRefPtr acc; - PRUint32 childLength = 0; for (PRUint32 index = 0; index < length; index++) { nsCOMPtr child; children->Item(index, getter_AddRefs(child)); diff --git a/accessible/src/xul/nsXULMenuAccessible.cpp b/accessible/src/xul/nsXULMenuAccessible.cpp index 98de3a43217e..469fa1c4049d 100644 --- a/accessible/src/xul/nsXULMenuAccessible.cpp +++ b/accessible/src/xul/nsXULMenuAccessible.cpp @@ -120,9 +120,6 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre return NS_ERROR_FAILURE; } - nsCOMPtr accService = GetAccService(); - NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE); - nsCOMPtr selectedAccessibles = do_CreateInstance(NS_ARRAY_CONTRACTID); NS_ENSURE_STATE(selectedAccessibles); @@ -138,8 +135,8 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre nsCOMPtr selectedItem; xulMultiSelect->GetSelectedItem(index, getter_AddRefs(selectedItem)); nsCOMPtr selectedNode(do_QueryInterface(selectedItem)); - accService->GetAccessibleInWeakShell(selectedNode, mWeakShell, - getter_AddRefs(selectedAccessible)); + GetAccService()->GetAccessibleInWeakShell(selectedNode, mWeakShell, + getter_AddRefs(selectedAccessible)); if (selectedAccessible) selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE); } @@ -149,8 +146,8 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem)); nsCOMPtr selectedNode(do_QueryInterface(selectedItem)); if(selectedNode) { - accService->GetAccessibleInWeakShell(selectedNode, mWeakShell, - getter_AddRefs(selectedAccessible)); + GetAccService()->GetAccessibleInWeakShell(selectedNode, mWeakShell, + getter_AddRefs(selectedAccessible)); if (selectedAccessible) selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE); } @@ -183,13 +180,11 @@ NS_IMETHODIMP nsXULSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccessi mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem)); if (selectedItem) { - nsCOMPtr accService = GetAccService(); - if (accService) { - accService->GetAccessibleInWeakShell(selectedItem, mWeakShell, aAccessible); - if (*aAccessible) { - NS_ADDREF(*aAccessible); - return NS_OK; - } + GetAccService()->GetAccessibleInWeakShell(selectedItem, mWeakShell, + aAccessible); + if (*aAccessible) { + NS_ADDREF(*aAccessible); + return NS_OK; } } @@ -354,8 +349,8 @@ nsXULMenuitemAccessible::GetStateInternal(PRUint32 *aState, grandParentAcc->GetState(&grandParentState, &grandParentExtState); *aState &= ~(nsIAccessibleStates::STATE_OFFSCREEN | nsIAccessibleStates::STATE_INVISIBLE); - *aState |= grandParentState & nsIAccessibleStates::STATE_OFFSCREEN | - grandParentState & nsIAccessibleStates::STATE_INVISIBLE; + *aState |= (grandParentState & nsIAccessibleStates::STATE_OFFSCREEN) | + (grandParentState & nsIAccessibleStates::STATE_INVISIBLE); if (aExtraState) { *aExtraState |= grandParentExtState & nsIAccessibleStates::EXT_STATE_OPAQUE; diff --git a/browser/base/content/tabbrowser.css b/browser/base/content/tabbrowser.css index 7ba3830fc516..05ca6976f29e 100644 --- a/browser/base/content/tabbrowser.css +++ b/browser/base/content/tabbrowser.css @@ -40,6 +40,10 @@ display: none; } +tabpanels { + background-color: white; +} + %ifdef MOZ_WIDGET_GTK2 /* Favicons override the "images-in-menus" metric in xul.css */ .alltabs-item > .menu-iconic-left { diff --git a/browser/components/sessionstore/src/nsSessionStore.js b/browser/components/sessionstore/src/nsSessionStore.js index 9b8650150f96..dd41801e2528 100644 --- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -1334,7 +1334,15 @@ SessionStoreService.prototype = { } catch (ex) { debug(ex); } } - + + if (aEntry.docIdentifier) { + entry.docIdentifier = aEntry.docIdentifier; + } + + if (aEntry.stateData) { + entry.stateData = aEntry.stateData; + } + if (!(aEntry instanceof Ci.nsISHContainer)) { return entry; } @@ -2038,9 +2046,11 @@ SessionStoreService.prototype = { delete this._windows[aWindow.__SSi]._restoring; } - // helper hash for ensuring unique frame IDs + // helper hashes for ensuring unique frame IDs and unique document + // identifiers. var idMap = { used: {} }; - this.restoreHistory(aWindow, aTabs, aTabData, idMap); + var docIdentMap = {}; + this.restoreHistory(aWindow, aTabs, aTabData, idMap, docIdentMap); }, /** @@ -2054,7 +2064,8 @@ SessionStoreService.prototype = { * @param aIdMap * Hash for ensuring unique frame IDs */ - restoreHistory: function sss_restoreHistory(aWindow, aTabs, aTabData, aIdMap) { + restoreHistory: + function sss_restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap) { var _this = this; while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) { aTabs.shift(); // this tab got removed before being completely restored @@ -2090,7 +2101,8 @@ SessionStoreService.prototype = { //XXXzpao Wallpaper patch for bug 514751 if (!tabData.entries[i].url) continue; - history.addEntry(this._deserializeHistoryEntry(tabData.entries[i], aIdMap), true); + history.addEntry(this._deserializeHistoryEntry(tabData.entries[i], + aIdMap, aDocIdentMap), true); } // make sure to reset the capabilities and attributes, in case this tab gets reused @@ -2152,7 +2164,9 @@ SessionStoreService.prototype = { browser.loadURI(tabData.userTypedValue, null, null, true); } - aWindow.setTimeout(function(){ _this.restoreHistory(aWindow, aTabs, aTabData, aIdMap); }, 0); + aWindow.setTimeout(function(){ + _this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap); + }, 0); }, /** @@ -2163,7 +2177,9 @@ SessionStoreService.prototype = { * Hash for ensuring unique frame IDs * @returns nsISHEntry */ - _deserializeHistoryEntry: function sss_deserializeHistoryEntry(aEntry, aIdMap) { + _deserializeHistoryEntry: + function sss_deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) { + var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"]. createInstance(Ci.nsISHEntry); @@ -2195,7 +2211,11 @@ SessionStoreService.prototype = { } shEntry.ID = id; } - + + if (aEntry.stateData) { + shEntry.stateData = aEntry.stateData; + } + if (aEntry.scroll) { var scrollPos = (aEntry.scroll || "0,0").split(","); scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0]; @@ -2216,6 +2236,28 @@ SessionStoreService.prototype = { shEntry.postData = stream; } + if (aEntry.docIdentifier) { + // Get a new document identifier for this entry to ensure that history + // entries after a session restore are considered to have different + // documents from the history entries before the session restore. + // Document identifiers are 64-bit ints, so JS will loose precision and + // start assigning all entries the same doc identifier if these ever get + // large enough. + // + // It's a potential security issue if document identifiers aren't + // globally unique, but shEntry.setUniqueDocIdentifier() below guarantees + // that we won't re-use a doc identifier within a given instance of the + // application. + let ident = aDocIdentMap[aEntry.docIdentifier]; + if (!ident) { + shEntry.setUniqueDocIdentifier(); + aDocIdentMap[aEntry.docIdentifier] = shEntry.docIdentifier; + } + else { + shEntry.docIdentifier = ident; + } + } + if (aEntry.owner_b64) { // Firefox 3 var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"]. createInstance(Ci.nsIStringInputStream); @@ -2237,7 +2279,8 @@ SessionStoreService.prototype = { //XXXzpao Wallpaper patch for bug 514751 if (!aEntry.children[i].url) continue; - shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap), i); + shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap, + aDocIdentMap), i); } } diff --git a/browser/components/sessionstore/test/browser/Makefile.in b/browser/components/sessionstore/test/browser/Makefile.in index 77d5fa1ff6c9..9f05784edeb4 100644 --- a/browser/components/sessionstore/test/browser/Makefile.in +++ b/browser/components/sessionstore/test/browser/Makefile.in @@ -108,6 +108,7 @@ _BROWSER_TEST_FILES = \ browser_491577.js \ browser_493467.js \ browser_495495.js \ + browser_500328.js \ browser_506482.js \ browser_514751.js \ browser_522545.js \ diff --git a/browser/components/sessionstore/test/browser/browser_500328.js b/browser/components/sessionstore/test/browser/browser_500328.js new file mode 100644 index 000000000000..89ffbc7410ca --- /dev/null +++ b/browser/components/sessionstore/test/browser/browser_500328.js @@ -0,0 +1,135 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is sessionstore test code. + * + * The Initial Developer of the Original Code is + * Justin Lebar + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +function checkState(tab) { + // Go back and then forward, and make sure that the state objects received + // from the popState event are as we expect them to be. + // + // We also add a node to the document's body when after going back and make + // sure it's still there after we go forward -- this is to test that the two + // history entries correspond to the same document. + + let popStateCount = 0; + + tab.linkedBrowser.addEventListener("popstate", function(aEvent) { + let contentWindow = tab.linkedBrowser.contentWindow; + if (popStateCount == 0) { + popStateCount++; + ok(aEvent.state, "Event should have a state property."); + is(JSON.stringify(aEvent.state), JSON.stringify({obj1:1}), + "first popstate object."); + + // Add a node with id "new-elem" to the document. + let doc = contentWindow.document; + ok(!doc.getElementById("new-elem"), + "doc shouldn't contain new-elem before we add it."); + let elem = doc.createElement("div"); + elem.id = "new-elem"; + doc.body.appendChild(elem); + + contentWindow.history.forward(); + } + else if (popStateCount == 1) { + popStateCount++; + is(JSON.stringify(aEvent.state), JSON.stringify({obj3:3}), + "second popstate object."); + + // Make sure that the new-elem node is present in the document. If it's + // not, then this history entry has a different doc identifier than the + // previous entry, which is bad. + let doc = contentWindow.document; + let newElem = doc.getElementById("new-elem"); + ok(newElem, "doc should contain new-elem."); + newElem.parentNode.removeChild(newElem); + ok(!doc.getElementById("new-elem"), "new-elem should be removed."); + + // Clean up after ourselves and finish the test. + tab.linkedBrowser.removeEventListener("popstate", arguments.callee, false); + gBrowser.removeTab(tab); + finish(); + } + }, true); + + tab.linkedBrowser.contentWindow.history.back(); +} + +function test() { + // Tests session restore functionality of history.pushState and + // history.replaceState(). (Bug 500328) + + let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); + waitForExplicitFinish(); + + // We open a new blank window, let it load, and then load in + // http://example.com. We need to load the blank window first, otherwise the + // docshell gets confused and doesn't have a current history entry. + let tab = gBrowser.addTab("about:blank"); + let tabBrowser = tab.linkedBrowser; + + tabBrowser.addEventListener("load", function(aEvent) { + tabBrowser.removeEventListener("load", arguments.callee, true); + + tabBrowser.loadURI("http://example.com", null, null); + + tabBrowser.addEventListener("load", function(aEvent) { + tabBrowser.removeEventListener("load", arguments.callee, true); + + // After these push/replaceState calls, the window should have three + // history entries: + // testURL (state object: null) <-- oldest + // testURL (state object: {obj1:1}) + // page2 (state object: {obj3:3}) <-- newest + let contentWindow = tab.linkedBrowser.contentWindow; + let history = contentWindow.history; + history.pushState({obj1:1}, "title-obj1"); + history.pushState({obj2:2}, "title-obj2", "page2"); + history.replaceState({obj3:3}, "title-obj3"); + + let state = ss.getTabState(tab); + + // In order to make sure that setWindowState actually modifies the + // window's state, we modify the state here. checkState will fail if + // this change isn't overwritten by setWindowState. + history.replaceState({should_be_overwritten:true}, "title-overwritten"); + + // Restore the state and make sure it looks right, after giving the event + // loop a chance to flush. + ss.setTabState(tab, state, true); + executeSoon(function() { checkState(tab); }); + + }, true); + }, true); +} diff --git a/browser/themes/gnomestripe/browser/browser.css b/browser/themes/gnomestripe/browser/browser.css index c8c3287b37b4..235736cd5913 100644 --- a/browser/themes/gnomestripe/browser/browser.css +++ b/browser/themes/gnomestripe/browser/browser.css @@ -1111,11 +1111,6 @@ statusbarpanel#statusbar-display { list-style-image: url("chrome://global/skin/icons/notloading_16.png"); } - -tabpanels { - -moz-appearance: none; -} - /* Tabs */ .tabbrowser-tab { border: none !important; diff --git a/browser/themes/pinstripe/browser/browser.css b/browser/themes/pinstripe/browser/browser.css index 8dd24b1f6b4f..34a8f7b42a8c 100644 --- a/browser/themes/pinstripe/browser/browser.css +++ b/browser/themes/pinstripe/browser/browser.css @@ -399,7 +399,6 @@ menubutton:not([disabled="true"]):hover:active { -moz-image-region: rect(23px, 36px, 46px, 0px); } #back-button:hover:active:not([disabled]), -#back-button[buttondown="true"]:not([disabled]), #back-button[open="true"] { -moz-image-region: rect(46px, 36px, 69px, 0px); } @@ -414,7 +413,6 @@ menubutton:not([disabled="true"]):hover:active { -moz-image-region: rect(23px, 72px, 46px, 36px); } #forward-button:hover:active:not([disabled]), -#forward-button[buttondown="true"]:not([disabled]), #forward-button[open="true"] { -moz-image-region: rect(46px, 72px, 69px, 36px); } @@ -1591,10 +1589,6 @@ tabbrowser > tabbox { display: none; } -tabbrowser > tabbox > tabpanels { - -moz-appearance: none !important; -} - /** * Tab Drag and Drop */ @@ -1782,10 +1776,6 @@ tabbrowser > tabbox > tabpanels { list-style-image: url("chrome://global/skin/icons/closetab-active.png"); } -tabpanels.plain { - background-color: #fff !important; -} - /* Bookmarks toolbar */ .toolbar-drop-indicator { list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png); diff --git a/browser/themes/winstripe/browser/browser.css b/browser/themes/winstripe/browser/browser.css index 2761e9c5f81f..e802926ae3e7 100644 --- a/browser/themes/winstripe/browser/browser.css +++ b/browser/themes/winstripe/browser/browser.css @@ -1177,10 +1177,6 @@ statusbarpanel#statusbar-display { border-bottom: 1px solid threedshadow; } -tabpanels { - -moz-appearance: none; -} - /* tabbrowser-tab focus ring */ .tabbrowser-tab > .tab-text { border: 1px dotted transparent; diff --git a/caps/idl/nsIScriptSecurityManager.idl b/caps/idl/nsIScriptSecurityManager.idl index 115ac3109041..8b373774af78 100644 --- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -41,7 +41,7 @@ interface nsIURI; interface nsIChannel; -[scriptable, uuid(c0dbfd5e-b7ae-4c18-8674-82492f35d715)] +[scriptable, uuid(50eda256-4dd2-4c7c-baed-96983910af9f)] interface nsIScriptSecurityManager : nsIXPCSecurityManager { ///////////////// Security Checks ////////////////// @@ -54,14 +54,6 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager in JSVal aProperty, in PRUint32 aAction); - /** - * Checks whether the running script is allowed to connect to aTargetURI - */ - [noscript] void checkConnect(in JSContextPtr aJSContext, - in nsIURI aTargetURI, - in string aClassName, - in string aProperty); - /** * Check that the script currently running in context "cx" can load "uri". * diff --git a/caps/include/nsScriptSecurityManager.h b/caps/include/nsScriptSecurityManager.h index f2d4aa11ed63..0cb01490aa77 100644 --- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -410,8 +410,7 @@ public: static nsresult CheckSameOriginPrincipal(nsIPrincipal* aSubject, - nsIPrincipal* aObject, - PRBool aIsCheckConnect); + nsIPrincipal* aObject); static PRUint32 HashPrincipalByOrigin(nsIPrincipal* aPrincipal); @@ -458,8 +457,7 @@ private: nsresult CheckSameOriginDOMProp(nsIPrincipal* aSubject, nsIPrincipal* aObject, - PRUint32 aAction, - PRBool aIsCheckConnect); + PRUint32 aAction); nsresult LookupPolicy(nsIPrincipal* principal, diff --git a/caps/src/nsPrincipal.cpp b/caps/src/nsPrincipal.cpp index f469e0dea902..4fffdf066cff 100644 --- a/caps/src/nsPrincipal.cpp +++ b/caps/src/nsPrincipal.cpp @@ -363,8 +363,7 @@ nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult) // Codebases are equal if they have the same origin. *aResult = NS_SUCCEEDED(nsScriptSecurityManager::CheckSameOriginPrincipal(this, - aOther, - PR_FALSE)); + aOther)); return NS_OK; } diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index d97126b74f64..39b991653d04 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -563,34 +563,6 @@ nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx, aClassName, aProperty, nsnull); } -NS_IMETHODIMP -nsScriptSecurityManager::CheckConnect(JSContext* cx, - nsIURI* aTargetURI, - const char* aClassName, - const char* aPropertyName) -{ - // Get a context if necessary - if (!cx) - { - cx = GetCurrentJSContext(); - if (!cx) - return NS_OK; // No JS context, so allow the load - } - - nsresult rv = CheckLoadURIFromScript(cx, aTargetURI); - if (NS_FAILED(rv)) return rv; - - JSAutoRequest ar(cx); - - JSString* propertyName = ::JS_InternString(cx, aPropertyName); - if (!propertyName) - return NS_ERROR_OUT_OF_MEMORY; - - return CheckPropertyAccessImpl(nsIXPCSecurityManager::ACCESS_CALL_METHOD, nsnull, - cx, nsnull, nsnull, aTargetURI, - nsnull, aClassName, STRING_TO_JSVAL(propertyName), nsnull); -} - NS_IMETHODIMP nsScriptSecurityManager::CheckSameOrigin(JSContext* cx, nsIURI* aTargetURI) @@ -750,7 +722,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, } if(NS_SUCCEEDED(rv)) rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal, - aAction, aTargetURI != nsnull); + aAction); break; } default: @@ -943,8 +915,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, /* static */ nsresult nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject, - nsIPrincipal* aObject, - PRBool aIsCheckConnect) + nsIPrincipal* aObject) { /* ** Get origin of subject and object and compare. @@ -952,36 +923,25 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject, if (aSubject == aObject) return NS_OK; - // These booleans are only used when !aIsCheckConnect. Default - // them to false, and change if that turns out wrong. + // Default to false, and change if that turns out wrong. PRBool subjectSetDomain = PR_FALSE; PRBool objectSetDomain = PR_FALSE; nsCOMPtr subjectURI; nsCOMPtr objectURI; - if (aIsCheckConnect) - { - // Don't use domain for CheckConnect calls, since that's called for - // data-only load checks like XMLHTTPRequest (bug 290100). + aSubject->GetDomain(getter_AddRefs(subjectURI)); + if (!subjectURI) { aSubject->GetURI(getter_AddRefs(subjectURI)); - aObject->GetURI(getter_AddRefs(objectURI)); + } else { + subjectSetDomain = PR_TRUE; } - else - { - aSubject->GetDomain(getter_AddRefs(subjectURI)); - if (!subjectURI) { - aSubject->GetURI(getter_AddRefs(subjectURI)); - } else { - subjectSetDomain = PR_TRUE; - } - aObject->GetDomain(getter_AddRefs(objectURI)); - if (!objectURI) { - aObject->GetURI(getter_AddRefs(objectURI)); - } else { - objectSetDomain = PR_TRUE; - } + aObject->GetDomain(getter_AddRefs(objectURI)); + if (!objectURI) { + aObject->GetURI(getter_AddRefs(objectURI)); + } else { + objectSetDomain = PR_TRUE; } if (SecurityCompareURIs(subjectURI, objectURI)) @@ -990,12 +950,6 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject, // done so in order to be considered the same origin. This prevents // DNS spoofing based on document.domain (154930) - // But this restriction does not apply to CheckConnect calls, since - // that's called for data-only load checks like XMLHTTPRequest where - // we ignore domain (bug 290100). - if (aIsCheckConnect) - return NS_OK; - // If both or neither explicitly set their domain, allow the access if (subjectSetDomain == objectSetDomain) return NS_OK; @@ -1009,7 +963,7 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject, // It's important that // -// CheckSameOriginPrincipal(A, B, PR_FALSE) == NS_OK +// CheckSameOriginPrincipal(A, B) == NS_OK // // imply // @@ -1032,21 +986,13 @@ nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal) nsresult nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject, nsIPrincipal* aObject, - PRUint32 aAction, - PRBool aIsCheckConnect) + PRUint32 aAction) { nsresult rv; - if (aIsCheckConnect) { - // Don't do equality compares, just do a same-origin compare, - // since the object principal isn't a real principal, just a - // GetCodebasePrincipal() on whatever URI we started with. - rv = CheckSameOriginPrincipal(aSubject, aObject, aIsCheckConnect); - } else { - PRBool subsumes; - rv = aSubject->Subsumes(aObject, &subsumes); - if (NS_SUCCEEDED(rv) && !subsumes) { - rv = NS_ERROR_DOM_PROP_ACCESS_DENIED; - } + PRBool subsumes; + rv = aSubject->Subsumes(aObject, &subsumes); + if (NS_SUCCEEDED(rv) && !subsumes) { + rv = NS_ERROR_DOM_PROP_ACCESS_DENIED; } if (NS_SUCCEEDED(rv)) diff --git a/content/base/public/nsIDOMFile.idl b/content/base/public/nsIDOMFile.idl index c3dbed992415..706e46aa5d15 100644 --- a/content/base/public/nsIDOMFile.idl +++ b/content/base/public/nsIDOMFile.idl @@ -39,7 +39,7 @@ interface nsIDOMFileError; -[scriptable, uuid(0845E8AE-56BD-4F0E-962A-3B3E92638A0B)] +[scriptable, uuid(16753172-6890-4e6a-8c10-a7ff30c5ef22)] interface nsIDOMFile : nsISupports { //fileName and fileSize are now deprecated attributes @@ -47,6 +47,7 @@ interface nsIDOMFile : nsISupports readonly attribute unsigned long long fileSize; readonly attribute DOMString name; + readonly attribute DOMString mozFullPath; readonly attribute unsigned long long size; readonly attribute DOMString type; diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 35206e66e7eb..7914d25f0aa5 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -106,8 +106,8 @@ class nsIBoxObject; // IID for the nsIDocument interface #define NS_IDOCUMENT_IID \ - { 0xb04d9176, 0xf087, 0x4d3c, \ - { 0x87, 0x11, 0x13, 0x9d, 0x19, 0x95, 0x43, 0x55 } } +{ 0x6b2f1996, 0x95d4, 0x48db, \ + {0xaf, 0xd1, 0xfd, 0xaa, 0x75, 0x4c, 0x79, 0x92 } } // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) @@ -1225,6 +1225,28 @@ public: Doc_Theme_Bright }; + /** + * Returns the document's pending state object (serialized to JSON), or the + * empty string if one doesn't exist. + * + * This field serves as a waiting place for the history entry's state object: + * We set the field's value to the history entry's state object early on in + * the load, then after we fire onload we deserialize the field's value and + * fire a popstate event containing the resulting object. + */ + nsAString& GetPendingStateObject() + { + return mPendingStateObject; + } + + /** + * Set the document's pending state object (as serialized to JSON). + */ + void SetPendingStateObject(nsAString &obj) + { + mPendingStateObject.Assign(obj); + } + /** * Returns Doc_Theme_None if there is no lightweight theme specified, * Doc_Theme_Dark for a dark theme, Doc_Theme_Bright for a light theme, and @@ -1388,6 +1410,8 @@ protected: nsCOMPtr mDisplayDocument; PRUint32 mEventsSuppressed; + + nsString mPendingStateObject; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID) diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index fd3e3fda1839..e0494141c43a 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -407,6 +407,7 @@ nsContentUtils::InitializeEventTable() { { &nsGkAtoms::onchange, { NS_FORM_CHANGE, EventNameType_HTMLXUL }}, { &nsGkAtoms::onselect, { NS_FORM_SELECTED, EventNameType_HTMLXUL }}, { &nsGkAtoms::onload, { NS_LOAD, EventNameType_All }}, + { &nsGkAtoms::onpopstate, { NS_POPSTATE, EventNameType_HTMLXUL }}, { &nsGkAtoms::onunload, { NS_PAGE_UNLOAD, (EventNameType_HTMLXUL | EventNameType_SVGSVG) }}, { &nsGkAtoms::onhashchange, { NS_HASHCHANGE, EventNameType_HTMLXUL }}, diff --git a/content/base/src/nsDOMFile.cpp b/content/base/src/nsDOMFile.cpp index 2f1a192cce3e..47812fa5114d 100644 --- a/content/base/src/nsDOMFile.cpp +++ b/content/base/src/nsDOMFile.cpp @@ -108,6 +108,16 @@ nsDOMFile::GetName(nsAString &aFileName) return mFile->GetLeafName(aFileName); } +NS_IMETHODIMP +nsDOMFile::GetMozFullPath(nsAString &aFileName) +{ + if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) { + return mFile->GetPath(aFileName); + } + aFileName.Truncate(); + return NS_OK; +} + NS_IMETHODIMP nsDOMFile::GetSize(PRUint64 *aFileSize) { diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 6db924f7e9a2..5c6574e9899d 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -46,6 +46,11 @@ * Base class for all our document implementations. */ +#ifdef MOZ_LOGGING +// so we can get logging even in release builds +#define FORCE_PR_LOG 1 +#endif +#include "prlog.h" #include "plstr.h" #include "prprf.h" @@ -184,13 +189,6 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID); // FOR CSP (autogenerated by xpidl) #include "nsIContentSecurityPolicy.h" - -#ifdef MOZ_LOGGING -// so we can get logging even in release builds -#define FORCE_PR_LOG 1 -#endif -#include "prlog.h" - /* Keeps track of whether or not CSP is enabled */ static PRBool gCSPEnabled = PR_TRUE; diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 11c39cf4db87..e82161446f93 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -650,6 +650,7 @@ GK_ATOM(onkeypress, "onkeypress") GK_ATOM(onkeyup, "onkeyup") GK_ATOM(onLoad, "onLoad") GK_ATOM(onload, "onload") +GK_ATOM(onpopstate, "onpopstate") GK_ATOM(only, "only") // this one is not an event GK_ATOM(onmousedown, "onmousedown") GK_ATOM(onmousemove, "onmousemove") diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 44a99f9dd8b9..1dd5ad039aea 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -2402,9 +2402,13 @@ WebGLContext::ValidateGL() //fprintf(stderr, "GL_MAX_VERTEX_ATTRIBS: %d\n", val); - gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_UNITS, &val); + // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware, + // even though the hardware supports much more. The + // GL_MAX_{COMBINED_}TEXTURE_IMAGE_UNITS value is the accurate + // value. For GLES2, GL_MAX_TEXTURE_UNITS is still correc.t + gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &val); if (val == 0) { - LogMessage("GL_MAX_TEXTURE_UNITS is 0!"); + LogMessage("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is 0!"); return PR_FALSE; } diff --git a/content/events/src/Makefile.in b/content/events/src/Makefile.in index 3b42bcc8505d..d7a41cda6641 100644 --- a/content/events/src/Makefile.in +++ b/content/events/src/Makefile.in @@ -82,6 +82,7 @@ CPPSRCS = \ nsDOMEventTargetHelper.cpp \ nsDOMScrollAreaEvent.cpp \ nsDOMTransitionEvent.cpp \ + nsDOMPopStateEvent.cpp \ $(NULL) # we don't want the shared lib, but we want to force the creation of a static lib. diff --git a/content/events/src/nsDOMEvent.cpp b/content/events/src/nsDOMEvent.cpp index ae875eef581f..fc57c14f69da 100644 --- a/content/events/src/nsDOMEvent.cpp +++ b/content/events/src/nsDOMEvent.cpp @@ -59,12 +59,13 @@ #include "nsIURI.h" #include "nsIScriptSecurityManager.h" #include "nsIScriptError.h" +#include "nsDOMPopStateEvent.h" static const char* const sEventNames[] = { "mousedown", "mouseup", "click", "dblclick", "mouseover", "mouseout", "mousemove", "contextmenu", "keydown", "keyup", "keypress", - "focus", "blur", "load", "beforeunload", "unload", "hashchange", "abort", "error", - "submit", "reset", "change", "select", "input" ,"text", + "focus", "blur", "load", "popstate", "beforeunload", "unload", "hashchange", + "abort", "error", "submit", "reset", "change", "select", "input", "text", "compositionstart", "compositionend", "popupshowing", "popupshown", "popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate", "dragenter", "dragover", "dragexit", "dragdrop", "draggesture", @@ -1328,6 +1329,8 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType) return sEventNames[eDOMEvents_close]; case NS_LOAD: return sEventNames[eDOMEvents_load]; + case NS_POPSTATE: + return sEventNames[eDOMEvents_popstate]; case NS_BEFORE_PAGE_UNLOAD: return sEventNames[eDOMEvents_beforeunload]; case NS_PAGE_UNLOAD: diff --git a/content/events/src/nsDOMEvent.h b/content/events/src/nsDOMEvent.h index a60d743da5b2..5adeb70290f4 100644 --- a/content/events/src/nsDOMEvent.h +++ b/content/events/src/nsDOMEvent.h @@ -58,7 +58,7 @@ class nsDOMEvent : public nsIDOMEvent, { public: - // Note: this enum must be kept in sync with mEventNames in nsDOMEvent.cpp + // Note: this enum must be kept in sync with sEventNames in nsDOMEvent.cpp enum nsDOMEvents { eDOMEvents_mousedown=0, eDOMEvents_mouseup, @@ -74,6 +74,7 @@ public: eDOMEvents_focus, eDOMEvents_blur, eDOMEvents_load, + eDOMEvents_popstate, eDOMEvents_beforeunload, eDOMEvents_unload, eDOMEvents_hashchange, diff --git a/content/events/src/nsDOMPopStateEvent.cpp b/content/events/src/nsDOMPopStateEvent.cpp new file mode 100644 index 000000000000..8ffdeb2b1ae8 --- /dev/null +++ b/content/events/src/nsDOMPopStateEvent.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is the Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsDOMPopStateEvent.h" +#include "nsCycleCollectionParticipant.h" + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMPopStateEvent) + +NS_IMPL_ADDREF_INHERITED(nsDOMPopStateEvent, nsDOMEvent) +NS_IMPL_RELEASE_INHERITED(nsDOMPopStateEvent, nsDOMEvent) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMPopStateEvent, nsDOMEvent) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mState) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMPopStateEvent, nsDOMEvent) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mState) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMPopStateEvent) + NS_INTERFACE_MAP_ENTRY(nsIDOMPopStateEvent) + NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(PopStateEvent) +NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) + +nsDOMPopStateEvent::~nsDOMPopStateEvent() +{ +} + +NS_IMETHODIMP +nsDOMPopStateEvent::GetState(nsIVariant **aState) +{ + NS_PRECONDITION(aState, "null state arg"); + NS_IF_ADDREF(*aState = mState); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMPopStateEvent::InitPopStateEvent(const nsAString &aTypeArg, + PRBool aCanBubbleArg, + PRBool aCancelableArg, + nsIVariant *aStateArg) +{ + nsresult rv = nsDOMEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg); + NS_ENSURE_SUCCESS(rv, rv); + + mState = aStateArg; + return NS_OK; +} + +nsresult NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult, + nsPresContext* aPresContext, + nsEvent* aEvent) +{ + nsDOMPopStateEvent* event = + new nsDOMPopStateEvent(aPresContext, aEvent); + + if (!event) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return CallQueryInterface(event, aInstancePtrResult); +} diff --git a/content/events/src/nsDOMPopStateEvent.h b/content/events/src/nsDOMPopStateEvent.h new file mode 100644 index 000000000000..20cc5f080833 --- /dev/null +++ b/content/events/src/nsDOMPopStateEvent.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is the Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsDOMPopStateEvent_h__ +#define nsDOMPopStateEvent_h__ + +class nsEvent; + +#include "nsIDOMPopStateEvent.h" +#include "nsDOMEvent.h" +#include "nsIVariant.h" +#include "nsCycleCollectionParticipant.h" + +class nsDOMPopStateEvent : public nsDOMEvent, + public nsIDOMPopStateEvent +{ +public: + nsDOMPopStateEvent(nsPresContext* aPresContext, nsEvent* aEvent) + : nsDOMEvent(aPresContext, aEvent) // state + { + } + + virtual ~nsDOMPopStateEvent(); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMPopStateEvent, nsDOMEvent) + + NS_DECL_NSIDOMPOPSTATEEVENT + + NS_FORWARD_TO_NSDOMEVENT + +protected: + nsCOMPtr mState; +}; + +nsresult NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult, + nsPresContext* aPresContext, + nsEvent* aEvent); + +#endif // nsDOMPopStateEvent_h__ diff --git a/content/events/src/nsEventDispatcher.cpp b/content/events/src/nsEventDispatcher.cpp index c3edf42700dc..3d2fcf3bc9c5 100644 --- a/content/events/src/nsEventDispatcher.cpp +++ b/content/events/src/nsEventDispatcher.cpp @@ -48,6 +48,7 @@ #include "nsFixedSizeAllocator.h" #include "nsINode.h" #include "nsPIDOMWindow.h" +#include "nsDOMPopStateEvent.h" #define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0) #define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1) @@ -796,6 +797,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext, // is probably wrong! if (aEventType.LowerCaseEqualsLiteral("transitionevent")) return NS_NewDOMTransitionEvent(aDOMEvent, aPresContext, nsnull); + if (aEventType.LowerCaseEqualsLiteral("popstateevent")) + return NS_NewDOMPopStateEvent(aDOMEvent, aPresContext, nsnull); return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index da23b4b713a4..eba91bfa3a02 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -692,9 +692,30 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand, loadAsHtml5 = PR_FALSE; } - if (!(contentType.EqualsLiteral("text/html") && aCommand && !nsCRT::strcmp(aCommand, "view"))) { + if (loadAsHtml5 && + !(contentType.EqualsLiteral("text/html") && + aCommand && + !nsCRT::strcmp(aCommand, "view"))) { loadAsHtml5 = PR_FALSE; } + + // TODO: Proper about:blank treatment is bug 543435 + if (loadAsHtml5) { + // mDocumentURI hasn't been set, yet, so get the URI from the channel + nsCOMPtr uri; + aChannel->GetOriginalURI(getter_AddRefs(uri)); + // Adapted from nsDocShell: + // GetSpec can be expensive for some URIs, so check the scheme first. + PRBool isAbout = PR_FALSE; + if (uri && NS_SUCCEEDED(uri->SchemeIs("about", &isAbout)) && isAbout) { + nsCAutoString str; + uri->GetSpec(str); + if (str.EqualsLiteral("about:blank")) { + loadAsHtml5 = PR_FALSE; + } + } + } + #ifdef DEBUG else { NS_ASSERTION(mIsRegularHTML, diff --git a/content/smil/SMILBoolType.h b/content/smil/SMILBoolType.h index 674a3903296f..43d18c2f0709 100644 --- a/content/smil/SMILBoolType.h +++ b/content/smil/SMILBoolType.h @@ -44,6 +44,12 @@ namespace mozilla { class SMILBoolType : public nsISMILType { public: + // Singleton for nsSMILValue objects to hold onto. + static SMILBoolType sSingleton; + +protected: + // nsISMILType Methods + // ------------------- virtual nsresult Init(nsSMILValue& aValue) const; virtual void Destroy(nsSMILValue&) const; virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const; @@ -57,10 +63,11 @@ public: double aUnitDistance, nsSMILValue& aResult) const; - static SMILBoolType sSingleton; - private: - SMILBoolType() {} + // Private constructor & destructor: prevent instances beyond my singleton, + // and prevent others from deleting my singleton. + SMILBoolType() {} + ~SMILBoolType() {} }; } // namespace mozilla diff --git a/content/smil/SMILEnumType.h b/content/smil/SMILEnumType.h index 0bb9736e81ed..e439585463bf 100644 --- a/content/smil/SMILEnumType.h +++ b/content/smil/SMILEnumType.h @@ -44,6 +44,12 @@ namespace mozilla { class SMILEnumType : public nsISMILType { public: + // Singleton for nsSMILValue objects to hold onto. + static SMILEnumType sSingleton; + +protected: + // nsISMILType Methods + // ------------------- virtual nsresult Init(nsSMILValue& aValue) const; virtual void Destroy(nsSMILValue&) const; virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const; @@ -57,10 +63,11 @@ public: double aUnitDistance, nsSMILValue& aResult) const; - static SMILEnumType sSingleton; - private: - SMILEnumType() {} + // Private constructor & destructor: prevent instances beyond my singleton, + // and prevent others from deleting my singleton. + SMILEnumType() {} + ~SMILEnumType() {} }; } // namespace mozilla diff --git a/content/smil/nsISMILType.h b/content/smil/nsISMILType.h index 892fa818df37..6ecea01e5d12 100644 --- a/content/smil/nsISMILType.h +++ b/content/smil/nsISMILType.h @@ -75,7 +75,12 @@ class nsSMILValue; class nsISMILType { -public: + /** + * Only give the nsSMILValue class access to this interface. + */ + friend class nsSMILValue; + +protected: /** * Initialises aValue and sets it to some identity value such that adding * aValue to another value of the same type has no effect. @@ -211,11 +216,12 @@ public: double aUnitDistance, nsSMILValue& aResult) const = 0; - /* - * Virtual destructor: Nothing to do here, but subclasses - * may need it. + /** + * Protected destructor, to ensure that no one accidentally deletes an + * instance of this class. + * (The only instances in existence should be singletons - one per subclass.) */ - virtual ~nsISMILType() {}; + ~nsISMILType() {} }; #endif // NS_ISMILTYPE_H_ diff --git a/content/smil/nsSMILCSSProperty.cpp b/content/smil/nsSMILCSSProperty.cpp index a231dfa3cb42..7fbaa240d8ae 100644 --- a/content/smil/nsSMILCSSProperty.cpp +++ b/content/smil/nsSMILCSSProperty.cpp @@ -46,13 +46,16 @@ #include "nsIContent.h" #include "nsIDOMElement.h" +// Helper function static PRBool GetCSSComputedValue(nsIContent* aElem, nsCSSProperty aPropID, nsAString& aResult) { - NS_ENSURE_TRUE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID), - PR_FALSE); + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aPropID), + "Can't look up computed value of shorthand property"); + NS_ABORT_IF_FALSE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID), + "Shouldn't get here for non-animatable properties"); nsIDocument* doc = aElem->GetCurrentDoc(); if (!doc) { @@ -73,8 +76,7 @@ GetCSSComputedValue(nsIContent* aElem, nsresult rv = NS_NewComputedDOMStyle(domElement, EmptyString(), shell, getter_AddRefs(computedStyle)); - if (NS_SUCCEEDED(rv) && computedStyle) { - // NOTE: This will produce an empty string for shorthand values + if (NS_SUCCEEDED(rv)) { computedStyle->GetPropertyValue(aPropID, aResult); return PR_TRUE; } @@ -94,6 +96,20 @@ nsSMILCSSProperty::nsSMILCSSProperty(nsCSSProperty aPropID, nsSMILValue nsSMILCSSProperty::GetBaseValue() const { + // SPECIAL CASE: Shorthands + if (nsCSSProps::IsShorthand(mPropID)) { + // We can't look up the base (computed-style) value of shorthand + // properties, because they aren't guaranteed to have a consistent computed + // value. However, that's not a problem, because it turns out the caller + // isn't going to end up using the value we return anyway. Base values only + // get used when there's interpolation or addition, and the shorthand + // properties we know about don't support those operations. So, we can just + // return a dummy value (initialized with the right type, so as not to + // indicate failure). + return nsSMILValue(&nsSMILCSSValueType::sSingleton); + } + + // GENERAL CASE: Non-Shorthands // (1) Put empty string in override style for property mPropID // (saving old override style value, so we can set it again when we're done) nsCOMPtr overrideStyle; @@ -118,18 +134,11 @@ nsSMILCSSProperty::GetBaseValue() const overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal); } + // (4) Create a nsSMILValue from the computed style nsSMILValue baseValue; if (didGetComputedVal) { - // (4) Create the nsSMILValue from the computed style value - nsSMILCSSValueType::sSingleton.Init(baseValue); - if (!nsCSSProps::IsShorthand(mPropID) && - !nsSMILCSSValueType::sSingleton.ValueFromString(mPropID, mElement, - computedStyleVal, - baseValue)) { - nsSMILCSSValueType::sSingleton.Destroy(baseValue); - NS_ABORT_IF_FALSE(baseValue.IsNull(), - "Destroy should leave us with null-typed value"); - } + nsSMILCSSValueType::ValueFromString(mPropID, mElement, + computedStyleVal, baseValue); } return baseValue; } @@ -140,14 +149,9 @@ nsSMILCSSProperty::ValueFromString(const nsAString& aStr, nsSMILValue& aValue) const { NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); - nsSMILCSSValueType::sSingleton.Init(aValue); - PRBool success = - nsSMILCSSValueType::sSingleton.ValueFromString(mPropID, mElement, - aStr, aValue); - if (!success) { - nsSMILCSSValueType::sSingleton.Destroy(aValue); - } - return success ? NS_OK : NS_ERROR_FAILURE; + + nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue); + return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK; } nsresult @@ -155,32 +159,29 @@ nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue) { NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); - nsresult rv = NS_OK; + // Convert nsSMILValue to string nsAutoString valStr; - - if (nsSMILCSSValueType::sSingleton.ValueToString(aValue, valStr)) { - // Apply the style to the target element - nsCOMPtr overrideStyle; - mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle)); - NS_ABORT_IF_FALSE(overrideStyle, "Need a non-null overrideStyle"); - - nsCOMPtr overrideDecl = - do_QueryInterface(overrideStyle); - if (overrideDecl) { - overrideDecl->SetPropertyValue(mPropID, valStr); - } - } else { + if (!nsSMILCSSValueType::ValueToString(aValue, valStr)) { NS_WARNING("Failed to convert nsSMILValue for CSS property into a string"); - rv = NS_ERROR_FAILURE; + return NS_ERROR_FAILURE; } - return rv; + // Use string value to style the target element + nsCOMPtr overrideStyle; + mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle)); + NS_ABORT_IF_FALSE(overrideStyle, "Need a non-null overrideStyle"); + + nsCOMPtr overrideDecl = do_QueryInterface(overrideStyle); + if (overrideDecl) { + overrideDecl->SetPropertyValue(mPropID, valStr); + } + return NS_OK; } void nsSMILCSSProperty::ClearAnimValue() { - // Put empty string in override style for property propID + // Put empty string in override style for our property nsCOMPtr overrideStyle; mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle)); nsCOMPtr overrideDecl = do_QueryInterface(overrideStyle); diff --git a/content/smil/nsSMILCSSValueType.cpp b/content/smil/nsSMILCSSValueType.cpp index 170461b49a26..588f65ee920b 100644 --- a/content/smil/nsSMILCSSValueType.cpp +++ b/content/smil/nsSMILCSSValueType.cpp @@ -303,59 +303,79 @@ GetPresContextForElement(nsIContent* aElem) return shell ? shell->GetPresContext() : nsnull; } -PRBool -nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID, - nsIContent* aTargetElement, - const nsAString& aString, - nsSMILValue& aValue) const +// Helper function to parse a string into a nsStyleAnimation::Value +static PRBool +ValueFromStringHelper(nsCSSProperty aPropID, + nsIContent* aTargetElement, + nsPresContext* aPresContext, + const nsAString& aString, + nsStyleAnimation::Value& aStyleAnimValue) { - NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton, - "Passed-in value is wrong type"); - NS_ABORT_IF_FALSE(!aValue.mU.mPtr, "expecting barely-initialized outparam"); - - nsPresContext* presContext = GetPresContextForElement(aTargetElement); - if (!presContext) { - NS_WARNING("Not parsing animation value; unable to get PresContext"); - return PR_FALSE; - } - // If value is negative, we'll strip off the "-" so the CSS parser won't - // barf, and then manually make the parsed value negative. (This is a partial - // solution to let us accept some otherwise out-of-bounds CSS values -- bug - // 501188 will provide a more complete fix.) + // barf, and then manually make the parsed value negative. + // (This is a partial solution to let us accept some otherwise out-of-bounds + // CSS values. Bug 501188 will provide a more complete fix.) PRBool isNegative = PR_FALSE; PRUint32 subStringBegin = 0; PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString); if (absValuePos > 0) { - subStringBegin = (PRUint32)absValuePos; isNegative = PR_TRUE; + subStringBegin = (PRUint32)absValuePos; // Start parsing after '-' sign } nsDependentSubstring subString(aString, subStringBegin); - nsStyleAnimation::Value parsedValue; - if (nsStyleAnimation::ComputeValue(aPropID, aTargetElement, - subString, parsedValue)) { - if (isNegative) { - InvertSign(parsedValue); - } - if (aPropID == eCSSProperty_font_size) { - // Divide out text-zoom, since SVG is supposed to ignore it - NS_ABORT_IF_FALSE(parsedValue.GetUnit() == nsStyleAnimation::eUnit_Coord, - "'font-size' value with unexpected style unit"); - parsedValue.SetCoordValue(parsedValue.GetCoordValue() / - presContext->TextZoom()); - } - aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext); - return aValue.mU.mPtr != nsnull; + if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, + subString, aStyleAnimValue)) { + return PR_FALSE; } - return PR_FALSE; + if (isNegative) { + InvertSign(aStyleAnimValue); + } + + if (aPropID == eCSSProperty_font_size) { + // Divide out text-zoom, since SVG is supposed to ignore it + NS_ABORT_IF_FALSE(aStyleAnimValue.GetUnit() == + nsStyleAnimation::eUnit_Coord, + "'font-size' value with unexpected style unit"); + aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() / + aPresContext->TextZoom()); + } + return PR_TRUE; } +// static +void +nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID, + nsIContent* aTargetElement, + const nsAString& aString, + nsSMILValue& aValue) +{ + NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed"); + nsPresContext* presContext = GetPresContextForElement(aTargetElement); + if (!presContext) { + NS_WARNING("Not parsing animation value; unable to get PresContext"); + return; + } + + nsStyleAnimation::Value parsedValue; + if (ValueFromStringHelper(aPropID, aTargetElement, presContext, + aString, parsedValue)) { + sSingleton.Init(aValue); + aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext); + if (!aValue.mU.mPtr) { + // Out of memory! Destroy outparam, to leave it as nsSMILNullType, + // which indicates to our caller that we failed. + sSingleton.Destroy(aValue); + } + } +} + +// static PRBool nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue, - nsAString& aString) const + nsAString& aString) { NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton, - "Passed-in value is wrong type"); + "Unexpected SMIL value type"); const ValueWrapper* wrapper = ExtractValueWrapper(aValue); return !wrapper || nsStyleAnimation::UncomputeValue(wrapper->mPropID, wrapper->mPresContext, diff --git a/content/smil/nsSMILCSSValueType.h b/content/smil/nsSMILCSSValueType.h index e97d226ed73d..9269c0e61cd6 100644 --- a/content/smil/nsSMILCSSValueType.h +++ b/content/smil/nsSMILCSSValueType.h @@ -54,8 +54,12 @@ class nsAString; class nsSMILCSSValueType : public nsISMILType { public: - // nsISMILValueType Methods - // ------------------------ + // Singleton for nsSMILValue objects to hold onto. + static nsSMILCSSValueType sSingleton; + +protected: + // nsISMILType Methods + // ------------------- NS_OVERRIDE virtual nsresult Init(nsSMILValue& aValue) const; NS_OVERRIDE virtual void Destroy(nsSMILValue&) const; NS_OVERRIDE virtual nsresult Assign(nsSMILValue& aDest, @@ -71,24 +75,29 @@ public: double aUnitDistance, nsSMILValue& aResult) const; +public: + // Helper Methods + // -------------- /** * Sets up the given nsSMILValue to represent the given string value. The * string is interpreted as a value for the given property on the given * element. * - * Note: aValue is expected to be freshly initialized (i.e. it should already - * have been passed into nsSMILCSSValueType::Init(), and it should not have - * been set up further via e.g. Assign() or another ValueFromString() call.) + * On failure, this method leaves aValue.mType == nsSMILNullType::sSingleton. + * Otherwise, this method leaves aValue.mType == this class's singleton. * * @param aPropID The property for which we're parsing a value. * @param aTargetElement The target element to whom the property/value * setting applies. * @param aString The string to be parsed as a CSS value. - * @param [out] aValue The nsSMILValue to be populated. - * @return PR_TRUE on success, PR_FALSE on failure. + * @param [out] aValue The nsSMILValue to be populated. Should + * initially be null-typed. + * @pre aValue.IsNull() + * @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton */ - PRBool ValueFromString(nsCSSProperty aPropID, nsIContent* aTargetElement, - const nsAString& aString, nsSMILValue& aValue) const; + static void ValueFromString(nsCSSProperty aPropID, + nsIContent* aTargetElement, + const nsAString& aString, nsSMILValue& aValue); /** * Creates a string representation of the given nsSMILValue. @@ -102,13 +111,13 @@ public: * @param [out] aString The string to be populated with the given value. * @return PR_TRUE on success, PR_FALSE on failure. */ - PRBool ValueToString(const nsSMILValue& aValue, nsAString& aString) const; - - // Singleton for nsSMILValue objects to hold onto. - static nsSMILCSSValueType sSingleton; + static PRBool ValueToString(const nsSMILValue& aValue, nsAString& aString); private: - nsSMILCSSValueType() {} + // Private constructor & destructor: prevent instances beyond my singleton, + // and prevent others from deleting my singleton. + nsSMILCSSValueType() {} + ~nsSMILCSSValueType() {} }; #endif // NS_SMILCSSVALUETYPE_H_ diff --git a/content/smil/nsSMILFloatType.h b/content/smil/nsSMILFloatType.h index 11d4e3fd06e2..a410bda37842 100644 --- a/content/smil/nsSMILFloatType.h +++ b/content/smil/nsSMILFloatType.h @@ -44,6 +44,12 @@ class nsSMILFloatType : public nsISMILType { public: + // Singleton for nsSMILValue objects to hold onto. + static nsSMILFloatType sSingleton; + +protected: + // nsISMILType Methods + // ------------------- virtual nsresult Init(nsSMILValue& aValue) const; virtual void Destroy(nsSMILValue&) const; virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const; @@ -57,10 +63,11 @@ public: double aUnitDistance, nsSMILValue& aResult) const; - static nsSMILFloatType sSingleton; - private: - nsSMILFloatType() {} + // Private constructor & destructor: prevent instances beyond my singleton, + // and prevent others from deleting my singleton. + nsSMILFloatType() {} + ~nsSMILFloatType() {} }; #endif // NS_SMILFLOATTYPE_H_ diff --git a/content/smil/nsSMILNullType.h b/content/smil/nsSMILNullType.h index 899439e6f207..1e4b0cb4fa7b 100644 --- a/content/smil/nsSMILNullType.h +++ b/content/smil/nsSMILNullType.h @@ -44,6 +44,12 @@ class nsSMILNullType : public nsISMILType { public: + // Singleton for nsSMILValue objects to hold onto. + static nsSMILNullType sSingleton; + +protected: + // nsISMILType Methods + // ------------------- virtual nsresult Init(nsSMILValue& aValue) const { return NS_OK; } virtual void Destroy(nsSMILValue& aValue) const {} virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const; @@ -60,7 +66,11 @@ public: double aUnitDistance, nsSMILValue& aResult) const; - static nsSMILNullType sSingleton; +private: + // Private constructor & destructor: prevent instances beyond my singleton, + // and prevent others from deleting my singleton. + nsSMILNullType() {} + ~nsSMILNullType() {} }; #endif // NS_SMILNULLTYPE_H_ diff --git a/content/svg/content/src/nsSVGTransformSMILAttr.cpp b/content/svg/content/src/nsSVGTransformSMILAttr.cpp index f6f67eb18c30..aa50fd0fe87c 100644 --- a/content/svg/content/src/nsSVGTransformSMILAttr.cpp +++ b/content/svg/content/src/nsSVGTransformSMILAttr.cpp @@ -50,12 +50,6 @@ #include "nsISVGValue.h" #include "prdtoa.h" -nsISMILType* -nsSVGTransformSMILAttr::GetSMILType() const -{ - return &nsSVGTransformSMILType::sSingleton; -} - nsresult nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr, const nsISMILAnimationElement* aSrcElement, @@ -65,32 +59,21 @@ nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr, NS_ASSERTION(aValue.IsNull(), "aValue should have been cleared before calling ValueFromString"); - nsSMILValue val(&nsSVGTransformSMILType::sSingleton); - if (val.IsNull()) - return NS_ERROR_FAILURE; - const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type); - const nsIAtom* transformType = typeAttr ? typeAttr->GetAtomValue() : nsGkAtoms::translate; - nsresult rv = ParseValue(aStr, transformType, val); - if (NS_FAILED(rv)) - return rv; - - aValue = val; - - return NS_OK; + ParseValue(aStr, transformType, aValue); + return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK; } nsSMILValue nsSVGTransformSMILAttr::GetBaseValue() const { - nsSVGTransformSMILType *type = &nsSVGTransformSMILType::sSingleton; - nsSMILValue val(type); + nsSMILValue val(&nsSVGTransformSMILType::sSingleton); if (val.IsNull()) - return val; + return val; // Initialization failed nsIDOMSVGTransformList *list = mVal->mBaseVal.get(); @@ -101,7 +84,7 @@ nsSVGTransformSMILAttr::GetBaseValue() const nsresult rv = list->GetItem(i, getter_AddRefs(transform)); if (NS_SUCCEEDED(rv) && transform) { rv = AppendSVGTransformToSMILValue(transform.get(), val); - NS_ENSURE_SUCCESS(rv,nsSMILValue()); + NS_ENSURE_SUCCESS(rv, nsSMILValue()); } } @@ -149,19 +132,12 @@ nsSVGTransformSMILAttr::SetAnimValue(const nsSMILValue& aValue) //---------------------------------------------------------------------- // Implementation helpers -nsresult +void nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec, const nsIAtom* aTransformType, - nsSMILValue& aResult) const + nsSMILValue& aResult) { - nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton; - NS_ASSERTION( - type == static_cast(aResult.mType), - "Unexpected type for SMIL value result"); - - // Reset the result so we can just append to it - nsresult rv = type->Init(aResult); - NS_ENSURE_SUCCESS(rv,rv); + NS_ASSERTION(aResult.IsNull(), "Unexpected type for SMIL value"); float params[3] = { 0.f }; PRInt32 numParsed = ParseParameterList(aSpec, params, 3); @@ -170,12 +146,12 @@ nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec, if (aTransformType == nsGkAtoms::translate) { // tx [ty=0] if (numParsed != 1 && numParsed != 2) - return NS_ERROR_FAILURE; + return; transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE; } else if (aTransformType == nsGkAtoms::scale) { // sx [sy=sx] if (numParsed != 1 && numParsed != 2) - return NS_ERROR_FAILURE; + return; if (numParsed == 1) { params[1] = params[0]; } @@ -183,35 +159,41 @@ nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec, } else if (aTransformType == nsGkAtoms::rotate) { // r [cx=0 cy=0] if (numParsed != 1 && numParsed != 3) - return NS_ERROR_FAILURE; + return; transformType = nsSVGSMILTransform::TRANSFORM_ROTATE; } else if (aTransformType == nsGkAtoms::skewX) { // x-angle if (numParsed != 1) - return NS_ERROR_FAILURE; + return; transformType = nsSVGSMILTransform::TRANSFORM_SKEWX; } else if (aTransformType == nsGkAtoms::skewY) { // y-angle if (numParsed != 1) - return NS_ERROR_FAILURE; + return; transformType = nsSVGSMILTransform::TRANSFORM_SKEWY; } else { - return NS_ERROR_FAILURE; + return; } - return type->AppendTransform(nsSVGSMILTransform(transformType, params), - aResult); + nsSMILValue val(&nsSVGTransformSMILType::sSingleton); + nsSVGSMILTransform transform(transformType, params); + if (NS_FAILED(nsSVGTransformSMILType::AppendTransform(transform, val))) { + return; + } + + // Success! Initialize our outparam with parsed value. + aResult = val; } inline PRBool -nsSVGTransformSMILAttr::IsSpace(const char c) const +IsSpace(const char c) { return (c == 0x9 || c == 0xA || c == 0xD || c == 0x20); } inline void -nsSVGTransformSMILAttr::SkipWsp(nsACString::const_iterator& aIter, - const nsACString::const_iterator& aIterEnd) const +SkipWsp(nsACString::const_iterator& aIter, + const nsACString::const_iterator& aIterEnd) { while (aIter != aIterEnd && IsSpace(*aIter)) ++aIter; @@ -220,7 +202,7 @@ nsSVGTransformSMILAttr::SkipWsp(nsACString::const_iterator& aIter, PRInt32 nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec, float* aVars, - PRInt32 aNVars) const + PRInt32 aNVars) { NS_ConvertUTF16toUTF8 spec(aSpec); @@ -258,9 +240,10 @@ nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec, nsresult nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue( - nsIDOMSVGTransform* aTransform, nsSMILValue& aValue) const + nsIDOMSVGTransform* aTransform, nsSMILValue& aValue) { - nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton; + NS_ASSERTION(aValue.mType == &nsSVGTransformSMILType::sSingleton, + "Unexpected type for SMIL value"); PRUint16 svgTransformType = nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX; aTransform->GetType(&svgTransformType); @@ -328,10 +311,9 @@ nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue( matrix->GetD(&mx[3]); matrix->GetE(&mx[4]); matrix->GetF(&mx[5]); - rv = type->AppendTransform(nsSVGSMILTransform(mx), aValue); - transformType = nsSVGSMILTransform::TRANSFORM_MATRIX; + return nsSVGTransformSMILType::AppendTransform(nsSVGSMILTransform(mx), + aValue); } - break; case nsIDOMSVGTransform::SVG_TRANSFORM_UNKNOWN: // If it's 'unknown', it's probably not initialised, so just skip it. @@ -342,12 +324,11 @@ nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue( return NS_ERROR_FAILURE; } - if (transformType != nsSVGSMILTransform::TRANSFORM_MATRIX) { - rv = - type->AppendTransform(nsSVGSMILTransform(transformType, params), aValue); - } + NS_ABORT_IF_FALSE(transformType != nsSVGSMILTransform::TRANSFORM_MATRIX, + "generalized matrix case should have returned above"); - return rv; + return nsSVGTransformSMILType:: + AppendTransform(nsSVGSMILTransform(transformType, params), aValue); } nsresult @@ -396,52 +377,48 @@ nsSVGTransformSMILAttr::UpdateFromSMILValue( nsresult nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue( const nsSVGSMILTransform& aSMILTransform, - nsIDOMSVGTransform* aSVGTransform) const + nsIDOMSVGTransform* aSVGTransform) { - nsresult rv = NS_ERROR_FAILURE; - switch (aSMILTransform.mTransformType) { case nsSVGSMILTransform::TRANSFORM_TRANSLATE: - rv = aSVGTransform->SetTranslate(aSMILTransform.mParams[0], - aSMILTransform.mParams[1]); - break; + return aSVGTransform->SetTranslate(aSMILTransform.mParams[0], + aSMILTransform.mParams[1]); case nsSVGSMILTransform::TRANSFORM_SCALE: - rv = aSVGTransform->SetScale(aSMILTransform.mParams[0], + return aSVGTransform->SetScale(aSMILTransform.mParams[0], aSMILTransform.mParams[1]); - break; case nsSVGSMILTransform::TRANSFORM_ROTATE: - rv = aSVGTransform->SetRotate(aSMILTransform.mParams[0], - aSMILTransform.mParams[1], - aSMILTransform.mParams[2]); - break; + return aSVGTransform->SetRotate(aSMILTransform.mParams[0], + aSMILTransform.mParams[1], + aSMILTransform.mParams[2]); case nsSVGSMILTransform::TRANSFORM_SKEWX: - rv = aSVGTransform->SetSkewX(aSMILTransform.mParams[0]); - break; + return aSVGTransform->SetSkewX(aSMILTransform.mParams[0]); case nsSVGSMILTransform::TRANSFORM_SKEWY: - rv = aSVGTransform->SetSkewY(aSMILTransform.mParams[0]); - break; + return aSVGTransform->SetSkewY(aSMILTransform.mParams[0]); case nsSVGSMILTransform::TRANSFORM_MATRIX: - { - nsCOMPtr svgMatrix; - rv = NS_NewSVGMatrix(getter_AddRefs(svgMatrix), - aSMILTransform.mParams[0], - aSMILTransform.mParams[1], - aSMILTransform.mParams[2], - aSMILTransform.mParams[3], - aSMILTransform.mParams[4], - aSMILTransform.mParams[5]); - NS_ENSURE_SUCCESS(rv,rv); - NS_ENSURE_TRUE(svgMatrix,NS_ERROR_FAILURE); - rv = aSVGTransform->SetMatrix(svgMatrix); - } - break; + { + nsCOMPtr svgMatrix; + nsresult rv = + NS_NewSVGMatrix(getter_AddRefs(svgMatrix), + aSMILTransform.mParams[0], + aSMILTransform.mParams[1], + aSMILTransform.mParams[2], + aSMILTransform.mParams[3], + aSMILTransform.mParams[4], + aSMILTransform.mParams[5]); + NS_ENSURE_SUCCESS(rv, rv); + NS_ABORT_IF_FALSE(svgMatrix, + "NS_NewSVGMatrix succeeded, so it should have " + "given us a non-null result"); + return aSVGTransform->SetMatrix(svgMatrix); + } + default: + NS_WARNING("Unexpected transform type"); + return NS_ERROR_FAILURE; } - - return rv; } diff --git a/content/svg/content/src/nsSVGTransformSMILAttr.h b/content/svg/content/src/nsSVGTransformSMILAttr.h index 6754391811d3..54ef91c40312 100644 --- a/content/svg/content/src/nsSVGTransformSMILAttr.h +++ b/content/svg/content/src/nsSVGTransformSMILAttr.h @@ -54,11 +54,9 @@ class nsSVGTransformSMILAttr : public nsISMILAttr public: nsSVGTransformSMILAttr(nsSVGAnimatedTransformList* aTransform, nsSVGElement* aSVGElement) - : mVal(aTransform), - mSVGElement(aSVGElement) {} + : mVal(aTransform) {} // nsISMILAttr methods - virtual nsISMILType* GetSMILType() const; virtual nsresult ValueFromString(const nsAString& aStr, const nsISMILAnimationElement* aSrcElement, nsSMILValue& aValue) const; @@ -67,30 +65,24 @@ public: virtual nsresult SetAnimValue(const nsSMILValue& aValue); protected: - nsresult ParseValue(const nsAString& aSpec, - const nsIAtom* aTransformType, - nsSMILValue& aResult) const; - PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars, - PRInt32 aNVars) const; - PRBool IsSpace(const char c) const; - void SkipWsp(nsACString::const_iterator& aIter, - const nsACString::const_iterator& aIterEnd) const; - nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform, - nsSMILValue& aValue) const; - nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList, - const nsSMILValue& aValue); - nsresult GetSVGTransformFromSMILValue( - const nsSVGSMILTransform& aSMILTransform, - nsIDOMSVGTransform* aSVGTransform) const; - already_AddRefed GetSVGTransformFromSMILValue( - const nsSMILValue& aValue) const; + static void ParseValue(const nsAString& aSpec, + const nsIAtom* aTransformType, + nsSMILValue& aResult); + static PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars, + PRInt32 aNVars); + static nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform, + nsSMILValue& aValue); + static nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList, + const nsSMILValue& aValue); + static nsresult GetSVGTransformFromSMILValue( + const nsSVGSMILTransform& aSMILTransform, + nsIDOMSVGTransform* aSVGTransform); private: // Raw pointers are OK here because this nsSVGTransformSMILAttr is both // created & destroyed during a SMIL sample-step, during which time the DOM // isn't modified. nsSVGAnimatedTransformList* mVal; - nsSVGElement* mSVGElement; }; #endif // NS_SVGTRANSFORMSMILATTR_H_ diff --git a/content/svg/content/src/nsSVGTransformSMILType.cpp b/content/svg/content/src/nsSVGTransformSMILType.cpp index ea65a371d2dc..c4b1696113c8 100644 --- a/content/svg/content/src/nsSVGTransformSMILType.cpp +++ b/content/svg/content/src/nsSVGTransformSMILType.cpp @@ -42,28 +42,20 @@ /*static*/ nsSVGTransformSMILType nsSVGTransformSMILType::sSingleton; +typedef nsTArray TransformArray; + //---------------------------------------------------------------------- // nsISMILType implementation nsresult nsSVGTransformSMILType::Init(nsSMILValue &aValue) const { - NS_PRECONDITION(aValue.mType == this || aValue.IsNull(), - "Unexpected value type"); - NS_ASSERTION(aValue.mType != this || aValue.mU.mPtr, - "Invalid nsSMILValue of SVG transform type: NULL data member"); + NS_PRECONDITION(aValue.IsNull(), "Unexpected value type"); - if (aValue.mType != this || !aValue.mU.mPtr) { - // Different type, or no data member: allocate memory and set type - TransformArray* transforms = new TransformArray(1); - NS_ENSURE_TRUE(transforms, NS_ERROR_OUT_OF_MEMORY); - aValue.mU.mPtr = transforms; - aValue.mType = this; - } else { - // Same type, just set clear - TransformArray* transforms = static_cast(aValue.mU.mPtr); - transforms->Clear(); - } + TransformArray* transforms = new TransformArray(1); + NS_ENSURE_TRUE(transforms, NS_ERROR_OUT_OF_MEMORY); + aValue.mU.mPtr = transforms; + aValue.mType = this; return NS_OK; } @@ -313,10 +305,11 @@ nsSVGTransformSMILType::Interpolate(const nsSMILValue& aStartVal, //---------------------------------------------------------------------- // Transform array accessors +// static PRUint32 -nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue) const +nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue) { - NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value"); + NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type"); const TransformArray& transforms = *static_cast(aValue.mU.mPtr); @@ -324,11 +317,12 @@ nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue) const return transforms.Length(); } +// static const nsSVGSMILTransform* nsSVGTransformSMILType::GetTransformAt(PRUint32 aIndex, - const nsSMILValue& aValue) const + const nsSMILValue& aValue) { - NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value"); + NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type"); const TransformArray& transforms = *static_cast(aValue.mU.mPtr); @@ -341,16 +335,14 @@ nsSVGTransformSMILType::GetTransformAt(PRUint32 aIndex, return &transforms[aIndex]; } +// static nsresult nsSVGTransformSMILType::AppendTransform(const nsSVGSMILTransform& aTransform, - nsSMILValue& aValue) const + nsSMILValue& aValue) { - NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value"); + NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type"); TransformArray& transforms = *static_cast(aValue.mU.mPtr); - - nsSVGSMILTransform* transform = transforms.AppendElement(aTransform); - NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY); - - return NS_OK; + return transforms.AppendElement(aTransform) ? + NS_OK : NS_ERROR_OUT_OF_MEMORY; } diff --git a/content/svg/content/src/nsSVGTransformSMILType.h b/content/svg/content/src/nsSVGTransformSMILType.h index d6480db3b60b..ebc3a18cb835 100644 --- a/content/svg/content/src/nsSVGTransformSMILType.h +++ b/content/svg/content/src/nsSVGTransformSMILType.h @@ -106,7 +106,12 @@ class nsSMILValue; class nsSVGTransformSMILType : public nsISMILType { public: - // nsISMILType + // Singleton for nsSMILValue objects to hold onto. + static nsSVGTransformSMILType sSingleton; + +protected: + // nsISMILType Methods + // ------------------- virtual nsresult Init(nsSMILValue& aValue) const; virtual void Destroy(nsSMILValue& aValue) const; virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const; @@ -122,20 +127,22 @@ public: const nsSMILValue& aEndVal, double aUnitDistance, nsSMILValue& aResult) const; + +public: // Transform array accessors - PRUint32 GetNumTransforms(const nsSMILValue& aValue) const; - const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex, - const nsSMILValue& aValue) const; - nsresult AppendTransform(const nsSVGSMILTransform& aTransform, - nsSMILValue& aValue) const; + // ------------------------- + static PRUint32 GetNumTransforms(const nsSMILValue& aValue); + static const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex, + const nsSMILValue& aValue); + static nsresult AppendTransform(const nsSVGSMILTransform& aTransform, + nsSMILValue& aValue); - static nsSVGTransformSMILType sSingleton; - -protected: - typedef nsTArray TransformArray; private: - nsSVGTransformSMILType() {} + // Private constructor & destructor: prevent instances beyond my singleton, + // and prevent others from deleting my singleton. + nsSVGTransformSMILType() {} + ~nsSVGTransformSMILType() {} }; #endif // NS_SVGTRANSFORMSMILTYPE_H_ diff --git a/content/xul/templates/tests/chrome/templates_shared.js b/content/xul/templates/tests/chrome/templates_shared.js index 2e3fe2d80811..96717a9a62bf 100644 --- a/content/xul/templates/tests/chrome/templates_shared.js +++ b/content/xul/templates/tests/chrome/templates_shared.js @@ -52,6 +52,7 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const debug = false; var expectedConsoleMessages = []; +var expectLoggedMessages = null; try { const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]. @@ -88,6 +89,9 @@ function test_template() if (needsOpen) root.open = true; + if (expectLoggedMessages) + expectLoggedMessages(); + checkResults(root, 0); if (changes.length) { diff --git a/content/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul b/content/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul index e3a98b7d1871..60757c1e783e 100644 --- a/content/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul +++ b/content/xul/templates/tests/chrome/test_tmpl_xmlquerywithbindinginrule.xul @@ -7,7 +7,7 @@ --> @@ -37,7 +37,7 @@ var expectedOutput = Components.classes["@mozilla.org/consoleservice;1"]. getService(Components.interfaces.nsIConsoleService).reset(); -function expectLoggedMessages() +expectLoggedMessages = function() { // check log to ensure that two rows have been added var initialNumber = Number(document.getElementById("root").firstChild.nextSibling.id.substring(3)); diff --git a/docshell/base/crashtests/500328-1.html b/docshell/base/crashtests/500328-1.html new file mode 100644 index 000000000000..fd97f84ae1ba --- /dev/null +++ b/docshell/base/crashtests/500328-1.html @@ -0,0 +1,17 @@ + + + + + + diff --git a/docshell/base/crashtests/crashtests.list b/docshell/base/crashtests/crashtests.list index 148a7b19b756..aa125c727426 100644 --- a/docshell/base/crashtests/crashtests.list +++ b/docshell/base/crashtests/crashtests.list @@ -6,3 +6,4 @@ load 430628-1.html load 432114-1.html load 432114-2.html load 436900-1.html +load 500328-1.html diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 455e94815456..62aaaf7aad1f 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -109,6 +109,7 @@ #include "nsIURIClassifier.h" #include "nsIOfflineCacheUpdate.h" #include "nsCPrefetchService.h" +#include "nsJSON.h" // we want to explore making the document own the load group // so we can associate the document URI with the load group. @@ -655,6 +656,8 @@ DispatchPings(nsIContent *content, nsIURI *referrer) ForEachPing(content, SendPing, &info); } +static nsISHEntry* GetRootSHEntry(nsISHEntry *entry); + //***************************************************************************** //*** nsDocShell: Object Management //***************************************************************************** @@ -863,6 +866,14 @@ NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink) mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink); return *aSink ? NS_OK : NS_NOINTERFACE; } + else if (aIID.Equals(NS_GET_IID(nsIDocument)) && + NS_SUCCEEDED(EnsureContentViewer())) { + nsCOMPtr domDoc; + mContentViewer->GetDOMDocument(getter_AddRefs(domDoc)); + if (!domDoc) + return NS_NOINTERFACE; + return domDoc->QueryInterface(aIID, aSink); + } else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) { *aSink = nsnull; @@ -1196,7 +1207,7 @@ nsDocShell::LoadURI(nsIURI * aURI, // The parent was loaded normally. In this case, this *brand new* child really shouldn't // have a SHEntry. If it does, it could be because the parent is replacing an // existing frame with a new frame, in the onLoadHandler. We don't want this - // url to get into session history. Clear off shEntry, and set laod type to + // url to get into session history. Clear off shEntry, and set load type to // LOAD_BYPASS_HISTORY. PRBool inOnLoadHandler=PR_FALSE; parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler); @@ -3226,11 +3237,11 @@ nsDocShell::GetChildSHEntry(PRInt32 aChildOffset, nsISHEntry ** aResult) NS_IMETHODIMP nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry, - PRInt32 aChildOffset) + PRInt32 aChildOffset, PRUint32 loadType) { nsresult rv; - if (mLSHE) { + if (mLSHE && loadType != LOAD_PUSHSTATE) { /* You get here if you are currently building a * hierarchy ie.,you just visited a frameset page */ @@ -3285,7 +3296,8 @@ nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry, nsCOMPtr parent = do_QueryInterface(GetAsSupports(mParent), &rv); if (parent) { - rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset); + rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset, + loadType); } } return rv; @@ -3313,7 +3325,7 @@ nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, PRInt32 aChildOffset) nsCOMPtr parent = do_QueryInterface(GetAsSupports(mParent), &rv); if (parent) { - rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset); + rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType); } @@ -3457,7 +3469,6 @@ NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex) } - NS_IMETHODIMP nsDocShell::LoadURI(const PRUnichar * aURI, PRUint32 aLoadFlags, @@ -3846,6 +3857,13 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL, mFailedURI = aURI; mFailedLoadType = mLoadType; + if (mLSHE) { + // If we don't give mLSHE a new doc identifier here, when we go back or + // forward to another SHEntry with the same doc identifier, the error + // page will persist. + mLSHE->SetUniqueDocIdentifier(); + } + nsCAutoString url; nsCAutoString charset; if (aURI) @@ -5714,13 +5732,13 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress, // We're done with the URI classifier for this channel mClassifier = nsnull; - // - // Notify the ContentViewer that the Document has finished loading... - // - // This will cause any OnLoad(...) handlers to fire, if it is a HTML - // document... - // + // Notify the ContentViewer that the Document has finished loading. This + // will cause any OnLoad(...) and PopState(...) handlers to fire. if (!mEODForCurrentDocument && mContentViewer) { + // Set the pending state object which will be returned to the page in + // the popstate event. + SetDocPendingStateObj(mLSHE); + mIsExecutingOnLoadHandler = PR_TRUE; mContentViewer->LoadComplete(aStatus); mIsExecutingOnLoadHandler = PR_FALSE; @@ -7368,6 +7386,26 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) return NS_OK; } +nsresult +nsDocShell::SetDocPendingStateObj(nsISHEntry *shEntry) +{ + nsresult rv; + + nsCOMPtr document = do_GetInterface(GetAsSupports(this)); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + nsAutoString stateData; + if (shEntry) { + rv = shEntry->GetStateData(stateData); + NS_ENSURE_SUCCESS(rv, rv); + + // if shEntry is null, we just set the pending state object to the + // empty string. + } + + document->SetPendingStateObject(stateData); + return NS_OK; +} nsresult nsDocShell::CheckLoadingPermissions() @@ -7844,27 +7882,50 @@ nsDocShell::InternalLoad(nsIURI * aURI, } #endif } - - if ((aLoadType == LOAD_NORMAL || - aLoadType == LOAD_STOP_CONTENT || - LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) || - aLoadType == LOAD_HISTORY || - aLoadType == LOAD_LINK) && allowScroll) { + + if (aLoadType == LOAD_NORMAL || + aLoadType == LOAD_STOP_CONTENT || + LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) || + aLoadType == LOAD_HISTORY || + aLoadType == LOAD_LINK) { + PRBool wasAnchor = PR_FALSE; PRBool doHashchange = PR_FALSE; nscoord cx, cy; - NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx, &cy, - &doHashchange), - NS_ERROR_FAILURE); - if (wasAnchor) { + if (allowScroll) { + NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx, + &cy, &doHashchange), + NS_ERROR_FAILURE); + } + + // If this is a history load, aSHEntry will have document identifier X + // if it was created as a result of a History.pushState() from a + // SHEntry with doc ident X, or if it was created by changing the hash + // of the URI corresponding to a SHEntry with doc ident X. + PRBool sameDocIdent = PR_FALSE; + if (mOSHE && aSHEntry) { + PRUint64 ourDocIdent, otherDocIdent; + mOSHE->GetDocIdentifier(&ourDocIdent); + aSHEntry->GetDocIdentifier(&otherDocIdent); + sameDocIdent = (ourDocIdent == otherDocIdent); + } + + // Do a short-circuited load if the new URI differs from the current + // URI only in the hash, or if the two entries belong to the same + // document and don't point to the same object. + // + // (If we didn't check that the SHEntries are different objects, + // history.go(0) would short-circuit instead of triggering a true + // load, and we wouldn't dispatch an onload event to the page.) + if (wasAnchor || (sameDocIdent && (mOSHE != aSHEntry))) { mLoadType = aLoadType; mURIResultedInDocument = PR_TRUE; - /* we need to assign mLSHE to aSHEntry right here, so that on History loads, - * SetCurrentURI() called from OnNewURI() will send proper + /* we need to assign mLSHE to aSHEntry right here, so that on History loads, + * SetCurrentURI() called from OnNewURI() will send proper * onLocationChange() notifications to the browser to update - * back/forward buttons. + * back/forward buttons. */ SetHistoryEntry(&mLSHE, aSHEntry); @@ -7877,10 +7938,11 @@ nsDocShell::InternalLoad(nsIURI * aURI, mOSHE->GetOwner(getter_AddRefs(owner)); } OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE); + nsCOMPtr postData; PRUint32 pageIdent = PR_UINT32_MAX; nsCOMPtr cacheKey; - + if (mOSHE) { /* save current position of scroller(s) (bug 59774) */ mOSHE->SetScrollPosition(cx, cy); @@ -7895,8 +7957,19 @@ nsDocShell::InternalLoad(nsIURI * aURI, mOSHE->GetPageIdentifier(&pageIdent); mOSHE->GetCacheKey(getter_AddRefs(cacheKey)); } + + if (mLSHE && wasAnchor) { + // If it's an anchor load, set mLSHE's doc identifier to + // mOSHE's doc identifier -- These are the same documents, + // as far as HTML5 is concerned. + PRUint64 docIdent; + rv = mOSHE->GetDocIdentifier(&docIdent); + if (NS_SUCCEEDED(rv)) { + mLSHE->SetDocIdentifier(docIdent); + } + } } - + /* Assign mOSHE to mLSHE. This will either be a new entry created * by OnNewURI() for normal loads or aSHEntry for history loads. */ @@ -7913,7 +7986,7 @@ nsDocShell::InternalLoad(nsIURI * aURI, // cache first if (cacheKey) mOSHE->SetCacheKey(cacheKey); - + // Propagate our page ident to the new mOSHE so that // we'll know it just differed by a scroll on the page. if (pageIdent != PR_UINT32_MAX) @@ -7949,12 +8022,27 @@ nsDocShell::InternalLoad(nsIURI * aURI, shEntry->SetTitle(mTitle); } - if (doHashchange) { - nsCOMPtr window = - do_QueryInterface(mScriptGlobal); + if (sameDocIdent) { + // Set the doc's URI according to the new history entry's URI + nsCOMPtr newURI; + mOSHE->GetURI(getter_AddRefs(newURI)); + NS_ENSURE_TRUE(newURI, NS_ERROR_FAILURE); + nsCOMPtr doc = + do_GetInterface(GetAsSupports(this)); + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); - if (window) - window->DispatchSyncHashchange(); + doc->SetDocumentURI(newURI); + } + + SetDocPendingStateObj(mOSHE); + + // Dispatch the popstate and hashchange events, as appropriate + nsCOMPtr window = do_QueryInterface(mScriptGlobal); + if (window) { + window->DispatchSyncPopState(); + + if (doHashchange) + window->DispatchSyncHashchange(); } return NS_OK; @@ -8837,6 +8925,14 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner, if (uploadChannel) { uploadChannel->GetUploadStream(getter_AddRefs(inputStream)); } + + // If the response status indicates an error, unlink this session + // history entry from any entries sharing its doc ident. + PRUint32 responseStatus; + nsresult rv = httpChannel->GetResponseStatus(&responseStatus); + if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) { + mLSHE->SetUniqueDocIdentifier(); + } } } /* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in @@ -8858,7 +8954,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner, aLoadType & LOAD_CMD_RELOAD) updateHistory = PR_FALSE; - // Check if the url to be loaded is the same as the one already loaded. + // Check if the url to be loaded is the same as the one already loaded. if (mCurrentURI) aURI->Equals(mCurrentURI, &equalUri); @@ -8895,7 +8991,6 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner, SetHistoryEntry(&mLSHE, mOSHE); } - /* If the user pressed shift-reload, cache will create a new cache key * for the page. Save the new cacheKey in Session History. * see bug 90098 @@ -8985,7 +9080,283 @@ nsDocShell::SetReferrerURI(nsIURI * aURI) //***************************************************************************** // nsDocShell: Session History -//***************************************************************************** +//***************************************************************************** + +nsresult +nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult) +{ + nsresult rv; + aResult.Truncate(); + + // First, try to extract a jsval from the variant |aData|. This works only + // if the variant implements GetAsJSVal. + jsval jsData; + rv = aData->GetAsJSVal(&jsData); + NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED); + + // Now get the JSContext associated with the current document. + // First get the current document. + nsCOMPtr document = do_GetInterface(GetAsSupports(this)); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + // Get the JSContext from the document, like we do in + // nsContentUtils::GetContextFromDocument(). + nsIScriptGlobalObject *sgo = document->GetScopeObject(); + NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE); + + nsIScriptContext *scx = sgo->GetContext(); + NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE); + + JSContext *cx = (JSContext *)scx->GetNativeContext(); + + // If our json call triggers a JS-to-C++ call, we want that call to use cx + // as the context. So we push cx onto the context stack. + nsCOMPtr contextStack = + do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + contextStack->Push(cx); + + nsCOMPtr json = do_GetService("@mozilla.org/dom/json;1"); + if(json) { + // Do the encoding + rv = json->EncodeFromJSVal(&jsData, cx, aResult); + } + else { + rv = NS_ERROR_FAILURE; + } + + // Always pop the stack! + contextStack->Pop(&cx); + + return rv; +} + +NS_IMETHODIMP +nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle, + const nsAString& aURL, PRBool aReplace) +{ + // Implements History.pushState and History.replaceState + + // Here's what we do, roughly in the order specified by HTML5: + // 1. Serialize aData to JSON. + // 2. If the third argument is present, + // a. Resolve the url, relative to the first script's base URL + // b. If (a) fails, raise a SECURITY_ERR + // c. Compare the resulting absolute URL to the document's address. If + // any part of the URLs difer other than the , , and + // components, raise a SECURITY_ERR and abort. + // 3. If !aReplace: + // Remove from the session history all entries after the current entry, + // as we would after a regular navigation. + // 4. As apropriate, either add a state object entry to the session history + // after the current entry with the following properties, or modify the + // current session history entry to set + // a. cloned data as the state object, + // b. the given title as the title, and, + // c. if the third argument was present, the absolute URL found in + // step 2 + // 5. If aReplace is false (i.e. we're doing a pushState instead of a + // replaceState), notify bfcache that we've navigated to a new page. + // 6. If the third argument is present, set the document's current address + // to the absolute URL found in step 2. + // + // It's important that this function not run arbitrary scripts after step 1 + // and before completing step 5. For example, if a script called + // history.back() before we completed step 5, bfcache might destroy an + // active content viewer. Since EvictContentViewers at the end of step 5 + // might run script, we can't just put a script blocker around the critical + // section. + + nsresult rv; + + nsCOMPtr document = do_GetInterface(GetAsSupports(this)); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + mLoadType = LOAD_PUSHSTATE; + + // Step 1: Clone aData by getting its JSON representation + nsString dataStr; + rv = StringifyJSValVariant(aData, dataStr); + NS_ENSURE_SUCCESS(rv, rv); + + // Check that the state object isn't too long. + // Default max length: 640k chars. + PRInt32 maxStateObjSize = 0xA0000; + if (mPrefs) { + mPrefs->GetIntPref("browser.history.maxStateObjectSize", + &maxStateObjSize); + } + if (maxStateObjSize < 0) + maxStateObjSize = 0; + NS_ENSURE_TRUE(dataStr.Length() <= (PRUint32)maxStateObjSize, + NS_ERROR_ILLEGAL_VALUE); + + // Step 2: Resolve aURL + PRBool equalURIs = PR_TRUE; + nsCOMPtr oldURI = mCurrentURI; + nsCOMPtr newURI; + if (aURL.Length() == 0) { + newURI = mCurrentURI; + } + else { + // 2a: Resolve aURL relative to mURI + + nsIURI* docBaseURI = document->GetBaseURI(); + if (!docBaseURI) + return NS_ERROR_FAILURE; + + nsCAutoString spec; + docBaseURI->GetSpec(spec); + + nsCAutoString charset; + rv = docBaseURI->GetOriginCharset(charset); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); + + rv = NS_NewURI(getter_AddRefs(newURI), aURL, + charset.get(), docBaseURI); + + // 2b: If 2a fails, raise a SECURITY_ERR + if (NS_FAILED(rv)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + // 2c: Same-origin check. + if (!URIIsLocalFile(newURI)) { + // In addition to checking that the security manager says that + // the new URI has the same origin as our current URI, we also + // check that the two URIs have the same userpass. (The + // security manager says that |http://foo.com| and + // |http://me@foo.com| have the same origin.) mCurrentURI + // won't contain the password part of the userpass, so this + // means that it's never valid to specify a password in a + // pushState or replaceState URI. + + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); + NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE); + + // It's very important that we check that newURI is of the same + // origin as mCurrentURI, not docBaseURI, because a page can + // set docBaseURI arbitrarily to any domain. + nsCAutoString currentUserPass, newUserPass; + NS_ENSURE_SUCCESS(mCurrentURI->GetUserPass(currentUserPass), + NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass), + NS_ERROR_FAILURE); + if (NS_FAILED(secMan->CheckSameOriginURI(mCurrentURI, + newURI, PR_TRUE)) || + !currentUserPass.Equals(newUserPass)) { + + return NS_ERROR_DOM_SECURITY_ERR; + } + } + else { + // It's a file:// URI + nsCOMPtr docScriptObj = + do_QueryInterface(document); + + if (!docScriptObj) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsCOMPtr principal = docScriptObj->GetPrincipal(); + + if (!principal || + NS_FAILED(principal->CheckMayLoad(newURI, PR_TRUE))) { + + return NS_ERROR_DOM_SECURITY_ERR; + } + } + + mCurrentURI->Equals(newURI, &equalURIs); + + } // end of same-origin check + + nsCOMPtr sessionHistory = mSessionHistory; + if (!sessionHistory) { + // Get the handle to SH from the root docshell + GetRootSessionHistory(getter_AddRefs(sessionHistory)); + } + NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE); + + nsCOMPtr shInternal = + do_QueryInterface(sessionHistory, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Step 3: Create a new entry in the session history; this will erase + // all SHEntries after the new entry and make this entry the current + // one. This operation may modify mOSHE, which we need later, so we + // keep a reference here. + NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE); + nsCOMPtr oldOSHE = mOSHE; + + nsCOMPtr newSHEntry; + if (!aReplace) { + rv = AddToSessionHistory(newURI, nsnull, nsnull, + getter_AddRefs(newSHEntry)); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE); + + // Set the new SHEntry's document identifier, if we can. + PRUint64 ourDocIdent; + NS_ENSURE_SUCCESS(oldOSHE->GetDocIdentifier(&ourDocIdent), + NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS(newSHEntry->SetDocIdentifier(ourDocIdent), + NS_ERROR_FAILURE); + + // AddToSessionHistory may not modify mOSHE. In case it doesn't, + // we'll just set mOSHE here. + mOSHE = newSHEntry; + + } else { + newSHEntry = mOSHE; + newSHEntry->SetURI(newURI); + } + + // Step 4: Modify new/original session history entry + newSHEntry->SetStateData(dataStr); + + // Step 5: If aReplace is false, indicating that we're doing a pushState + // rather than a replaceState, notify bfcache that we've added a page to + // the history so it can evict content viewers if appropriate. + if (!aReplace) { + nsCOMPtr rootSH; + GetRootSessionHistory(getter_AddRefs(rootSH)); + NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED); + + nsCOMPtr internalSH = + do_QueryInterface(rootSH); + NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED); + + PRInt32 curIndex = -1; + rv = rootSH->GetIndex(&curIndex); + if (NS_SUCCEEDED(rv) && curIndex > -1) { + internalSH->EvictContentViewers(curIndex - 1, curIndex); + } + } + + // Step 6: If the document's URI changed, update document's URI and update + // global history + if (!equalURIs) { + SetCurrentURI(newURI, nsnull, PR_TRUE); + document->SetDocumentURI(newURI); + + AddToGlobalHistory(newURI, PR_FALSE, oldURI); + } + + // Try to set the title of the current history element + if (mOSHE) + mOSHE->SetTitle(aTitle); + + // We need this to ensure that the back button is enabled after a + // pushState, if it wasn't already enabled. + FireOnLocationChange(this, nsnull, mCurrentURI); + + return NS_OK; +} + PRBool nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI) { @@ -9428,7 +9799,6 @@ nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry, return rv; } - void nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry) { @@ -9679,9 +10049,6 @@ nsresult nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect, nsIChannel * aChannel) { - if (mItemType != typeContent || !mGlobalHistory) - return NS_OK; - // If this is a POST request, we do not want to include this in global // history, so return early. nsCOMPtr hchan(do_QueryInterface(aChannel)); @@ -9692,16 +10059,26 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect, return NS_OK; } + nsCOMPtr referrer; + if (aChannel) + NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer)); + + return AddToGlobalHistory(aURI, aRedirect, referrer); +} + +nsresult +nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect, + nsIURI * aReferrer) +{ + if (mItemType != typeContent || !mGlobalHistory) + return NS_OK; + PRBool visited; nsresult rv = mGlobalHistory->IsVisited(aURI, &visited); if (NS_FAILED(rv)) return rv; - nsCOMPtr referrer; - if (aChannel) - NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer)); - - rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), referrer); + rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), aReferrer); if (NS_FAILED(rv)) return rv; @@ -9714,6 +10091,7 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect, } return NS_OK; + } //***************************************************************************** diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 68b95ffe9449..00c21e8952e3 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -364,6 +364,10 @@ protected: PRUint32 aLoadType, nscoord *cx, nscoord *cy, PRBool * aDoHashchange); + // Tries to stringify a given variant by converting it to JSON. This only + // works if the variant is backed by a JSVal. + nsresult StringifyJSValVariant(nsIVariant *aData, nsAString &aResult); + // Returns PR_TRUE if would have called FireOnLocationChange, // but did not because aFireOnLocationChange was false on entry. // In this case it is the caller's responsibility to ensure @@ -465,8 +469,11 @@ protected: PRUint32 aStateFlags); // Global History + nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect, nsIChannel * aChannel); + nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect, + nsIURI * aReferrer); // Helper Routines nsresult ConfirmRepost(PRBool * aRepost); @@ -515,6 +522,11 @@ protected: nsIChannel * aChannel, nsresult aResult); + // Sets the current document's pending state object to the given SHEntry's + // state object. The pending state object is eventually given to the page + // in the PopState event. + nsresult SetDocPendingStateObj(nsISHEntry *shEntry); + nsresult CheckLoadingPermissions(); // Security checks to prevent frameset spoofing. See comments at diff --git a/docshell/base/nsDocShellLoadTypes.h b/docshell/base/nsDocShellLoadTypes.h index 4628ccc1814f..c5442e84d1dd 100644 --- a/docshell/base/nsDocShellLoadTypes.h +++ b/docshell/base/nsDocShellLoadTypes.h @@ -92,6 +92,7 @@ enum LoadType { LOAD_BYPASS_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_HISTORY), LOAD_STOP_CONTENT = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT), LOAD_STOP_CONTENT_AND_REPLACE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT | nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY), + LOAD_PUSHSTATE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_PUSHSTATE, nsIWebNavigation::LOAD_FLAGS_NONE), /** * Load type for an error page. These loads are never triggered by users of * Docshell. Instead, Docshell triggers the load itself when a @@ -122,6 +123,7 @@ static inline PRBool IsValidLoadType(PRUint32 aLoadType) case LOAD_BYPASS_HISTORY: case LOAD_STOP_CONTENT: case LOAD_STOP_CONTENT_AND_REPLACE: + case LOAD_PUSHSTATE: case LOAD_ERROR_PAGE: return PR_TRUE; } diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 0e1b8aef4362..26c82da554ce 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -69,8 +69,9 @@ interface nsISecureBrowserUI; interface nsIDOMStorage; interface nsIPrincipal; interface nsIWebBrowserPrint; +interface nsIVariant; -[scriptable, uuid(c95eaff1-14e6-4db1-a806-46be97d5a9b6)] +[scriptable, uuid(3adde256-05a9-43a7-a190-f8fe75eecfd6)] interface nsIDocShell : nsISupports { /** @@ -169,6 +170,13 @@ interface nsIDocShell : nsISupports out nsIDocShell aDocShell, out nsIRequest aRequest); + /** + * Do either a history.pushState() or history.replaceState() operation, + * depending on the value of aReplace. + */ + void addState(in nsIVariant aData, in DOMString aTitle, + in DOMString aURL, in boolean aReplace); + /** * Creates a DocShellLoadInfo object that you can manipulate and then pass * to loadURI. @@ -339,9 +347,10 @@ interface nsIDocShell : nsISupports /** * Load commands for the document */ - const unsigned long LOAD_CMD_NORMAL = 0x1; // Normal load - const unsigned long LOAD_CMD_RELOAD = 0x2; // Reload - const unsigned long LOAD_CMD_HISTORY = 0x4; // Load from history + const unsigned long LOAD_CMD_NORMAL = 0x1; // Normal load + const unsigned long LOAD_CMD_RELOAD = 0x2; // Reload + const unsigned long LOAD_CMD_HISTORY = 0x4; // Load from history + const unsigned long LOAD_CMD_PUSHSTATE = 0x8; // History.pushState() readonly attribute unsigned long busyFlags; diff --git a/docshell/base/nsIDocShellHistory.idl b/docshell/base/nsIDocShellHistory.idl index 5a74417b739b..8cc0819397c3 100644 --- a/docshell/base/nsIDocShellHistory.idl +++ b/docshell/base/nsIDocShellHistory.idl @@ -39,7 +39,7 @@ #include "nsISupports.idl" interface nsISHEntry; -[scriptable, uuid(89caa9f0-8b1c-47fb-b0d3-f0aef0bff749)] +[scriptable, uuid(a89b80a8-3c44-4a25-9d2c-2fb42358b46e)] interface nsIDocShellHistory : nsISupports { /** @@ -48,11 +48,12 @@ interface nsIDocShellHistory : nsISupports nsISHEntry getChildSHEntry(in long aChildOffset); /** - * Add a Child SHEntry for a frameset page + * Add a Child SHEntry for a frameset page, given the child's loadtype. */ void addChildSHEntry(in nsISHEntry aCloneReference, in nsISHEntry aHistoryEntry, - in long aChildOffset); + in long aChildOffset, + in unsigned long aLoadType); /* * Whether this docshell should save entries in global history. diff --git a/docshell/shistory/public/nsISHEntry.idl b/docshell/shistory/public/nsISHEntry.idl index 6235345c9eb2..9dbe424e175c 100644 --- a/docshell/shistory/public/nsISHEntry.idl +++ b/docshell/shistory/public/nsISHEntry.idl @@ -58,7 +58,7 @@ class nsDocShellEditorData; [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData); -[scriptable, uuid(09fecea6-5453-43ba-bf91-3ff32618f037)] +[scriptable, uuid(62b0603f-57ca-439e-a0fb-6f6978500755)] interface nsISHEntry : nsIHistoryEntry { /** URI for the document */ @@ -149,6 +149,21 @@ interface nsISHEntry : nsIHistoryEntry */ attribute unsigned long pageIdentifier; + /** + * docIdentifier is an integer that should be the same for two entries + * attached to the same docshell if and only if the two entries are entries + * for the same document. In practice, two entries A and B will have the + * same docIdentifier if they have the same pageIdentifier or if B was + * created by A calling history.pushState(). + */ + attribute unsigned long long docIdentifier; + + /** + * Changes this entry's doc identifier to a new value which is unique + * among those of all other entries. + */ + void setUniqueDocIdentifier(); + /** attribute to set and get the cache key for the entry */ attribute nsISupports cacheKey; @@ -192,6 +207,12 @@ interface nsISHEntry : nsIHistoryEntry */ attribute nsISupports owner; + /** + * Get/set data associated with this history state via a pushState() call, + * encoded as JSON. + **/ + attribute AString stateData; + /** * Gets the owning pointer to the editor data assosicated with * this shistory entry. This forgets its pointer, so free it when diff --git a/docshell/shistory/src/nsSHEntry.cpp b/docshell/shistory/src/nsSHEntry.cpp index 99ba2bee0c4a..db90cf90259a 100644 --- a/docshell/shistory/src/nsSHEntry.cpp +++ b/docshell/shistory/src/nsSHEntry.cpp @@ -75,6 +75,7 @@ protected: static HistoryTracker *gHistoryTracker = nsnull; static PRUint32 gEntryID = 0; +static PRUint64 gEntryDocIdentifier = 0; nsresult nsSHEntry::Startup() { @@ -104,6 +105,7 @@ nsSHEntry::nsSHEntry() : mLoadType(0) , mID(gEntryID++) , mPageIdentifier(mID) + , mDocIdentifier(gEntryDocIdentifier++) , mScrollPositionX(0) , mScrollPositionY(0) , mIsFrameNavigation(PR_FALSE) @@ -125,6 +127,7 @@ nsSHEntry::nsSHEntry(const nsSHEntry &other) , mLoadType(0) // XXX why not copy? , mID(other.mID) , mPageIdentifier(other.mPageIdentifier) + , mDocIdentifier(other.mDocIdentifier) , mScrollPositionX(0) // XXX why not copy? , mScrollPositionY(0) // XXX why not copy? , mIsFrameNavigation(other.mIsFrameNavigation) @@ -393,6 +396,30 @@ NS_IMETHODIMP nsSHEntry::SetPageIdentifier(PRUint32 aPageIdentifier) return NS_OK; } +NS_IMETHODIMP nsSHEntry::GetDocIdentifier(PRUint64 * aResult) +{ + *aResult = mDocIdentifier; + return NS_OK; +} + +NS_IMETHODIMP nsSHEntry::SetDocIdentifier(PRUint64 aDocIdentifier) +{ + // This ensures that after a session restore, gEntryDocIdentifier is greater + // than all SHEntries' docIdentifiers, which ensures that we'll never repeat + // a doc identifier. + if (aDocIdentifier >= gEntryDocIdentifier) + gEntryDocIdentifier = aDocIdentifier + 1; + + mDocIdentifier = aDocIdentifier; + return NS_OK; +} + +NS_IMETHODIMP nsSHEntry::SetUniqueDocIdentifier() +{ + mDocIdentifier = gEntryDocIdentifier++; + return NS_OK; +} + NS_IMETHODIMP nsSHEntry::GetIsSubFrame(PRBool * aFlag) { *aFlag = mIsFrameNavigation; @@ -470,7 +497,7 @@ nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle, mCacheKey = aCacheKey; mContentType = aContentType; mOwner = aOwner; - + // Set the LoadType by default to loadHistory during creation mLoadType = (PRUint32) nsIDocShellLoadInfo::loadHistory; @@ -866,3 +893,17 @@ nsSHEntry::HasDetachedEditor() return mEditorData != nsnull; } +NS_IMETHODIMP +nsSHEntry::GetStateData(nsAString &aStateData) +{ + aStateData.Assign(mStateData); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::SetStateData(const nsAString &aDataStr) +{ + mStateData.Assign(aDataStr); + return NS_OK; +} + diff --git a/docshell/shistory/src/nsSHEntry.h b/docshell/shistory/src/nsSHEntry.h index a966b97e8f2b..14c085b54a2b 100644 --- a/docshell/shistory/src/nsSHEntry.h +++ b/docshell/shistory/src/nsSHEntry.h @@ -96,9 +96,10 @@ private: nsCOMPtr mPostData; nsCOMPtr mLayoutHistoryState; nsCOMArray mChildren; - PRUint32 mLoadType; + PRUint32 mLoadType; PRUint32 mID; PRUint32 mPageIdentifier; + PRInt64 mDocIdentifier; PRInt32 mScrollPositionX; PRInt32 mScrollPositionY; PRPackedBool mIsFrameNavigation; @@ -115,6 +116,7 @@ private: nsCOMPtr mOwner; nsExpirationState mExpirationState; nsAutoPtr mEditorData; + nsString mStateData; }; #endif /* nsSHEntry_h */ diff --git a/docshell/shistory/src/nsSHistory.cpp b/docshell/shistory/src/nsSHistory.cpp index 83eff115e53e..ffd132642abf 100644 --- a/docshell/shistory/src/nsSHistory.cpp +++ b/docshell/shistory/src/nsSHistory.cpp @@ -478,7 +478,7 @@ nsSHistory::PrintHistory() nsCOMPtr layoutHistoryState; nsCOMPtr uri; nsXPIDLString title; - + entry->GetLayoutHistoryState(getter_AddRefs(layoutHistoryState)); nsCOMPtr hEntry(do_QueryInterface(entry)); if (hEntry) { @@ -492,11 +492,12 @@ nsSHistory::PrintHistory() uri->GetSpec(url); printf("**** SH Transaction #%d, Entry = %x\n", index, entry.get()); - printf("\t\t URL = %s\n", url); + printf("\t\t URL = %s\n", url.get()); + printf("\t\t Title = %s\n", NS_LossyConvertUTF16toASCII(title).get()); - printf("\t\t layout History Data = %x\n", layoutHistoryState); + printf("\t\t layout History Data = %x\n", layoutHistoryState.get()); #endif - + nsCOMPtr next; rv = txn->GetNext(getter_AddRefs(next)); if (NS_SUCCEEDED(rv) && next) { @@ -864,7 +865,7 @@ nsSHistory::EvictContentViewersInRange(PRInt32 aStart, PRInt32 aEnd) if (viewer) { NS_ASSERTION(ownerEntry, "ContentViewer exists but its SHEntry is null"); -#ifdef DEBUG_PAGE_CACHE +#ifdef DEBUG_PAGE_CACHE nsCOMPtr uri; ownerEntry->GetURI(getter_AddRefs(uri)); nsCAutoString spec; @@ -1149,23 +1150,23 @@ nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd) mRequestedIndex = aIndex; nsCOMPtr prevEntry; - GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(prevEntry)); - - nsCOMPtr nextEntry; + GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(prevEntry)); + + nsCOMPtr nextEntry; GetEntryAtIndex(mRequestedIndex, PR_FALSE, getter_AddRefs(nextEntry)); nsCOMPtr nHEntry(do_QueryInterface(nextEntry)); - if (!nextEntry || !prevEntry || !nHEntry) { + if (!nextEntry || !prevEntry || !nHEntry) { mRequestedIndex = -1; return NS_ERROR_FAILURE; } - + // Send appropriate listener notifications PRBool canNavigate = PR_TRUE; // Get the uri for the entry we are about to visit nsCOMPtr nextURI; nHEntry->GetURI(getter_AddRefs(nextURI)); - - if(mListener) { + + if(mListener) { nsCOMPtr listener(do_QueryReferent(mListener)); if (listener) { if (aHistCmd == HIST_CMD_BACK) { @@ -1222,7 +1223,6 @@ nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd) else docShell = mRootDocShell; } - if (!docShell) { // we did not successfully go to the proper index. @@ -1235,8 +1235,6 @@ nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd) return InitiateLoad(nextEntry, docShell, aLoadType); } - - nsresult nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound) { diff --git a/docshell/shistory/src/nsSHistory.h b/docshell/shistory/src/nsSHistory.h index be785969a29f..3c8aa418b427 100644 --- a/docshell/shistory/src/nsSHistory.h +++ b/docshell/shistory/src/nsSHistory.h @@ -66,7 +66,7 @@ class nsSHistory: public PRCList, public nsIWebNavigation { public: - nsSHistory(); + nsSHistory(); NS_DECL_ISUPPORTS NS_DECL_NSISHISTORY @@ -94,7 +94,7 @@ protected: nsresult InitiateLoad(nsISHEntry * aFrameEntry, nsIDocShell * aFrameDS, long aLoadType); NS_IMETHOD LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 histCmd); - + #ifdef DEBUG nsresult PrintHistory(); #endif diff --git a/docshell/test/navigation/blank.html b/docshell/test/navigation/blank.html index 245c62e8d1e2..5360333f1d14 100644 --- a/docshell/test/navigation/blank.html +++ b/docshell/test/navigation/blank.html @@ -1 +1 @@ -This is a blank document. +This is a blank document. \ No newline at end of file diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 160ed477f6f2..ae45a8f842b3 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -82,6 +82,7 @@ #include "nsIDOMNSEvent.h" #include "nsIDOMKeyEvent.h" #include "nsIDOMEventListener.h" +#include "nsIDOMPopStateEvent.h" #include "nsContentUtils.h" #include "nsDOMWindowUtils.h" @@ -1330,13 +1331,15 @@ static nsDOMClassInfoData sClassInfoData[] = { NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(PopStateEvent, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(TransitionEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) }; -// Objects that shuld be constructable through |new Name();| +// Objects that should be constructable through |new Name();| struct nsContractIDMapData { PRInt32 mDOMClassInfoID; @@ -1420,6 +1423,7 @@ jsval nsDOMClassInfo::sOnreset_id = JSVAL_VOID; jsval nsDOMClassInfo::sOnchange_id = JSVAL_VOID; jsval nsDOMClassInfo::sOnselect_id = JSVAL_VOID; jsval nsDOMClassInfo::sOnload_id = JSVAL_VOID; +jsval nsDOMClassInfo::sOnpopstate_id = JSVAL_VOID; jsval nsDOMClassInfo::sOnbeforeunload_id = JSVAL_VOID; jsval nsDOMClassInfo::sOnunload_id = JSVAL_VOID; jsval nsDOMClassInfo::sOnhashchange_id = JSVAL_VOID; @@ -1614,6 +1618,7 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx) SET_JSVAL_TO_STRING(sOnchange_id, cx, "onchange"); SET_JSVAL_TO_STRING(sOnselect_id, cx, "onselect"); SET_JSVAL_TO_STRING(sOnload_id, cx, "onload"); + SET_JSVAL_TO_STRING(sOnpopstate_id, cx, "onpopstate"); SET_JSVAL_TO_STRING(sOnbeforeunload_id, cx, "onbeforeunload"); SET_JSVAL_TO_STRING(sOnunload_id, cx, "onunload"); SET_JSVAL_TO_STRING(sOnhashchange_id, cx, "onhashchange"); @@ -2232,6 +2237,11 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(PopStateEvent, nsIDOMPopStateEvent) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMPopStateEvent) + DOM_CLASSINFO_EVENT_MAP_ENTRIES + DOM_CLASSINFO_MAP_END + DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument) DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLDocument) @@ -7327,7 +7337,8 @@ nsEventReceiverSH::ReallyIsEventName(jsval id, jschar aFirstChar) return (id == sOnpaint_id || id == sOnpageshow_id || id == sOnpagehide_id || - id == sOnpaste_id); + id == sOnpaste_id || + id == sOnpopstate_id); case 'k' : return (id == sOnkeydown_id || id == sOnkeypress_id || diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index 378f9f0b168e..0f8ea3e597af 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -327,6 +327,7 @@ protected: static jsval sOnchange_id; static jsval sOnselect_id; static jsval sOnload_id; + static jsval sOnpopstate_id; static jsval sOnbeforeunload_id; static jsval sOnunload_id; static jsval sOnhashchange_id; diff --git a/dom/base/nsDOMClassInfoID.h b/dom/base/nsDOMClassInfoID.h index f5b23f5baa2f..47bdf94b9ba5 100644 --- a/dom/base/nsDOMClassInfoID.h +++ b/dom/base/nsDOMClassInfoID.h @@ -473,6 +473,7 @@ enum nsDOMClassInfoID { eDOMClassInfo_PaintRequestList_id, eDOMClassInfo_ScrollAreaEvent_id, + eDOMClassInfo_PopStateEvent_id, eDOMClassInfo_EventListenerInfo_id, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 7206440e2487..0ba9c20c0bce 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -79,6 +79,7 @@ #include "nsCycleCollector.h" #include "nsCCUncollectableMarker.h" #include "nsDOMThreadService.h" +#include "nsAutoJSValHolder.h" // Interfaces Needed #include "nsIFrame.h" @@ -112,6 +113,7 @@ #include "nsIDOMKeyEvent.h" #include "nsIDOMMessageEvent.h" #include "nsIDOMPopupBlockedEvent.h" +#include "nsIDOMPopStateEvent.h" #include "nsIDOMOfflineResourceList.h" #include "nsIDOMGeoGeolocation.h" #include "nsPIDOMStorage.h" @@ -169,6 +171,7 @@ #include "nsIXULAppInfo.h" #include "nsNetUtil.h" #include "nsFocusManager.h" +#include "nsIJSON.h" #ifdef MOZ_XUL #include "nsXULPopupManager.h" #include "nsIDOMXULControlElement.h" @@ -361,6 +364,8 @@ static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1"; static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID; static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID; +static const char sPopStatePrefStr[] = "browser.history.allowPopState"; + static PRBool IsAboutBlank(nsIURI* aURI) { @@ -655,9 +660,9 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mTimeoutPublicIdCounter(1), mTimeoutFiringDepth(0), mJSObject(nsnull), + mPendingStorageEventsObsolete(nsnull), mTimeoutsSuspendDepth(0), - mFocusMethod(0), - mPendingStorageEventsObsolete(nsnull) + mFocusMethod(0) #ifdef DEBUG , mSetOpenerWindowCalled(PR_FALSE) #endif @@ -6978,7 +6983,7 @@ nsGlobalWindow::DispatchSyncHashchange() // Don't do anything if the window is frozen. if (IsFrozen()) - return NS_OK; + return NS_OK; // Dispatch the hashchange event, which doesn't bubble and isn't cancelable, // to the outer window. @@ -6987,7 +6992,119 @@ nsGlobalWindow::DispatchSyncHashchange() PR_FALSE, PR_FALSE); } -// Find an nsCanvasFrame under aFrame. Only search the principal +nsresult +nsGlobalWindow::DispatchSyncPopState() +{ + FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK); + + NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), + "Must be safe to run script here."); + + // Check that PopState hasn't been pref'ed off. + if (!nsContentUtils::GetBoolPref(sPopStatePrefStr, PR_FALSE)) + return NS_OK; + + nsresult rv = NS_OK; + + // Bail if the window is frozen. + if (IsFrozen()) { + return NS_OK; + } + + // Bail if there's no document or the document's readystate isn't "complete". + if (!mDoc) { + return NS_OK; + } + + nsIDocument::ReadyState readyState = mDoc->GetReadyStateEnum(); + if (readyState != nsIDocument::READYSTATE_COMPLETE) { + return NS_OK; + } + + // Get the document's pending state object -- it contains the data we're + // going to send along with the popstate event. The object is serialized as + // JSON. + nsAString& stateObjJSON = mDoc->GetPendingStateObject(); + + nsCOMPtr stateObj; + // Parse the JSON, if there's any to parse. + if (!stateObjJSON.IsEmpty()) { + // Get the JSContext associated with our document. We need this for + // deserialization. + nsCOMPtr document = do_QueryInterface(mDocument); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + // Get the JSContext from the document, like we do in + // nsContentUtils::GetContextFromDocument(). + nsIScriptGlobalObject *sgo = document->GetScopeObject(); + NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE); + + nsIScriptContext *scx = sgo->GetContext(); + NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE); + + JSContext *cx = (JSContext*) scx->GetNativeContext(); + + // If our json call triggers a JS-to-C++ call, we want that call to use cx + // as the context. So we push cx onto the context stack. + nsCxPusher cxPusher; + + jsval jsStateObj = JSVAL_NULL; + // Root the container which will hold our decoded state object. + nsAutoGCRoot(&jsStateObj, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // Deserialize the state object into an nsIVariant. + nsCOMPtr json = do_GetService("@mozilla.org/dom/json;1"); + NS_ENSURE_TRUE(cxPusher.Push(cx), NS_ERROR_FAILURE); + rv = json->DecodeToJSVal(stateObjJSON, cx, &jsStateObj); + NS_ENSURE_SUCCESS(rv, rv); + cxPusher.Pop(); + + nsCOMPtr xpconnect = do_GetService(nsIXPConnect::GetCID()); + NS_ENSURE_TRUE(xpconnect, NS_ERROR_FAILURE); + rv = xpconnect->JSValToVariant(cx, &jsStateObj, getter_AddRefs(stateObj)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Obtain a presentation shell for use in creating a popstate event. + nsIPresShell *shell = mDoc->GetPrimaryShell(); + nsCOMPtr presContext; + if (shell) { + presContext = shell->GetPresContext(); + } + + // Create a new popstate event + nsCOMPtr domEvent; + rv = nsEventDispatcher::CreateEvent(presContext, nsnull, + NS_LITERAL_STRING("popstateevent"), + getter_AddRefs(domEvent)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr privateEvent = do_QueryInterface(domEvent); + NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE); + + // Initialize the popstate event, which does bubble but isn't cancellable. + nsCOMPtr popstateEvent = do_QueryInterface(domEvent); + rv = popstateEvent->InitPopStateEvent(NS_LITERAL_STRING("popstate"), + PR_TRUE, PR_FALSE, + stateObj); + NS_ENSURE_SUCCESS(rv, rv); + + rv = privateEvent->SetTrusted(PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr outerWindow = + do_QueryInterface(GetOuterWindow()); + NS_ENSURE_TRUE(outerWindow, NS_ERROR_UNEXPECTED); + + rv = privateEvent->SetTarget(outerWindow); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool dummy; // default action + return DispatchEvent(popstateEvent, &dummy); +} + +// Find an nsICanvasFrame under aFrame. Only search the principal // child lists. aFrame must be non-null. static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame) { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 2ed1658157ff..cac8a5640298 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -448,6 +448,8 @@ public: virtual void SetReadyForFocus(); virtual void PageHidden(); virtual nsresult DispatchSyncHashchange(); + virtual nsresult DispatchSyncPopState(); + virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin); static PRBool DOMWindowDumpEnabled(); diff --git a/dom/base/nsHistory.cpp b/dom/base/nsHistory.cpp index 25c04058ecec..5c2f23ff1536 100644 --- a/dom/base/nsHistory.cpp +++ b/dom/base/nsHistory.cpp @@ -57,6 +57,13 @@ #include "nsReadableUtils.h" #include "nsDOMClassInfo.h" #include "nsContentUtils.h" +#include "nsIDOMNSDocument.h" +#include "nsISHistoryInternal.h" + +static const char* sAllowPushStatePrefStr = + "browser.history.allowPushState"; +static const char* sAllowReplaceStatePrefStr = + "browser.history.allowReplaceState"; // // History class implementation @@ -258,7 +265,7 @@ nsHistory::Go(PRInt32 aDelta) PRInt32 curIndex=-1; PRInt32 len = 0; - nsresult rv = session_history->GetIndex(&curIndex); + nsresult rv = session_history->GetIndex(&curIndex); rv = session_history->GetCount(&len); PRInt32 index = curIndex + aDelta; @@ -272,6 +279,47 @@ nsHistory::Go(PRInt32 aDelta) return NS_OK; } +NS_IMETHODIMP +nsHistory::PushState(nsIVariant *aData, const nsAString& aTitle, + const nsAString& aURL) +{ + // Check that PushState hasn't been pref'ed off. + if (!nsContentUtils::GetBoolPref(sAllowPushStatePrefStr, PR_FALSE)) + return NS_OK; + + NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); + + // AddState might run scripts, so we need to hold a strong reference to the + // docShell here to keep it from going away. + nsCOMPtr docShell = mDocShell; + + // PR_FALSE tells the docshell to add a new history entry instead of + // modifying the current one. + nsresult rv = mDocShell->AddState(aData, aTitle, aURL, PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +NS_IMETHODIMP +nsHistory::ReplaceState(nsIVariant *aData, const nsAString& aTitle, + const nsAString& aURL) +{ + // Check that ReplaceState hasn't been pref'ed off + if (!nsContentUtils::GetBoolPref(sAllowReplaceStatePrefStr, PR_FALSE)) + return NS_OK; + + NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); + + // As in PushState(), we need to keep a strong reference to the docShell + // here. + nsCOMPtr docShell = mDocShell; + + // PR_TRUE tells the docshell to modify the current SHEntry, rather than + // create a new one. + return mDocShell->AddState(aData, aTitle, aURL, PR_TRUE); +} + NS_IMETHODIMP nsHistory::Item(PRUint32 aIndex, nsAString& aReturn) { diff --git a/dom/base/nsLocation.cpp b/dom/base/nsLocation.cpp index 53df363f9fe2..946dc3695764 100644 --- a/dom/base/nsLocation.cpp +++ b/dom/base/nsLocation.cpp @@ -194,7 +194,6 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo) return NS_ERROR_FAILURE; nsCOMPtr owner; - nsCOMPtr sourceURI; if (cx) { // No cx means that there's no JS running, or at least no JS that @@ -222,7 +221,6 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo) !principal) return NS_ERROR_FAILURE; owner = do_QueryInterface(principal); - principal->GetURI(getter_AddRefs(sourceURI)); } // Create load info @@ -232,10 +230,12 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo) loadInfo->SetOwner(owner); - // now set the referrer on the loadinfo - if (sourceURI) { + // Now set the referrer on the loadinfo. We need to do this in order to get + // the correct referrer URI from a document which was pushStated. + nsCOMPtr sourceURI; + result = GetURI(getter_AddRefs(sourceURI)); + if (NS_SUCCEEDED(result)) loadInfo->SetReferrer(sourceURI); - } loadInfo.swap(*aLoadInfo); diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index ca91f7d207b0..c236852002bc 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -461,6 +461,10 @@ public: */ virtual nsresult DispatchSyncHashchange() = 0; + /** + * Instructs this window to synchronously dispatch a popState event. + */ + virtual nsresult DispatchSyncPopState() = 0; /** * Tell this window that there is an observer for orientation changes diff --git a/dom/interfaces/base/nsIDOMHistory.idl b/dom/interfaces/base/nsIDOMHistory.idl index 33956fe4b2dd..c78e31a624f3 100644 --- a/dom/interfaces/base/nsIDOMHistory.idl +++ b/dom/interfaces/base/nsIDOMHistory.idl @@ -39,7 +39,9 @@ #include "domstubs.idl" -[scriptable, uuid(896d1d20-b4c4-11d2-bd93-00805f8ae3f4)] +interface nsIVariant; + +[scriptable, uuid(208f2af7-9f2e-497c-8a53-9e7803280898)] interface nsIDOMHistory : nsISupports { readonly attribute long length; @@ -52,4 +54,10 @@ interface nsIDOMHistory : nsISupports void go([optional] in long aDelta); DOMString item(in unsigned long index); + void pushState(in nsIVariant aData, + in DOMString aTitle, + [optional] in DOMString aURL); + void replaceState(in nsIVariant aData, + in DOMString aTitle, + [optional] in DOMString aURL); }; diff --git a/dom/interfaces/events/Makefile.in b/dom/interfaces/events/Makefile.in index f7498ab1a73e..b584eb5afdb5 100644 --- a/dom/interfaces/events/Makefile.in +++ b/dom/interfaces/events/Makefile.in @@ -83,6 +83,7 @@ XPIDLSRCS = \ nsIDOMOrientationEvent.idl \ nsIDOMScrollAreaEvent.idl \ nsIDOMTransitionEvent.idl \ + nsIDOMPopStateEvent.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/interfaces/events/nsIDOMPopStateEvent.idl b/dom/interfaces/events/nsIDOMPopStateEvent.idl new file mode 100644 index 000000000000..dc7de0db7915 --- /dev/null +++ b/dom/interfaces/events/nsIDOMPopStateEvent.idl @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is the Mozilla Corporation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIDOMEvent.idl" + +interface nsIVariant; + +[scriptable, uuid(f3834fd5-0ef5-4ccd-a741-0b6685414342)] +interface nsIDOMPopStateEvent : nsIDOMEvent +{ + /** + * The state associated with this popstate event + */ + readonly attribute nsIVariant state; + + void initPopStateEvent(in DOMString typeArg, + in boolean canBubbleArg, + in boolean cancelableArg, + in nsIVariant stateArg); +}; diff --git a/dom/interfaces/json/nsIJSON.idl b/dom/interfaces/json/nsIJSON.idl index 940a9d1a2d76..7dddbeb13e2a 100644 --- a/dom/interfaces/json/nsIJSON.idl +++ b/dom/interfaces/json/nsIJSON.idl @@ -42,10 +42,18 @@ interface nsIInputStream; interface nsIOutputStream; interface nsIScriptGlobalObject; +%{ C++ +#include "jspubtd.h" +%} + + native JSVal(jsval); +[ptr] native JSValPtr(jsval); +[ptr] native JSContext(JSContext); + /** * Encode and decode JSON text. */ -[scriptable, uuid(45464c36-efde-4cb5-8e00-07480533ff35)] +[scriptable, uuid(6fcf09ee-87d0-42ec-a72a-8d60114e974f)] interface nsIJSON : nsISupports { AString encode(/* in JSObject value */); @@ -59,4 +67,9 @@ interface nsIJSON : nsISupports void /* JSObject */ decodeFromStream(in nsIInputStream stream, in long contentLength); + + [noscript] AString encodeFromJSVal(in JSValPtr value, in JSContext cx); + + // Make sure you GCroot the result of this function before using it. + [noscript] JSVal decodeToJSVal(in AString str, in JSContext cx); }; diff --git a/dom/locales/en-US/chrome/plugins.properties b/dom/locales/en-US/chrome/plugins.properties index 6edbde5366e2..b898932f2bb7 100644 --- a/dom/locales/en-US/chrome/plugins.properties +++ b/dom/locales/en-US/chrome/plugins.properties @@ -12,6 +12,5 @@ version_label=Version: mimetype_label=MIME Type description_label=Description suffixes_label=Suffixes -enabled_label=Enabled yes_label=Yes no_label=No diff --git a/dom/plugins/PluginModuleChild.cpp b/dom/plugins/PluginModuleChild.cpp index f332ae10a44e..79ee1d2ef2da 100644 --- a/dom/plugins/PluginModuleChild.cpp +++ b/dom/plugins/PluginModuleChild.cpp @@ -235,6 +235,10 @@ PluginModuleChild::InitGraphics() { // FIXME/cjones: is this the place for this? #if defined(MOZ_WIDGET_GTK2) + // Work around plugins that don't interact well with GDK + // client-side windows. + PR_SetEnv("GDK_NATIVE_WINDOWS=1"); + gtk_init(0, 0); // GtkPlug is a static class so will leak anyway but this ref makes sure. diff --git a/dom/plugins/PluginModuleParent.cpp b/dom/plugins/PluginModuleParent.cpp index b13f519aaecc..46e4c6915198 100644 --- a/dom/plugins/PluginModuleParent.cpp +++ b/dom/plugins/PluginModuleParent.cpp @@ -149,6 +149,8 @@ PluginModuleParent::WriteExtraDataForMinidump(nsIFile* dumpFile) pluginFile.substr(filePos).c_str()); //TODO: add plugin name and version: bug 539841 // (as PluginName, PluginVersion) + WriteExtraDataEntry(stream, "PluginName", ""); + WriteExtraDataEntry(stream, "PluginVersion", ""); stream->Close(); } diff --git a/dom/src/json/Makefile.in b/dom/src/json/Makefile.in index 92d9efde9409..611a727d1e01 100644 --- a/dom/src/json/Makefile.in +++ b/dom/src/json/Makefile.in @@ -51,6 +51,9 @@ CPPSRCS = \ nsJSON.cpp \ $(NULL) +EXPORTS = nsJSON.h \ + $(NULL) + FORCE_STATIC_LIB = 1 LOCAL_INCLUDES = \ diff --git a/dom/src/json/nsJSON.cpp b/dom/src/json/nsJSON.cpp index e5dd6b82e889..bac690e40caa 100644 --- a/dom/src/json/nsJSON.cpp +++ b/dom/src/json/nsJSON.cpp @@ -195,6 +195,27 @@ WriteCallback(const jschar *buf, uint32 len, void *data) return JS_TRUE; } +NS_IMETHODIMP +nsJSON::EncodeFromJSVal(jsval *value, JSContext *cx, nsAString &result) +{ + result.Truncate(); + + // Begin a new request + JSAutoRequest ar(cx); + + nsJSONWriter writer; + JSBool ok = JS_Stringify(cx, value, NULL, JSVAL_NULL, + WriteCallback, &writer); + if (!ok) { + return NS_ERROR_XPC_BAD_CONVERT_JS; + } + + NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED); + writer.FlushBuffer(); + result.Assign(writer.mOutputString); + return NS_OK; +} + nsresult nsJSON::EncodeInternal(nsJSONWriter *writer) { @@ -382,6 +403,30 @@ nsJSON::DecodeFromStream(nsIInputStream *aStream, PRInt32 aContentLength) return DecodeInternal(aStream, aContentLength, PR_TRUE); } +NS_IMETHODIMP +nsJSON::DecodeToJSVal(const nsAString &str, JSContext *cx, jsval *result) +{ + JSAutoRequest ar(cx); + + JSONParser *parser = JS_BeginJSONParse(cx, result); + NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED); + + JSBool ok = JS_ConsumeJSONText(cx, parser, + (jschar*)PromiseFlatString(str).get(), + (uint32)str.Length()); + + // Since we've called JS_BeginJSONParse, we have to call JS_FinishJSONParse, + // even if JS_ConsumeJSONText fails. But if either fails, we'll report an + // error. + ok = ok && JS_FinishJSONParse(cx, parser, JSVAL_NULL); + + if (!ok) { + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + nsresult nsJSON::DecodeInternal(nsIInputStream *aStream, PRInt32 aContentLength, diff --git a/dom/src/storage/nsDOMStorage.cpp b/dom/src/storage/nsDOMStorage.cpp index df35c0f41e1b..3ed4343967ae 100644 --- a/dom/src/storage/nsDOMStorage.cpp +++ b/dom/src/storage/nsDOMStorage.cpp @@ -550,8 +550,8 @@ NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult) nsDOMStorage::nsDOMStorage() : mUseDB(PR_FALSE) , mSessionOnly(PR_TRUE) - , mItemsCached(PR_FALSE) , mStorageType(nsPIDOMStorage::Unknown) + , mItemsCached(PR_FALSE) , mEventBroadcaster(nsnull) { mSecurityChecker = this; @@ -562,10 +562,10 @@ nsDOMStorage::nsDOMStorage() nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat) : mUseDB(PR_FALSE) // Any clone is not using the database - , mSessionOnly(PR_TRUE) - , mItemsCached(PR_FALSE) , mDomain(aThat.mDomain) + , mSessionOnly(PR_TRUE) , mStorageType(aThat.mStorageType) + , mItemsCached(PR_FALSE) #ifdef MOZ_STORAGE , mScopeDBKey(aThat.mScopeDBKey) #endif diff --git a/dom/tests/mochitest/whatwg/Makefile.in b/dom/tests/mochitest/whatwg/Makefile.in index 2f6984f4e8af..bb5d5e2433b3 100644 --- a/dom/tests/mochitest/whatwg/Makefile.in +++ b/dom/tests/mochitest/whatwg/Makefile.in @@ -77,6 +77,9 @@ _TEST_FILES = \ postMessage.jar \ postMessage.jar^headers^ \ test_bug477323.html \ + test_bug500328.html \ + file_bug500328_1.html \ + file_bug500328_2.html \ $(NULL) _CHROME_FILES = \ diff --git a/dom/tests/mochitest/whatwg/file_bug500328_1.html b/dom/tests/mochitest/whatwg/file_bug500328_1.html new file mode 100644 index 000000000000..f0ef793b53b0 --- /dev/null +++ b/dom/tests/mochitest/whatwg/file_bug500328_1.html @@ -0,0 +1,34 @@ + + + + +test 1 + + + + +Link Anchor1 +Self + + diff --git a/dom/tests/mochitest/whatwg/file_bug500328_2.html b/dom/tests/mochitest/whatwg/file_bug500328_2.html new file mode 100644 index 000000000000..3ce66493dde1 --- /dev/null +++ b/dom/tests/mochitest/whatwg/file_bug500328_2.html @@ -0,0 +1,17 @@ + + + + + + + +file_bug500328_2.html + + diff --git a/dom/tests/mochitest/whatwg/test_bug500328.html b/dom/tests/mochitest/whatwg/test_bug500328.html new file mode 100644 index 000000000000..95889febb385 --- /dev/null +++ b/dom/tests/mochitest/whatwg/test_bug500328.html @@ -0,0 +1,740 @@ + + + + + Test for Bug 500328 + + + + + + +Mozilla Bug 500328 +

+
+
+ + + link +
+
+
+
+ + diff --git a/gfx/src/nsColorNames.cpp b/gfx/src/nsColorNames.cpp deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/gfx/tests/DumpColors.cpp b/gfx/tests/DumpColors.cpp deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/intl/locale/src/mac/nsDateTimeFormatMac.cpp b/intl/locale/src/mac/nsDateTimeFormatMac.cpp index 201ec948d839..ed7d71e41695 100644 --- a/intl/locale/src/mac/nsDateTimeFormatMac.cpp +++ b/intl/locale/src/mac/nsDateTimeFormatMac.cpp @@ -135,9 +135,6 @@ nsresult nsDateTimeFormatMac::FormatTMTime(nsILocale* locale, return NS_OK; } - // set the default string, in case for API/conversion errors - CopyASCIItoUTF16(nsDependentCString(asctime(tmTime)), stringOut); - NS_ASSERTION(tmTime->tm_mon >= 0, "tm is not set correctly"); NS_ASSERTION(tmTime->tm_mday >= 1, "tm is not set correctly"); NS_ASSERTION(tmTime->tm_hour >= 0, "tm is not set correctly"); diff --git a/js/src/xpconnect/idl/nsIDispatchSupport.idl b/js/src/xpconnect/idl/nsIDispatchSupport.idl index 09662cfaf3a5..a0f6d397dca1 100644 --- a/js/src/xpconnect/idl/nsIDispatchSupport.idl +++ b/js/src/xpconnect/idl/nsIDispatchSupport.idl @@ -57,7 +57,6 @@ native COMVARIANT(VARIANT); [ptr] native COMVARIANTPtr(VARIANT); -native JSVal(jsval); [ptr] native JSContextPtr(JSContext); interface IDispatch; diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index 2c177f917e4c..382adc8d0c6f 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -59,11 +59,12 @@ /***************************************************************************/ +// NB: JSVal is declared in nsIVariant.idl + [ptr] native JSContextPtr(JSContext); [ptr] native JSClassPtr(JSClass); [ptr] native JSObjectPtr(JSObject); [ptr] native JSValPtr(jsval); - native JSVal(jsval); native JSEqualityOp(JSEqualityOp); native JSID(jsid); [ptr] native voidPtrPtr(void*); @@ -530,6 +531,12 @@ interface nsIXPConnect : nsISupports in nsIIDRef aIID, [iid_is(aIID),retval] out nsQIResult result); + /** + * Wraps the given JSVal in a nsIVariant and returns the new variant. + */ + nsIVariant + jSValToVariant(in JSContextPtr cx, in JSValPtr aJSVal); + /** * This only succeeds if the JSObject is a nsIXPConnectWrappedNative. * A new wrapper is *never* constructed. diff --git a/js/src/xpconnect/shell/xpcshell.cpp b/js/src/xpconnect/shell/xpcshell.cpp index 98f2dcdc5866..9bb3b80679c6 100644 --- a/js/src/xpconnect/shell/xpcshell.cpp +++ b/js/src/xpconnect/shell/xpcshell.cpp @@ -1358,14 +1358,6 @@ FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext, return NS_OK; } -/* [noscript] void checkConnect (in JSContextPtr aJSContext, in nsIURI aTargetURI, in string aClassName, in string aProperty); */ -NS_IMETHODIMP -FullTrustSecMan::CheckConnect(JSContext * aJSContext, nsIURI *aTargetURI, - const char *aClassName, const char *aProperty) -{ - return NS_OK; -} - /* [noscript] void checkLoadURIFromScript (in JSContextPtr cx, in nsIURI uri); */ NS_IMETHODIMP FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx, nsIURI *uri) diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 4737b3a4ec1b..c01a6cb86974 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -1051,7 +1051,7 @@ InitWebGLTypes(JSContext *aJSContext, JSObject *aGlobalJSObj) // Alias WebGLArrayBuffer -> ArrayBuffer if(!JS_GetProperty(aJSContext, aGlobalJSObj, "ArrayBuffer", &v) || !JS_DefineProperty(aJSContext, aGlobalJSObj, "WebGLArrayBuffer", v, - NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE)) + NULL, NULL, JSPROP_PERMANENT)) return PR_FALSE; const int webglTypes[] = { @@ -1080,7 +1080,7 @@ InitWebGLTypes(JSContext *aJSContext, JSObject *aGlobalJSObj) { 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)) + NULL, NULL, JSPROP_PERMANENT)) return PR_FALSE; } @@ -1370,6 +1370,25 @@ nsXPConnect::WrapJS(JSContext * aJSContext, return NS_OK; } +NS_IMETHODIMP +nsXPConnect::JSValToVariant(JSContext *cx, + jsval *aJSVal, + nsIVariant ** aResult) +{ + NS_PRECONDITION(aJSVal, "bad param"); + NS_PRECONDITION(aResult, "bad param"); + *aResult = nsnull; + + XPCCallContext ccx(NATIVE_CALLER, cx); + if(!ccx.IsValid()) + return NS_ERROR_FAILURE; + + *aResult = XPCVariant::newVariant(ccx, *aJSVal); + NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); + + return NS_OK; +} + /* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */ NS_IMETHODIMP nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter, diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index f3cdc8d8b6e8..5924460d6fb8 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -4198,6 +4198,10 @@ public: static XPCVariant* newVariant(XPCCallContext& ccx, jsval aJSVal); + /** + * nsIVariant exposes a GetAsJSVal() method, which also returns mJSVal. + * But if you can, you should call this one, since it can be inlined. + */ jsval GetJSVal() const {return mJSVal;} XPCVariant(XPCCallContext& ccx, jsval aJSVal); diff --git a/js/src/xpconnect/src/xpcvariant.cpp b/js/src/xpconnect/src/xpcvariant.cpp index 6eeef76b618c..c8f42aa596a8 100644 --- a/js/src/xpconnect/src/xpcvariant.cpp +++ b/js/src/xpconnect/src/xpcvariant.cpp @@ -390,6 +390,14 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx) NS_SUCCEEDED(nsVariant::SetFromInterface(&mData, iid, wrapper)); } +NS_IMETHODIMP +XPCVariant::GetAsJSVal(jsval* result) +{ + NS_PRECONDITION(result, "null result arg."); + *result = GetJSVal(); + return NS_OK; +} + // static JSBool XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx, @@ -399,43 +407,42 @@ XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx, { // Get the type early because we might need to spoof it below. PRUint16 type; - if(NS_FAILED(variant->GetDataType(&type))) + if (NS_FAILED(variant->GetDataType(&type))) return JS_FALSE; - nsCOMPtr xpcvariant = do_QueryInterface(variant); - if(xpcvariant) - { - jsval realVal = xpcvariant->GetJSVal(); - if(JSVAL_IS_PRIMITIVE(realVal) || - type == nsIDataType::VTYPE_ARRAY || - type == nsIDataType::VTYPE_EMPTY_ARRAY || - type == nsIDataType::VTYPE_ID) - { - // Not a JSObject (or is a JSArray or is a JSObject representing - // an nsID),. - // So, just pass through the underlying data. - *pJSVal = realVal; - return JS_TRUE; - } + jsval realVal; + nsresult rv = variant->GetAsJSVal(&realVal); - if(xpcvariant->mReturnRawObject) - { - NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE || - type == nsIDataType::VTYPE_INTERFACE_IS, - "Weird variant"); - *pJSVal = realVal; - return JS_TRUE; - } + if(NS_SUCCEEDED(rv) && + (JSVAL_IS_PRIMITIVE(realVal) || + type == nsIDataType::VTYPE_ARRAY || + type == nsIDataType::VTYPE_EMPTY_ARRAY || + type == nsIDataType::VTYPE_ID)) + { + // It's not a JSObject (or it's a JSArray or a JSObject representing an + // nsID). Just pass through the underlying data. + *pJSVal = realVal; + return JS_TRUE; + } + + nsCOMPtr xpcvariant = do_QueryInterface(variant); + if(xpcvariant && xpcvariant->mReturnRawObject) + { + NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE || + type == nsIDataType::VTYPE_INTERFACE_IS, + "Weird variant"); + *pJSVal = realVal; + return JS_TRUE; // else, it's an object and we really need to double wrap it if we've // already decided that its 'natural' type is as some sort of interface. - + // We just fall through to the code below and let it do what it does. } // The nsIVariant is not a XPCVariant (or we act like it isn't). // So we extract the data and do the Right Thing. - + // We ASSUME that the variant implementation can do these conversions... nsXPTCVariant xpctvar; diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index c2d205891e80..98d0e9161fd0 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -998,7 +998,7 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) nsCOMPtr shell = mPresShell; shell->FlushPendingNotifications(Flush_Layout); } - + nsresult rv = NS_OK; NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); @@ -1038,8 +1038,6 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) // if navigator.xul's load is complete, the main nav window is visible // mark that point. - //printf("DEBUG: getting uri from document (%p)\n", mDocument.get()); - nsIURI *uri = mDocument ? mDocument->GetDocumentURI() : nsnull; if (uri) { @@ -1097,6 +1095,10 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) } #endif + if (!mStopped) { + window->DispatchSyncPopState(); + } + return rv; } diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index ce16b7f4e586..a4e42828098a 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1297,7 +1297,7 @@ AddItemsToRegion(nsDisplayListBuilder* aBuilder, nsDisplayList* aList, nsRegion clippedOutDestination; clippedOutDestination.Sub(aUpdateRect, clip); #ifdef DEBUG - PrintAddedRegion("Adding region for clipped out source frame %p", + PrintAddedRegion("Adding region for clipped out destination frame %p", clipFrame, clippedOutDestination); #endif aRegion->Or(*aRegion, clippedOutDestination); diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index f1fd0c9c7271..6f332401727d 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -933,7 +933,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, pfd->SetFlag(PFD_ISLETTERFRAME, PR_TRUE); } if (pfd->mSpan) { - isEmpty = !pfd->mSpan->mHasNonemptyContent && pfd->mFrame->IsSelfEmpty(); + isEmpty = !pfd->mSpan->mHasNonemptyContent; } else { isEmpty = pfd->mFrame->IsEmpty(); } diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index 0102545b068c..8eb431e67e63 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -2179,6 +2179,8 @@ DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner, PRBool aDelayedStop) if (DoDelayedStop(aInstanceOwner, aDelayedStop)) return; + + inst->Stop(); nsCOMPtr pluginHost = do_GetService(MOZ_PLUGIN_HOST_CONTRACTID); if (pluginHost) diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 8ab8ed9c32f5..9f1095b14bd8 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -6126,7 +6126,7 @@ nsTextFrame::Reflow(nsPresContext* aPresContext, // Restrict preformatted text to the nearest newline PRInt32 newLineOffset = -1; // this will be -1 or a content offset // Pointer to the nsGkAtoms::newline set on this frame's element - NewlineProperty* cachedNewlineOffset; + NewlineProperty* cachedNewlineOffset = nsnull; if (textStyle->NewlineIsSignificant()) { cachedNewlineOffset = static_cast(mContent->GetProperty(nsGkAtoms::newline)); diff --git a/layout/generic/test/plugin_clipping_helper2.xhtml b/layout/generic/test/plugin_clipping_helper2.xhtml index 559dcbb3f477..e22163d9d3a4 100644 --- a/layout/generic/test/plugin_clipping_helper2.xhtml +++ b/layout/generic/test/plugin_clipping_helper2.xhtml @@ -44,11 +44,7 @@ function runTests() { checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 150], [150, 50, 200, 150], [0, 150, 200, 200]]); scroll.scrollTop = 150; - 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). @@ -56,24 +52,30 @@ function runTests() { } function part2() { - checkClipRegion("p2", [[0, 0, 200, 100], [0, 100, 50, 200], [150, 100, 200, 200]]); + checkClipRegion("p2", [[0, 0, 200, 50], [0, 50, 50, 200], [150, 50, 200, 200]]); - sbox.style.background = ""; + zbox.style.zIndex = -1; - flush(); setTimeout(part3, 1000); } function part3() { - checkClipRegion("p2", [[0, 0, 200, 200]]); - - p1.style.zIndex = 1; + checkClipRegion("p2", [[0, 0, 200, 100], [0, 100, 50, 200], [150, 100, 200, 200]]); + + sbox.style.background = ""; - flush(); setTimeout(part4, 1000); } function part4() { + checkClipRegion("p2", [[0, 0, 200, 200]]); + + p1.style.zIndex = 1; + + setTimeout(part5, 1000); +} + +function part5() { checkClipRegion("p1", [[0, 0, 200, 200]]); checkClipRegion("p2", [[0, 100, 200, 200]]); @@ -83,7 +85,6 @@ function part4() { zbox.style.top = "50.3px;" d2.style.top = "100.3px"; - flush(); setTimeout(done, 1000); } @@ -94,14 +95,6 @@ function done() { window.close(); } -function flush() { - // This function is for X11 to flush the Xlib request queue. It takes - // advantage of the current scrolling implementation, which will do this for - // us. Beware though, it does not wait for the X server to process the - // events. - ++scroll.scrollTop; - --scroll.scrollTop; -} ]]> diff --git a/layout/reftests/bugs/538935-1-ref.html b/layout/reftests/bugs/538935-1-ref.html new file mode 100644 index 000000000000..b301c4368520 --- /dev/null +++ b/layout/reftests/bugs/538935-1-ref.html @@ -0,0 +1,16 @@ + + + +
Hello
+
Hello
+
Hello
+
Hello
+
Hello
+ +
Hello
+
Hello
+
Hello
+
Hello
+
Hello
+ + diff --git a/layout/reftests/bugs/538935-1.html b/layout/reftests/bugs/538935-1.html new file mode 100644 index 000000000000..2cab32382d41 --- /dev/null +++ b/layout/reftests/bugs/538935-1.html @@ -0,0 +1,16 @@ + + + +
Hello
+
Hello
+
Hello
+
Hello
+
Hello
+ +
Hello
+
Hello
+
Hello
+
Hello
+
Hello
+ + diff --git a/layout/reftests/bugs/542620-1-ref.html b/layout/reftests/bugs/542620-1-ref.html new file mode 100644 index 000000000000..c01b1761753a --- /dev/null +++ b/layout/reftests/bugs/542620-1-ref.html @@ -0,0 +1,11 @@ + + + + + +
+ + +
+ + diff --git a/layout/reftests/bugs/542620-1.html b/layout/reftests/bugs/542620-1.html new file mode 100644 index 000000000000..cd6677b44a75 --- /dev/null +++ b/layout/reftests/bugs/542620-1.html @@ -0,0 +1,13 @@ + + + + + + +
+ + + +
+ + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index dafca24fd726..44d14ca51fe7 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1379,5 +1379,7 @@ fails HTTP(..) == 518172-2b.html 518172-b-ref.html # bug 518172 == 537507-1.xul 537507-1-ref.xul == 537507-2.html 537507-2-ref.html == 537471-1.html 537471-1-ref.html +== 538935-1.html 538935-1-ref.html == 539226-1.html about:blank +== 542620-1.html 542620-1-ref.html == 541382-1.html 541382-1-ref.html diff --git a/layout/reftests/mathml/table-width-1-ref.xhtml b/layout/reftests/mathml/table-width-1-ref.xhtml index c1e30cb930c1..7864d23fa18c 100644 --- a/layout/reftests/mathml/table-width-1-ref.xhtml +++ b/layout/reftests/mathml/table-width-1-ref.xhtml @@ -82,5 +82,17 @@ + + +
+ + + + 1473903823894702 + 2808472638402743 + + + +
diff --git a/layout/reftests/mathml/table-width-1.xhtml b/layout/reftests/mathml/table-width-1.xhtml index 59caeaa3929f..25098cbf6049 100644 --- a/layout/reftests/mathml/table-width-1.xhtml +++ b/layout/reftests/mathml/table-width-1.xhtml @@ -77,5 +77,15 @@ + + +
+ + + 1473903823894702 + 2808472638402743 + + +
diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 323d0c95ade1..53e18417b0e4 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1273,28 +1273,23 @@ IsFrameAllowedInTable(nsIAtom* aType) #endif static PRBool -AnyTablePartHasBorderOrBackground(nsIFrame* aFrame) +AnyTablePartHasBorderOrBackground(const nsFrameList& aFrames) { - NS_ASSERTION(IsFrameAllowedInTable(aFrame->GetType()), "unexpected frame type"); + for (nsFrameList::Enumerator e(aFrames); !e.AtEnd(); e.Next()) { + nsIFrame* f = e.get(); + NS_ASSERTION(IsFrameAllowedInTable(f->GetType()), "unexpected frame type"); - nsIScrollableFrame *scrollFrame = do_QueryFrame(aFrame); - if (scrollFrame) { - return AnyTablePartHasBorderOrBackground(scrollFrame->GetScrolledFrame()); - } + if (f->GetStyleVisibility()->IsVisible() && + (!f->GetStyleBackground()->IsTransparent() || + f->GetStyleDisplay()->mAppearance || + f->HasBorder())) + return PR_TRUE; - if (aFrame->GetStyleVisibility()->IsVisible() && - (!aFrame->GetStyleBackground()->IsTransparent() || - aFrame->GetStyleDisplay()->mAppearance || - aFrame->HasBorder())) - return PR_TRUE; + nsTableCellFrame *cellFrame = do_QueryFrame(f); + if (cellFrame) + continue; - nsTableCellFrame *cellFrame = do_QueryFrame(aFrame); - if (cellFrame) - return PR_FALSE; - - nsFrameList children = aFrame->GetChildList(nsnull); - for (nsIFrame* f = children.FirstChild(); f; f = f->GetNextSibling()) { - if (AnyTablePartHasBorderOrBackground(f)) + if (AnyTablePartHasBorderOrBackground(f->GetChildList(nsnull))) return PR_TRUE; } @@ -1331,7 +1326,8 @@ nsTableFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // Specific visibility decisions are delegated to the table background // painter, which handles borders and backgrounds for the table. if (aBuilder->IsForEventDelivery() || - AnyTablePartHasBorderOrBackground(this)) { + AnyTablePartHasBorderOrBackground(nsFrameList(this, GetNextSibling())) || + AnyTablePartHasBorderOrBackground(mColGroups)) { item = new (aBuilder) nsDisplayTableBorderBackground(this); nsresult rv = aLists.BorderBackground()->AppendNewToTop(item); NS_ENSURE_SUCCESS(rv, rv); @@ -3483,7 +3479,7 @@ nsTableFrame::DumpRowGroup(nsIFrame* aKidFrame) if (cellFrame) { PRInt32 colIndex; cellFrame->GetColIndex(colIndex); - printf("cell(%d)=%p ", colIndex, childFrame); + printf("cell(%d)=%p ", colIndex, static_cast(childFrame)); } childFrame = childFrame->GetNextSibling(); } diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index de3ea8b68fbc..5137c7e1ac52 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -2838,6 +2838,12 @@ pref("html5.flushtimer.continuedelay", 150); // Time in milliseconds between timer firings once the timer has starting // firing. pref("html5.flushtimer.interval", 100); + +// Push/Pop/Replace State prefs +pref("browser.history.allowPushState", true); +pref("browser.history.allowReplaceState", true); +pref("browser.history.allowPopState", true); +pref("browser.history.maxStateObjectSize", 655360); // Initial max length for number of tree ops in on flush. pref("html5.opqueue.initiallengthlimit", 200); // Maximum time in milliseconds to spend flushing the tree op queue when not forced to completion diff --git a/modules/plugin/base/src/nsNPAPIPlugin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp index 150a40991524..1133a769467e 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.cpp +++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp @@ -224,7 +224,6 @@ nsNPAPIPlugin::nsNPAPIPlugin(NPPluginFuncs* callbacks, mPluginFuncs.size = sizeof(mPluginFuncs); mLibrary = nsnull; - mIsDefaultPlugin = PR_FALSE; #if defined(XP_WIN) || defined(XP_OS2) // On Windows and OS/2 we need to keep a direct reference to @@ -308,18 +307,6 @@ nsNPAPIPlugin::PluginCrashed() } #endif -void -nsNPAPIPlugin::SetIsDefaultPlugin() -{ - mIsDefaultPlugin = PR_TRUE; -} - -PRBool -nsNPAPIPlugin::IsDefaultPlugin() -{ - return mIsDefaultPlugin; -} - namespace { #ifdef MOZ_IPC @@ -624,7 +611,8 @@ nsNPAPIPlugin::CreatePluginInstance(nsIPluginInstance **aResult) *aResult = NULL; - nsRefPtr inst = new nsNPAPIPluginInstance(this, &mPluginFuncs, mLibrary); + nsRefPtr inst = + new nsNPAPIPluginInstance(&mPluginFuncs, mLibrary); if (!inst) return NS_ERROR_OUT_OF_MEMORY; @@ -2128,7 +2116,7 @@ _getvalue(NPP npp, NPNVariable variable, void *result) case NPNVPluginElementNPObject: { *(NPObject **)result = _getpluginelement(npp); - return NPERR_NO_ERROR; + return *(NPObject **)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR; } case NPNVSupportsWindowless: { diff --git a/modules/plugin/base/src/nsNPAPIPlugin.h b/modules/plugin/base/src/nsNPAPIPlugin.h index e74bf289834c..9671cbd7fd36 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.h +++ b/modules/plugin/base/src/nsNPAPIPlugin.h @@ -97,9 +97,6 @@ public: void PluginCrashed(); #endif - void SetIsDefaultPlugin(); - PRBool IsDefaultPlugin(); - protected: // Ensures that the static browser functions are properly initialized static void CheckClassInitialized(); @@ -112,8 +109,6 @@ protected: // plugin callbacks for each plugin. NPPluginFuncs mPluginFuncs; PluginLibrary* mLibrary; - - PRBool mIsDefaultPlugin; }; namespace mozilla { diff --git a/modules/plugin/base/src/nsNPAPIPluginInstance.cpp b/modules/plugin/base/src/nsNPAPIPluginInstance.cpp index 54fe31ce7d29..32cfbf86ba11 100644 --- a/modules/plugin/base/src/nsNPAPIPluginInstance.cpp +++ b/modules/plugin/base/src/nsNPAPIPluginInstance.cpp @@ -877,8 +877,7 @@ nsInstanceStream::~nsInstanceStream() NS_IMPL_ISUPPORTS1(nsNPAPIPluginInstance, nsIPluginInstance) -nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin, - NPPluginFuncs* callbacks, +nsNPAPIPluginInstance::nsNPAPIPluginInstance(NPPluginFuncs* callbacks, PluginLibrary* aLibrary) : mCallbacks(callbacks), #ifdef XP_MACOSX @@ -899,11 +898,9 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin, mStreams(nsnull), mMIMEType(nsnull), mOwner(nsnull), - mCurrentPluginEvent(nsnull), - mPlugin(plugin) + mCurrentPluginEvent(nsnull) { - NS_ASSERTION(mCallbacks != nsnull, "null callbacks"); - NS_ASSERTION(mPlugin != nsnull, "null plugin"); + NS_ASSERTION(mCallbacks != NULL, "null callbacks"); // Initialize the NPP structure. @@ -1794,30 +1791,6 @@ nsNPAPIPluginInstance::ConvertPoint(double sourceX, double sourceY, NPCoordinate return PR_FALSE; } -nsNPAPIPlugin* -nsNPAPIPluginInstance::Plugin() -{ - return mPlugin; -} - -void -nsNPAPIPluginInstance::SetURI(nsIURI* uri) -{ - mURI = uri; -} - -nsIURI* -nsNPAPIPluginInstance::GetURI() -{ - return mURI.get(); -} - -nsTArray< nsRefPtr >* -nsNPAPIPluginInstance::StreamListeners() -{ - return &mStreamListeners; -} - nsresult nsNPAPIPluginInstance::GetDOMElement(nsIDOMElement* *result) { diff --git a/modules/plugin/base/src/nsNPAPIPluginInstance.h b/modules/plugin/base/src/nsNPAPIPluginInstance.h index ebafb6d77b2f..0c5858610a27 100644 --- a/modules/plugin/base/src/nsNPAPIPluginInstance.h +++ b/modules/plugin/base/src/nsNPAPIPluginInstance.h @@ -49,9 +49,6 @@ #include "nsIPluginInstanceOwner.h" #include "nsITimer.h" #include "mozilla/TimeStamp.h" -#include "nsPluginTags.h" -#include "nsIStreamListener.h" -#include "nsIURI.h" #include "npfunctions.h" #include "mozilla/PluginLibrary.h" @@ -109,7 +106,7 @@ public: PRBool aCallNotify, const char * aURL); - nsNPAPIPluginInstance(nsNPAPIPlugin* plugin, NPPluginFuncs* callbacks, PluginLibrary* aLibrary); + nsNPAPIPluginInstance(NPPluginFuncs* callbacks, PluginLibrary* aLibrary); // Use Release() to destroy this virtual ~nsNPAPIPluginInstance(); @@ -134,11 +131,6 @@ public: void UnscheduleTimer(uint32_t timerID); NPError PopUpContextMenu(NPMenu* menu); NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); - - nsNPAPIPlugin* Plugin(); - void SetURI(nsIURI* uri); - nsIURI* GetURI(); - nsTArray< nsRefPtr > *StreamListeners(); protected: nsresult InitializePlugin(); @@ -194,10 +186,6 @@ private: // Timestamp for the last time this plugin was stopped. // This is only valid when the plugin is actually stopped! mozilla::TimeStamp mStopTime; - - nsNPAPIPlugin* mPlugin; - nsCOMPtr mURI; - nsTArray< nsRefPtr > mStreamListeners; }; #endif // nsNPAPIPluginInstance_h_ diff --git a/modules/plugin/base/src/nsPluginHost.cpp b/modules/plugin/base/src/nsPluginHost.cpp index 442deda9743c..73180445e29a 100644 --- a/modules/plugin/base/src/nsPluginHost.cpp +++ b/modules/plugin/base/src/nsPluginHost.cpp @@ -1008,25 +1008,29 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel) PRBool useExistingCacheFile = PR_FALSE; nsRefPtr pluginHost = dont_AddRef(nsPluginHost::GetInst()); - nsTArray< nsRefPtr > *instances = pluginHost->InstanceArray(); - for (PRUint32 i = 0; i < instances->Length(); i++) { - nsNPAPIPluginInstance *instance = (*instances)[i]; - nsTArray< nsRefPtr > *streamListeners = instance->StreamListeners(); - // most recent streams are at the end of list - PRInt32 cnt = streamListeners->Length(); - while (--cnt >= 0) { - nsPluginStreamListenerPeer *lp = static_cast(streamListeners->ElementAt(cnt).get()); - if (lp && lp->mLocalCachedFile && lp->mPluginStreamInfo) { - useExistingCacheFile = lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo); - if (useExistingCacheFile) { - mLocalCachedFile = lp->mLocalCachedFile; - NS_ADDREF(mLocalCachedFile); - break; + nsTArray< nsAutoPtr > *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(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); } } + if (useExistingCacheFile) + break; } - if (useExistingCacheFile) - break; } if (!useExistingCacheFile) { @@ -1077,8 +1081,16 @@ 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 - nsNPAPIPluginInstance* instance = static_cast(mInstance); - instance->StreamListeners()->AppendElement(static_cast(this)); + 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((static_cast(this))); + instanceTag->mStreams->AppendElement(supports); + } return rv; } @@ -1761,8 +1773,8 @@ PRBool nsPluginHost::IsRunningPlugin(nsPluginTag * plugin) return PR_FALSE; for (int i = 0; i < plugin->mVariants; i++) { - nsNPAPIPluginInstance *instance = FindInstance(plugin->mMimeTypeArray[i]); - if (instance && instance->IsRunning()) + nsPluginInstanceTag *instanceTag = FindInstanceTag(plugin->mMimeTypeArray[i]); + if (instanceTag && instanceTag->mInstance->IsRunning()) return PR_TRUE; } @@ -1773,7 +1785,7 @@ nsresult nsPluginHost::ReloadPlugins(PRBool reloadPages) { PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n", - reloadPages, mInstances.Length())); + reloadPages, mInstanceTags.Length())); nsresult rv = NS_OK; @@ -1854,7 +1866,7 @@ nsresult nsPluginHost::ReloadPlugins(PRBool reloadPages) PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::ReloadPlugins End active_instance_count=%d\n", - mInstances.Length())); + mInstanceTags.Length())); return rv; } @@ -2221,8 +2233,8 @@ void nsPluginHost::UnloadUnusedLibraries() void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag) { PRBool hasInstance = PR_FALSE; - for (PRUint32 i = 0; i < mInstances.Length(); i++) { - if (TagForPlugin(mInstances[i]->Plugin()) == aPluginTag) { + for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) { + if (mInstanceTags[i]->mPluginTag == aPluginTag) { hasInstance = PR_TRUE; break; } @@ -2569,7 +2581,7 @@ NS_IMETHODIMP nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType, } nsPluginTag* -nsPluginHost::TagForPlugin(nsNPAPIPlugin* aPlugin) +nsPluginHost::FindTagForPlugin(nsIPlugin* aPlugin) { nsPluginTag* pluginTag; for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) { @@ -2589,11 +2601,13 @@ nsresult nsPluginHost::FindStoppedPluginForURL(nsIURI* aURL, aURL->GetAsciiSpec(url); - nsNPAPIPluginInstance *instance = FindStoppedInstance(url.get()); - if (instance && !instance->IsRunning()) { + nsPluginInstanceTag *instanceTag = FindStoppedInstanceTag(url.get()); + + if (instanceTag && !instanceTag->mInstance->IsRunning()) { NPWindow* window = nsnull; aOwner->GetWindow(window); + nsIPluginInstance* instance = static_cast(instanceTag->mInstance); aOwner->SetInstance(instance); instance->SetOwner(aOwner); @@ -2611,6 +2625,34 @@ nsresult nsPluginHost::FindStoppedPluginForURL(nsIURI* aURL, return NS_ERROR_FAILURE; } +nsresult nsPluginHost::AddInstanceToActiveList(nsCOMPtr aPlugin, + nsIPluginInstance* aInstance, + nsIURI* aURL, + PRBool aDefaultPlugin) +{ + nsCAutoString url; + // It's OK to not have a URL here, as is the case with the dummy + // Java plugin. In that case simply use an empty string... + if (aURL) + aURL->GetSpec(url); + + // Let's find the corresponding plugin tag by matching nsIPlugin pointer. + // It is going to be used later when we decide whether or not we should delay + // unloading NPAPI dll from memory. + nsPluginTag * pluginTag = nsnull; + if (aPlugin) { + pluginTag = FindTagForPlugin(aPlugin); + NS_ASSERTION(pluginTag, "Plugin tag not found"); + } + + nsPluginInstanceTag *instanceTag = new nsPluginInstanceTag(pluginTag, aInstance, url.get(), aDefaultPlugin); + if (!instanceTag) + return NS_ERROR_OUT_OF_MEMORY; + + mInstanceTags.AppendElement(instanceTag); + return NS_OK; +} + NS_IMETHODIMP nsPluginHost::SetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner) @@ -2730,8 +2772,6 @@ nsPluginHost::TrySetUpPluginInstance(const char *aMimeType, if (NS_FAILED(result)) return result; - static_cast(instance.get())->SetURI(aURL); - // it is adreffed here aOwner->SetInstance(instance); @@ -2744,7 +2784,8 @@ nsPluginHost::TrySetUpPluginInstance(const char *aMimeType, return result; } - mInstances.AppendElement(static_cast(instance.get())); + // instance and peer will be addreffed here + result = AddInstanceToActiveList(plugin, instance, aURL, PR_FALSE); #ifdef PLUGIN_LOGGING nsCAutoString urlSpec2; @@ -2786,9 +2827,6 @@ nsPluginHost::SetUpDefaultPluginInstance(const char *aMimeType, if (NS_FAILED(result)) return result; - static_cast(plugin.get())->SetIsDefaultPlugin(); - static_cast(instance.get())->SetURI(aURL); - // it is adreffed here aOwner->SetInstance(instance); @@ -2812,7 +2850,7 @@ nsPluginHost::SetUpDefaultPluginInstance(const char *aMimeType, } // instance will be addreffed here - mInstances.AppendElement(static_cast(instance.get())); + result = AddInstanceToActiveList(plugin, instance, aURL, PR_TRUE); return result; } @@ -4503,64 +4541,65 @@ nsPluginHost::StopPluginInstance(nsIPluginInstance* aInstance) aInstance->Stop(); - nsNPAPIPluginInstance* instance = static_cast(aInstance); - - // if the plugin does not want to be 'cached' just remove it - PRBool doCache = PR_TRUE; - aInstance->ShouldCache(&doCache); - if (doCache) { - // try to get the max cached plugins from a pref or use default - PRUint32 cachedPluginLimit; - nsresult rv = NS_ERROR_FAILURE; - if (mPrefService) - rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&cachedPluginLimit); - if (NS_FAILED(rv)) - cachedPluginLimit = DEFAULT_NUMBER_OF_STOPPED_PLUGINS; - - if (StoppedInstanceCount() >= cachedPluginLimit) { - nsNPAPIPluginInstance *oldestInstance = FindOldestStoppedInstance(); - if (oldestInstance) { - nsPluginTag* pluginTag = TagForPlugin(oldestInstance->Plugin()); - mInstances.RemoveElement(oldestInstance); - OnPluginInstanceDestroyed(pluginTag); + 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) { + // try to get the max cached plugins from a pref or use default + PRUint32 cachedPluginLimit; + nsresult rv = NS_ERROR_FAILURE; + if (mPrefService) + rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&cachedPluginLimit); + if (NS_FAILED(rv)) + cachedPluginLimit = DEFAULT_NUMBER_OF_STOPPED_PLUGINS; + + if (StoppedInstanceTagCount() >= cachedPluginLimit) { + nsPluginInstanceTag * oldestInstanceTag = FindOldestStoppedInstanceTag(); + if (oldestInstanceTag) { + nsPluginTag* pluginTag = oldestInstanceTag->mPluginTag; + mInstanceTags.RemoveElement(oldestInstanceTag); + OnPluginInstanceDestroyed(pluginTag); + } } + } else { + nsPluginTag* pluginTag = instanceTag->mPluginTag; + mInstanceTags.RemoveElement(instanceTag); + OnPluginInstanceDestroyed(pluginTag); } - } else { - nsPluginTag* pluginTag = TagForPlugin(instance->Plugin()); - mInstances.RemoveElement(instance); - OnPluginInstanceDestroyed(pluginTag); } return NS_OK; } -nsNPAPIPluginInstance* -nsPluginHost::FindOldestStoppedInstance() +nsPluginInstanceTag* +nsPluginHost::FindOldestStoppedInstanceTag() { - nsNPAPIPluginInstance *oldestInstance = nsnull; + nsPluginInstanceTag *oldestInstanceTag = nsnull; TimeStamp oldestTime = TimeStamp::Now(); - for (PRUint32 i = 0; i < mInstances.Length(); i++) { - nsNPAPIPluginInstance *instance = mInstances[i]; - if (instance->IsRunning()) + for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) { + nsPluginInstanceTag *instanceTag = mInstanceTags[i]; + if (instanceTag->mInstance->IsRunning()) continue; - TimeStamp time = instance->LastStopTime(); + TimeStamp time = instanceTag->mInstance->LastStopTime(); if (time < oldestTime) { oldestTime = time; - oldestInstance = instance; + oldestInstanceTag = instanceTag; } } - return oldestInstance; + return oldestInstanceTag; } PRUint32 -nsPluginHost::StoppedInstanceCount() +nsPluginHost::StoppedInstanceTagCount() { PRUint32 stoppedCount = 0; - for (PRUint32 i = 0; i < mInstances.Length(); i++) { - nsNPAPIPluginInstance *instance = mInstances[i]; - if (!instance->IsRunning()) + for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) { + nsPluginInstanceTag *instanceTag = mInstanceTags[i]; + if (!instanceTag->mInstance->IsRunning()) stoppedCount++; } return stoppedCount; @@ -4648,8 +4687,12 @@ nsresult nsPluginHost::NewFullPagePluginStream(nsIStreamListener *&aStreamListen NS_ADDREF(listener); // add peer to list of stream peers for this instance - nsNPAPIPluginInstance *instance = static_cast(aInstance); - instance->StreamListeners()->AppendElement(aStreamListener); + nsPluginInstanceTag * p = FindInstanceTag(aInstance); + if (p) { + if (!p->mStreams && (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(p->mStreams))))) + return rv; + p->mStreams->AppendElement(aStreamListener); + } return rv; } @@ -4666,8 +4709,9 @@ 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 (PRUint32 i = 0; i < mInstances.Length(); i++) { - mInstances[i]->PrivateModeStateChanged(); + for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) { + nsNPAPIPluginInstance* pi = static_cast(mInstanceTags[i]->mInstance); + pi->PrivateModeStateChanged(); } } return NS_OK; @@ -4728,12 +4772,16 @@ nsPluginHost::HandleBadPlugin(PRLibrary* aLibrary, nsIPluginInstance *aInstance) // add plugin name to the message nsCString pluginname; - nsNPAPIPluginInstance *instance = static_cast(aInstance); - nsPluginTag *tag = TagForPlugin(instance->Plugin()); - if (!tag->mName.IsEmpty()) - pluginname = tag->mName; - else - pluginname = tag->mFileName; + nsPluginInstanceTag * p = FindInstanceTag(aInstance); + if (p) { + nsPluginTag * tag = p->mPluginTag; + if (tag) { + if (!tag->mName.IsEmpty()) + pluginname = tag->mName; + else + pluginname = tag->mFileName; + } + } NS_ConvertUTF8toUTF16 msg(pluginname); msg.AppendLiteral("\n\n"); @@ -5050,11 +5098,11 @@ NS_IMETHODIMP nsPluginHost::GetPluginName(nsIPluginInstance *aPluginInstance, const char** aPluginName) { - nsNPAPIPluginInstance *instance = static_cast(aPluginInstance); - if (!instance) + nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance); + if (!instanceTag || !instanceTag->mPluginTag) return NS_ERROR_FAILURE; - *aPluginName = TagForPlugin(instance->Plugin())->mName.get(); + *aPluginName = instanceTag->mPluginTag->mName.get(); return NS_OK; } @@ -5066,10 +5114,12 @@ nsPluginHost::GetPluginTagForInstance(nsIPluginInstance *aPluginInstance, NS_ENSURE_ARG_POINTER(aPluginInstance); NS_ENSURE_ARG_POINTER(aPluginTag); - nsNPAPIPluginInstance *instance = static_cast(aPluginInstance); - *aPluginTag = TagForPlugin(instance->Plugin()); - NS_ADDREF(*aPluginTag); + nsPluginInstanceTag *instanceTag = FindInstanceTag(aPluginInstance); + NS_ENSURE_TRUE(instanceTag && instanceTag->mPluginTag, NS_ERROR_FAILURE); + + *aPluginTag = instanceTag->mPluginTag; + NS_ADDREF(*aPluginTag); return NS_OK; } @@ -5155,7 +5205,7 @@ NS_IMETHODIMP nsPluginHost::Notify(nsITimer* timer) void nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin) { - nsPluginTag* pluginTag = TagForPlugin(aPlugin); + nsPluginTag* pluginTag = FindTagForPlugin(aPlugin); if (!pluginTag) { NS_WARNING("nsPluginTag not found in nsPluginHost::PluginCrashed"); return; @@ -5163,21 +5213,21 @@ nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin) // Invalidate each nsPluginInstanceTag for the crashed plugin - for (PRUint32 i = mInstances.Length(); i > 0; i--) { - nsNPAPIPluginInstance* instance = mInstances[i - 1]; - if (TagForPlugin(instance->Plugin()) == pluginTag) { + 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 domElement; - instance->GetDOMElement(getter_AddRefs(domElement)); + instanceTag->mInstance->GetDOMElement(getter_AddRefs(domElement)); nsCOMPtr objectContent(do_QueryInterface(domElement)); if (objectContent) { objectContent->PluginCrashed(); } + + instanceTag->mInstance->Stop(); - instance->Stop(); - - nsPluginTag* pluginTag = TagForPlugin(instance->Plugin()); - mInstances.RemoveElement(instance); + nsPluginTag* pluginTag = instanceTag->mPluginTag; + mInstanceTags.RemoveElement(instanceTag); OnPluginInstanceDestroyed(pluginTag); } } @@ -5190,41 +5240,50 @@ nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin) } #endif -nsNPAPIPluginInstance* -nsPluginHost::FindInstance(const char *mimetype) +nsPluginInstanceTag* +nsPluginHost::FindInstanceTag(nsIPluginInstance *instance) { - PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0); - - for (PRUint32 i = 0; i < mInstances.Length(); i++) { - nsNPAPIPluginInstance* instance = mInstances[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 && instance->Plugin()->IsDefaultPlugin()) - return instance; - - const char* mt; - nsresult rv = instance->GetMIMEType(&mt); - if (NS_FAILED(rv)) - continue; - - if (PL_strcasecmp(mt, mimetype) == 0) - return instance; + for (PRUint32 i = 0; i < mInstanceTags.Length(); i++) { + nsPluginInstanceTag *instanceTag = mInstanceTags[i]; + if (instanceTag->mInstance == instance) + return instanceTag; } return nsnull; } -nsNPAPIPluginInstance* -nsPluginHost::FindStoppedInstance(const char * url) +nsPluginInstanceTag* +nsPluginHost::FindInstanceTag(const char *mimetype) { - for (PRUint32 i = 0; i < mInstances.Length(); i++) { - nsNPAPIPluginInstance *instance = mInstances[i]; - nsIURI *uri = instance->GetURI(); - if (!uri) + 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; - nsCAutoString spec; - uri->GetSpec(spec); - if (!PL_strcmp(url, spec.get()) && !instance->IsRunning()) - return instance; + + 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; } @@ -5232,9 +5291,10 @@ nsPluginHost::FindStoppedInstance(const char * url) void nsPluginHost::StopRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag) { - for (PRInt32 i = mInstances.Length(); i > 0; i--) { - nsNPAPIPluginInstance *instance = mInstances[i - 1]; - if (instance->IsRunning() && (!aPluginTag || aPluginTag == TagForPlugin(instance->Plugin()))) { + 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(); @@ -5252,17 +5312,17 @@ nsPluginHost::StopRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* a } } - nsPluginTag* pluginTag = TagForPlugin(instance->Plugin()); - mInstances.RemoveElement(instance); + nsPluginTag* pluginTag = instanceTag->mPluginTag; + mInstanceTags.RemoveElement(instanceTag); OnPluginInstanceDestroyed(pluginTag); } } } -nsTArray< nsRefPtr >* -nsPluginHost::InstanceArray() +nsTArray< nsAutoPtr >* +nsPluginHost::InstanceTagArray() { - return &mInstances; + return &mInstanceTags; } nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request, diff --git a/modules/plugin/base/src/nsPluginHost.h b/modules/plugin/base/src/nsPluginHost.h index c8452a941419..d187d665ab8f 100644 --- a/modules/plugin/base/src/nsPluginHost.h +++ b/modules/plugin/base/src/nsPluginHost.h @@ -163,16 +163,16 @@ public: void PluginCrashed(nsNPAPIPlugin* plugin); #endif - nsNPAPIPluginInstance *FindInstance(const char *mimetype); - nsNPAPIPluginInstance *FindStoppedInstance(const char * url); - nsNPAPIPluginInstance *FindOldestStoppedInstance(); - PRUint32 StoppedInstanceCount(); + 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< nsRefPtr > *InstanceArray(); + nsTArray< nsAutoPtr > *InstanceTagArray(); - nsPluginTag* TagForPlugin(nsNPAPIPlugin* aPlugin); private: nsresult TrySetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner); @@ -196,12 +196,21 @@ private: nsPluginTag* FindPluginEnabledForExtension(const char* aExtension, const char* &aMimeType); + // Return the tag for |plugin| if found, nsnull if not. + nsPluginTag* + FindTagForPlugin(nsIPlugin* aPlugin); + nsresult FindStoppedPluginForURL(nsIURI* aURL, nsIPluginInstanceOwner *aOwner); nsresult SetUpDefaultPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner); + nsresult + AddInstanceToActiveList(nsCOMPtr aPlugin, + nsIPluginInstance* aInstance, + nsIURI* aURL, PRBool aDefaultPlugin); + nsresult FindPlugins(PRBool aCreatePluginList, PRBool * aPluginsChanged); @@ -264,7 +273,7 @@ private: // set by pref plugin.disable PRPackedBool mPluginsDisabled; - nsTArray< nsRefPtr > mInstances; + nsTArray< nsAutoPtr > mInstanceTags; nsTArray mUnusedLibraries; diff --git a/modules/plugin/base/src/nsPluginTags.cpp b/modules/plugin/base/src/nsPluginTags.cpp index 6f911162e517..b63a0d92bbab 100644 --- a/modules/plugin/base/src/nsPluginTags.cpp +++ b/modules/plugin/base/src/nsPluginTags.cpp @@ -559,3 +559,36 @@ void nsPluginTag::TryUnloadPlugin() RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister); } } + +/* nsPluginInstanceTag */ + +nsPluginInstanceTag::nsPluginInstanceTag(nsPluginTag* aPluginTag, + nsIPluginInstance* aInstance, + const char * url, + PRBool aDefaultPlugin) +{ + NS_ASSERTION(aInstance, "Must have a valid plugin instance when creating an nsPluginInstanceTag"); + NS_ADDREF(aInstance); + mInstance = static_cast(aInstance); + + mPluginTag = aPluginTag; + + mURL = PL_strdup(url); + + mDefaultPlugin = aDefaultPlugin; +} + +nsPluginInstanceTag::~nsPluginInstanceTag() +{ + mPluginTag = nsnull; + + nsCOMPtr owner; + mInstance->GetOwner(getter_AddRefs(owner)); + if (owner) + owner->SetInstance(nsnull); + mInstance->InvalidateOwner(); + + NS_RELEASE(mInstance); + + PL_strfree(mURL); +} diff --git a/modules/plugin/base/src/nsPluginTags.h b/modules/plugin/base/src/nsPluginTags.h index 06ccb0768013..ae74c3e7b300 100644 --- a/modules/plugin/base/src/nsPluginTags.h +++ b/modules/plugin/base/src/nsPluginTags.h @@ -45,7 +45,8 @@ #include "nsCOMPtr.h" #include "nsIPluginTag.h" #include "nsIPlugin.h" -#include "nsString.h" +#include "nsNPAPIPluginInstance.h" +#include "nsISupportsArray.h" class nsPluginHost; struct PRLibrary; @@ -122,4 +123,20 @@ private: nsresult EnsureMembersAreUTF8(); }; +struct nsPluginInstanceTag +{ + char* mURL; + nsRefPtr mPluginTag; + nsNPAPIPluginInstance* mInstance; // this must always be valid + PRBool mDefaultPlugin; + // Array holding all opened stream listeners for this entry + nsCOMPtr mStreams; + + nsPluginInstanceTag(nsPluginTag* aPluginTag, + nsIPluginInstance* aInstance, + const char * url, + PRBool aDefaultPlugin); + ~nsPluginInstanceTag(); +}; + #endif // nsPluginTags_h_ diff --git a/modules/plugin/test/mochitest/test_GCrace.html b/modules/plugin/test/mochitest/test_GCrace.html new file mode 100644 index 000000000000..40e4f04e14df --- /dev/null +++ b/modules/plugin/test/mochitest/test_GCrace.html @@ -0,0 +1,59 @@ + + GC race with actors on the parent + + + + + +

+ + + + diff --git a/modules/plugin/test/testplugin/nptest.cpp b/modules/plugin/test/testplugin/nptest.cpp index 393eeebe346d..0b203c7dac51 100644 --- a/modules/plugin/test/testplugin/nptest.cpp +++ b/modules/plugin/test/testplugin/nptest.cpp @@ -46,6 +46,7 @@ #ifdef XP_WIN #include #include +#include #define getpid _getpid #else #include @@ -144,6 +145,7 @@ static bool setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, static bool getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static const NPUTF8* sPluginMethodIdentifierNames[] = { "npnEvaluateTest", @@ -181,6 +183,7 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = { "getCookie", "getAuthInfo", "asyncCallbackTest", + "checkGCRace", }; static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)]; static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMethodIdentifierNames)] = { @@ -219,6 +222,7 @@ static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMetho getCookie, getAuthInfo, asyncCallbackTest, + checkGCRace, }; struct URLNotifyData @@ -2450,3 +2454,101 @@ asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPV return true; } + +static bool +GCRaceInvoke(NPObject*, NPIdentifier, const NPVariant*, uint32_t, NPVariant*) +{ + return false; +} + +static bool +GCRaceInvokeDefault(NPObject* o, const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + if (1 != argCount || !NPVARIANT_IS_INT32(args[0]) || + 35 != NPVARIANT_TO_INT32(args[0])) + return false; + + return true; +} + +static const NPClass kGCRaceClass = { + NP_CLASS_STRUCT_VERSION, + NULL, + NULL, + NULL, + NULL, + GCRaceInvoke, + GCRaceInvokeDefault, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +struct GCRaceData +{ + GCRaceData(NPP npp, NPObject* callback, NPObject* localFunc) + : npp_(npp) + , callback_(callback) + , localFunc_(localFunc) + { + NPN_RetainObject(callback_); + NPN_RetainObject(localFunc_); + } + + ~GCRaceData() + { + NPN_ReleaseObject(callback_); + NPN_ReleaseObject(localFunc_); + } + + NPP npp_; + NPObject* callback_; + NPObject* localFunc_; +}; + +static void +FinishGCRace(void* closure) +{ + GCRaceData* rd = static_cast(closure); + +#ifdef XP_WIN + Sleep(5000); +#else + sleep(5); +#endif + + NPVariant arg; + OBJECT_TO_NPVARIANT(rd->localFunc_, arg); + + NPVariant result; + bool ok = NPN_InvokeDefault(rd->npp_, rd->callback_, &arg, 1, &result); + if (!ok) + return; + + NPN_ReleaseVariantValue(&result); + delete rd; +} + +bool +checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount, + NPVariant* result) +{ + if (1 != argCount || !NPVARIANT_IS_OBJECT(args[0])) + return false; + + NPP npp = static_cast(npobj)->npp; + + NPObject* localFunc = + NPN_CreateObject(npp, const_cast(&kGCRaceClass)); + + GCRaceData* rd = + new GCRaceData(npp, NPVARIANT_TO_OBJECT(args[0]), localFunc); + NPN_PluginThreadAsyncCall(npp, FinishGCRace, rd); + + OBJECT_TO_NPVARIANT(localFunc, *result); + return true; +} diff --git a/netwerk/base/src/nsStreamObserverProxy.cpp b/netwerk/base/src/nsStreamObserverProxy.cpp deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/netwerk/base/src/nsStreamObserverProxy.h b/netwerk/base/src/nsStreamObserverProxy.h deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/netwerk/streamconv/converters/nsBinHexDecoder.cpp b/netwerk/streamconv/converters/nsBinHexDecoder.cpp index 81897243e485..0b3950a05171 100644 --- a/netwerk/streamconv/converters/nsBinHexDecoder.cpp +++ b/netwerk/streamconv/converters/nsBinHexDecoder.cpp @@ -204,7 +204,7 @@ nsresult nsBinHexDecoder::ProcessNextState(nsIRequest * aRequest, nsISupports * // c & 63 returns the length of mName. So if we need the length, that's how // you can figure it out.... mName.SetLength(c & 63); - if (mName.Length() != c & 63) { + if (mName.Length() != (c & 63)) { /* XXX ProcessNextState/ProcessNextChunk aren't rv checked */ mState = BINHEX_STATE_DONE; } diff --git a/parser/htmlparser/src/nsViewSourceHTML.cpp b/parser/htmlparser/src/nsViewSourceHTML.cpp index 5f905994c511..38fcb948da6d 100644 --- a/parser/htmlparser/src/nsViewSourceHTML.cpp +++ b/parser/htmlparser/src/nsViewSourceHTML.cpp @@ -94,6 +94,7 @@ Stopwatch vsTimer; // viewsource.css; the setting is remembered between invocations using a pref. static const char kBodyId[] = "viewsource"; static const char kBodyClassWrap[] = "wrap"; +static const char kBodyTabSize[] = "-moz-tab-size: "; NS_IMPL_ISUPPORTS1(CViewSourceHTML, nsIDTD) @@ -197,6 +198,7 @@ CViewSourceHTML::CViewSourceHTML() { mSyntaxHighlight = PR_FALSE; mWrapLongLines = PR_FALSE; + mTabSize = -1; nsCOMPtr prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID)); if (prefBranch) { PRBool temp; @@ -206,6 +208,9 @@ CViewSourceHTML::CViewSourceHTML() rv = prefBranch->GetBoolPref("view_source.wrap_long_lines", &temp); mWrapLongLines = NS_SUCCEEDED(rv) ? temp : PR_FALSE; + + rv = prefBranch->GetIntPref("view_source.tab_size", &temp); + mTabSize = NS_SUCCEEDED(rv) ? temp : -1; } mSink = 0; @@ -402,6 +407,13 @@ NS_IMETHODIMP CViewSourceHTML::BuildModel(nsITokenizer* aTokenizer, NS_LITERAL_STRING("class"), NS_ConvertASCIItoUTF16(kBodyClassWrap)); } + if (mTabSize >= 0) { + nsAutoString styleValue = NS_ConvertASCIItoUTF16(kBodyTabSize); + styleValue.AppendInt(mTabSize); + AddAttrToNode(bodyNode, theAllocator, + NS_LITERAL_STRING("style"), + styleValue); + } result = mSink->OpenContainer(bodyNode); if(NS_SUCCEEDED(result)) mHasOpenBody=PR_TRUE; } diff --git a/parser/htmlparser/src/nsViewSourceHTML.h b/parser/htmlparser/src/nsViewSourceHTML.h index e7ed360888d2..3a0586e0f3c1 100644 --- a/parser/htmlparser/src/nsViewSourceHTML.h +++ b/parser/htmlparser/src/nsViewSourceHTML.h @@ -141,6 +141,7 @@ protected: PRInt32 mLineNumber; nsITokenizer* mTokenizer; // weak + PRInt32 mTabSize; PRPackedBool mSyntaxHighlight; PRPackedBool mWrapLongLines; PRPackedBool mHasOpenRoot; diff --git a/security/manager/ssl/src/nsSmartCardEvent.cpp b/security/manager/ssl/src/nsSmartCardEvent.cpp index 695c2da32576..53104e96ebd9 100644 --- a/security/manager/ssl/src/nsSmartCardEvent.cpp +++ b/security/manager/ssl/src/nsSmartCardEvent.cpp @@ -108,16 +108,12 @@ NS_IMETHODIMP nsSmartCardEvent::SetTarget(nsIDOMEventTarget *aTarget) NS_IMETHODIMP_(PRBool ) nsSmartCardEvent::IsDispatchStopped() { - PRBool isDispatchPrevented = nsnull; - PRBool * aIsDispatchPrevented = &isDispatchPrevented; NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); return mPrivate->IsDispatchStopped(); } NS_IMETHODIMP_(nsEvent*) nsSmartCardEvent::GetInternalNSEvent() { - nsEvent* nSEvent = nsnull; - nsEvent** aNSEvent = &nSEvent; NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); return mPrivate->GetInternalNSEvent(); } diff --git a/storage/src/Variant_inl.h b/storage/src/Variant_inl.h index f043f3637b8a..0bb279f641c8 100644 --- a/storage/src/Variant_inl.h +++ b/storage/src/Variant_inl.h @@ -251,5 +251,12 @@ Variant_base::GetAsWStringWithSize(PRUint32 *, return NS_ERROR_CANNOT_CONVERT_DATA; } +inline +NS_IMETHODIMP +Variant_base::GetAsJSVal(jsval *) +{ + return NS_ERROR_CANNOT_CONVERT_DATA; +} + } // namespace storage } // namespace mozilla diff --git a/testing/mochitest/server.js b/testing/mochitest/server.js index 8b555e2c7e21..bb88d5c5e826 100644 --- a/testing/mochitest/server.js +++ b/testing/mochitest/server.js @@ -205,6 +205,19 @@ function createMochitestServer(serverBasePath) server.registerContentType("oga", "audio/ogg"); server.setIndexHandler(defaultDirHandler); + var serverRoot = + { + getFile: function getFile(path) + { + var file = serverBasePath.clone().QueryInterface(Ci.nsILocalFile); + file.appendRelativePath(path); + return file; + }, + QueryInterface: function(aIID) { return this; } + }; + + server.setObjectState("SERVER_ROOT", serverRoot); + processLocations(server); return server; diff --git a/testing/mochitest/ssltunnel/ssltunnel.cpp b/testing/mochitest/ssltunnel/ssltunnel.cpp index 30b5b57e58d5..5e84bb8a794e 100644 --- a/testing/mochitest/ssltunnel/ssltunnel.cpp +++ b/testing/mochitest/ssltunnel/ssltunnel.cpp @@ -417,7 +417,10 @@ void HandleConnection(void* data) client_auth_option clientAuth; string fullHost; - printf("SSLTUNNEL(%p): incoming connection csock(0)=%p, ssock(1)=%p\n", data, ci->client_sock, (PRFileDesc*)other_sock); + printf("SSLTUNNEL(%p): incoming connection csock(0)=%p, ssock(1)=%p\n", + static_cast(data), + static_cast(ci->client_sock), + static_cast(other_sock)); if (other_sock) { PRInt32 numberOfSockets = 1; @@ -445,15 +448,17 @@ void HandleConnection(void* data) { sockets[0].in_flags |= PR_POLL_EXCEPT; sockets[1].in_flags |= PR_POLL_EXCEPT; - printf("SSLTUNNEL(%p): polling flags csock(0)=%c%c, ssock(1)=%c%c\n", data, - sockets[0].in_flags & PR_POLL_READ ? 'R' : '-', - sockets[0].in_flags & PR_POLL_WRITE ? 'W' : '-', - sockets[1].in_flags & PR_POLL_READ ? 'R' : '-', - sockets[1].in_flags & PR_POLL_WRITE ? 'W' : '-'); + printf("SSLTUNNEL(%p): polling flags csock(0)=%c%c, ssock(1)=%c%c\n", + static_cast(data), + sockets[0].in_flags & PR_POLL_READ ? 'R' : '-', + sockets[0].in_flags & PR_POLL_WRITE ? 'W' : '-', + sockets[1].in_flags & PR_POLL_READ ? 'R' : '-', + sockets[1].in_flags & PR_POLL_WRITE ? 'W' : '-'); PRInt32 pollStatus = PR_Poll(sockets, numberOfSockets, PR_MillisecondsToInterval(1000)); if (pollStatus < 0) { - printf("SSLTUNNEL(%p): pollStatus=%d, exiting\n", data, pollStatus); + printf("SSLTUNNEL(%p): pollStatus=%d, exiting\n", + static_cast(data), pollStatus); client_error = true; break; } @@ -461,7 +466,8 @@ void HandleConnection(void* data) if (pollStatus == 0) { // timeout - printf("SSLTUNNEL(%p): poll timeout, looping\n", data); + printf("SSLTUNNEL(%p): poll timeout, looping\n", + static_cast(data)); continue; } @@ -473,7 +479,12 @@ void HandleConnection(void* data) PRInt16 &in_flags2 = sockets[s2].in_flags; sockets[s].out_flags = 0; - printf("SSLTUNNEL(%p): %csock(%d)=%p out_flags=%d", data, s==0?'c':'s', s, sockets[s].fd, out_flags); + printf("SSLTUNNEL(%p): %csock(%d)=%p out_flags=%d", + static_cast(data), + s == 0 ? 'c' : 's', + s, + static_cast(sockets[s].fd), + out_flags); if (out_flags & (PR_POLL_EXCEPT | PR_POLL_ERR | PR_POLL_HUP)) { printf(" :exception\n"); @@ -489,7 +500,7 @@ void HandleConnection(void* data) if (out_flags & PR_POLL_READ && !buffers[s].free()) { printf(" no place in read buffer but got read flag, dropping it now!"); - in_flags &= ~PR_POLL_READ; + in_flags &= ~PR_POLL_READ; } if (out_flags & PR_POLL_READ && buffers[s].free()) @@ -650,7 +661,10 @@ void HandleConnection(void* data) else client_error = true; - printf("SSLTUNNEL(%p): exiting root function for csock=%p, ssock=%p\n", data, ci->client_sock, (PRFileDesc*)other_sock); + printf("SSLTUNNEL(%p): exiting root function for csock=%p, ssock=%p\n", + static_cast(data), + static_cast(ci->client_sock), + static_cast(other_sock)); if (!client_error) PR_Shutdown(ci->client_sock, PR_SHUTDOWN_SEND); PR_Close(ci->client_sock); diff --git a/toolkit/components/exthelper/extApplication.js b/toolkit/components/exthelper/extApplication.js index 763bedbda39b..e05f4d7a1330 100644 --- a/toolkit/components/exthelper/extApplication.js +++ b/toolkit/components/exthelper/extApplication.js @@ -140,7 +140,7 @@ Events.prototype = { }, dispatch : function evts_dispatch(aEvent, aEventItem) { - eventItem = new EventItem(aEvent, aEventItem); + var eventItem = new EventItem(aEvent, aEventItem); this._listeners.forEach(function(key){ if (key.event == aEvent) { diff --git a/toolkit/content/plugins.css b/toolkit/content/plugins.css index edfd0a61330e..089769ebf451 100644 --- a/toolkit/content/plugins.css +++ b/toolkit/content/plugins.css @@ -111,13 +111,9 @@ td { } th.type, th.suff { - width: 20%; + width: 25%; } th.desc { width: 50%; } - -th.enabled { - width: 10%; -} diff --git a/toolkit/content/plugins.html b/toolkit/content/plugins.html index 30c080f33bfa..08bda86b0986 100644 --- a/toolkit/content/plugins.html +++ b/toolkit/content/plugins.html @@ -129,30 +129,21 @@ document.writeln("" + pluginsbundle.GetStringFromName("mimetype_label") + "<\/th>"); document.writeln("" + pluginsbundle.GetStringFromName("description_label") + "<\/th>"); document.writeln("" + pluginsbundle.GetStringFromName("suffixes_label") + "<\/th>"); - document.writeln("" + pluginsbundle.GetStringFromName("enabled_label") + "<\/th><\/tr>"); - document.writeln("<\/thead>"); + document.writeln("<\/tr><\/thead>"); document.writeln(""); var numTypes = plugin.length; var mimetype; - var enabled; - var enabledPlugin; for (var j = 0; j < numTypes; j++) { mimetype = plugin[j]; if (mimetype) { - enabled = pluginsbundle.GetStringFromName("no_label"); - enabledPlugin = mimetype.enabledPlugin; - if (enabledPlugin && (enabledPlugin.filename == plugin.filename)) - enabled = pluginsbundle.GetStringFromName("yes_label"); - document.writeln(""); document.writeln("" + mimetype.type + "<\/td>"); document.writeln("" + mimetype.description + "<\/td>"); document.writeln("" + mimetype.suffixes + "<\/td>"); - document.writeln("" + enabled + "<\/td>"); document.writeln("<\/tr>"); } } diff --git a/toolkit/content/widgets/toolbarbutton.xml b/toolkit/content/widgets/toolbarbutton.xml index 4befb7bb02dc..4e939bab1451 100644 --- a/toolkit/content/widgets/toolbarbutton.xml +++ b/toolkit/content/widgets/toolbarbutton.xml @@ -13,9 +13,9 @@ - + + xbl:inherits="value=label,accesskey,crop"/> @@ -31,9 +31,9 @@ extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton"> - + + xbl:inherits="value=label,accesskey,crop,dragover-top"/> @@ -44,9 +44,9 @@ - + + xbl:inherits="value=label,accesskey,crop,dragover-top"/> @@ -64,9 +64,9 @@ + align,dir,pack,orient"/> + xbl:inherits="align,dir,pack,orient,disabled,label"/> diff --git a/toolkit/mozapps/xpinstall/locale/xpinstallConfirm.properties.txt b/toolkit/mozapps/xpinstall/locale/xpinstallConfirm.properties.txt deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/toolkit/themes/gnomestripe/global/toolbarbutton.css b/toolkit/themes/gnomestripe/global/toolbarbutton.css index ba3a09d1b513..62ce69907a73 100644 --- a/toolkit/themes/gnomestripe/global/toolbarbutton.css +++ b/toolkit/themes/gnomestripe/global/toolbarbutton.css @@ -73,8 +73,7 @@ toolbarbutton.tabbable { -moz-user-focus: normal !important; } -toolbarbutton:hover, -toolbarbutton[buttonover="true"] { +toolbarbutton:hover { border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight; color: -moz-buttonhovertext; } @@ -111,7 +110,7 @@ toolbarbutton[checked="true"] { } toolbarbutton[checked="true"]:hover, -toolbarbutton[checked="true"]:hover:active { +toolbarbutton[checked="true"]:hover:active { color: -moz-buttonhovertext !important; background-color: -moz-buttonhoverface !important; } diff --git a/toolkit/themes/pinstripe/global/tabbox.css b/toolkit/themes/pinstripe/global/tabbox.css index 7b67e3687e40..a2f0baef2beb 100644 --- a/toolkit/themes/pinstripe/global/tabbox.css +++ b/toolkit/themes/pinstripe/global/tabbox.css @@ -14,7 +14,7 @@ tabbox { } tabpanels { - -moz-appearance: tabpanels; + -moz-appearance: tabpanels; padding: 33px 15px 15px; } diff --git a/toolkit/themes/pinstripe/global/toolbarbutton.css b/toolkit/themes/pinstripe/global/toolbarbutton.css index 04955af47200..f79a88547b90 100644 --- a/toolkit/themes/pinstripe/global/toolbarbutton.css +++ b/toolkit/themes/pinstripe/global/toolbarbutton.css @@ -55,7 +55,7 @@ toolbarbutton:not([disabled="true"]):active:hover { } .toolbarbutton-icon { - padding: 1px 0px 1px 0px; + padding: 1px 0; } .toolbarbutton-text { @@ -65,13 +65,6 @@ toolbarbutton:not([disabled="true"]):active:hover { vertical-align: middle; } -toolbarbutton:hover:active[buttonstyle="text"], -toolbarbutton[open="true"][buttonstyle="text"] { - color: #2c498c; -} - - - toolbarbutton[disabled="true"], toolbarbutton[disabled="true"]:hover, toolbarbutton[disabled="true"]:hover:active, @@ -88,7 +81,7 @@ toolbarbutton[checked="true"] { border-left: 1px solid #b9b9b9; color: ButtonText !important; } - + /* ::::: toolbarbutton menu ::::: */ .toolbarbutton-menu-dropmarker { @@ -128,7 +121,6 @@ toolbarbutton[type="menu-button"][disabled="true"]:hover:active { -moz-box-orient: vertical; } - /* .......... dropmarker .......... */ .toolbarbutton-menubutton-dropmarker { @@ -148,4 +140,3 @@ toolbarbutton[type="menu-button"][disabled="true"]:hover:active { toolbarbutton.tabbable { -moz-user-focus: normal !important; } - diff --git a/toolkit/themes/pinstripe/help/help.css b/toolkit/themes/pinstripe/help/help.css index a3d2e187f2fe..04b7c7a2d3dc 100644 --- a/toolkit/themes/pinstripe/help/help.css +++ b/toolkit/themes/pinstripe/help/help.css @@ -92,44 +92,40 @@ /* Style the back dropmark */ -#help-back-button .toolbarbutton-menubutton-dropmarker { +#help-back-button > .toolbarbutton-menubutton-dropmarker { margin-top: 3px; list-style-image: url("chrome://global/skin/toolbar/dropmark-nav.png"); -moz-image-region: rect(0px, 14px, 24px, 0px); } -#help-back-button:hover .toolbarbutton-menubutton-dropmarker, -#help-back-button[buttonover="true"] > .toolbarbutton-menubutton-dropmarker { +#help-back-button:hover > .toolbarbutton-menubutton-dropmarker { -moz-image-region: rect(24px, 14px, 48px, 0px); } -#help-back-button[disabled="true"] .toolbarbutton-menubutton-dropmarker { +#help-back-button[disabled="true"] > .toolbarbutton-menubutton-dropmarker { list-style-image: url("chrome://global/skin/toolbar/dropmark-nav.png") !important; -moz-image-region: rect(48px, 14px, 72px, 0px) !important; } -#help-back-button:hover:active .toolbarbutton-menubutton-dropmarker, -#help-back-button[buttondown="true"] > .toolbarbutton-menubutton-dropmarker { +#help-back-button:hover:active > .toolbarbutton-menubutton-dropmarker { -moz-image-region: rect(72px, 14px, 96px, 0px); } /* Style the forward dropmark */ -#help-forward-button .toolbarbutton-menubutton-dropmarker { +#help-forward-button > .toolbarbutton-menubutton-dropmarker { margin-top: 3px; list-style-image: url("chrome://global/skin/toolbar/dropmark-nav.png"); -moz-image-region: rect(0px, 14px, 24px, 0px); } -#help-forward-button:hover .toolbarbutton-menubutton-dropmarker, -#help-forward-button[buttonover="true"] > .toolbarbutton-menubutton-dropmarker { +#help-forward-button:hover > .toolbarbutton-menubutton-dropmarker { -moz-image-region: rect(24px, 14px, 48px, 0px); } -#help-forward-button[disabled="true"] .toolbarbutton-menubutton-dropmarker { +#help-forward-button[disabled="true"] > .toolbarbutton-menubutton-dropmarker { list-style-image: url("chrome://global/skin/toolbar/dropmark-nav.png") !important; -moz-image-region: rect(48px, 14px, 72px, 0px) !important; } -#help-forward-button:hover:active .toolbarbutton-menubutton-dropmarker, -#help-forward-button[buttondown="true"] > .toolbarbutton-menubutton-dropmarker { +#help-forward-button:hover:active > .toolbarbutton-menubutton-dropmarker { -moz-image-region: rect(72px, 14px, 96px, 0px); } diff --git a/toolkit/themes/winstripe/global/button.css b/toolkit/themes/winstripe/global/button.css index 5cd1dd4b29ae..0c466e5c1472 100644 --- a/toolkit/themes/winstripe/global/button.css +++ b/toolkit/themes/winstripe/global/button.css @@ -180,7 +180,5 @@ button[type="disclosure"] { } button[type="disclosure"][open="true"] { - list-style-image: url("chrome://global/skin/tree/twisty-open.png"); + list-style-image: url("chrome://global/skin/tree/twisty-open.png"); } - - diff --git a/toolkit/themes/winstripe/global/global.css b/toolkit/themes/winstripe/global/global.css index 9086f20141a1..faec1e81b421 100644 --- a/toolkit/themes/winstripe/global/global.css +++ b/toolkit/themes/winstripe/global/global.css @@ -221,7 +221,7 @@ sidebarheader:-moz-lwtheme { border-bottom-color: ThreeDHighlight; margin: 0 5px 5px; } - + .outset { border: 1px solid ThreeDShadow; border-left-color: ThreeDHighlight; @@ -238,7 +238,7 @@ separator[orient="vertical"] { separator.thin:not([orient="vertical"]) { height: 0.5em; -} +} separator.thin[orient="vertical"] { width: 0.5em; } @@ -261,7 +261,7 @@ separator.groove[orient="vertical"] { .small-margin { margin: 1px 2px; } - + .plain { -moz-appearance: none; margin: 0 !important; @@ -325,7 +325,7 @@ label[disabled="true"]:-moz-system-metric(windows-classic) { border: 1px solid transparent; cursor: pointer; } - + .text-link:focus { border: 1px dotted -moz-DialogText; } diff --git a/toolkit/themes/winstripe/global/toolbarbutton.css b/toolkit/themes/winstripe/global/toolbarbutton.css index 274f03683408..0a1209add832 100644 --- a/toolkit/themes/winstripe/global/toolbarbutton.css +++ b/toolkit/themes/winstripe/global/toolbarbutton.css @@ -69,8 +69,7 @@ toolbarbutton.tabbable { -moz-user-focus: normal !important; } -toolbarbutton:focus -{ +toolbarbutton:focus { /* -moz-appearance looks redundant here but is necessary. Without it, the outline won't appear. */ -moz-appearance: toolbarbutton; @@ -78,8 +77,7 @@ toolbarbutton:focus outline-offset: -2px; } -toolbarbutton:hover:not([disabled="true"]), -toolbarbutton[buttonover="true"] { +toolbarbutton:hover:not([disabled="true"]) { border-color: ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight; } diff --git a/widget/public/nsGUIEvent.h b/widget/public/nsGUIEvent.h index 0dca15573fe7..126308fe0269 100644 --- a/widget/public/nsGUIEvent.h +++ b/widget/public/nsGUIEvent.h @@ -56,6 +56,7 @@ #include "nsTArray.h" #include "nsTraceRefcnt.h" #include "nsITransferable.h" +#include "nsIVariant.h" class nsIRenderingContext; class nsIRegion; @@ -246,6 +247,7 @@ class nsHashKey; #define NS_HASHCHANGE (NS_STREAM_EVENT_START + 2) #define NS_IMAGE_ABORT (NS_STREAM_EVENT_START + 3) #define NS_LOAD_ERROR (NS_STREAM_EVENT_START + 4) +#define NS_POPSTATE (NS_STREAM_EVENT_START + 5) #define NS_BEFORE_PAGE_UNLOAD (NS_STREAM_EVENT_START + 6) #define NS_PAGE_RESTORE (NS_STREAM_EVENT_START + 7) diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index d876eafca7f5..0938a4f73e95 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -1760,6 +1760,22 @@ void nsChildView::Scroll(const nsIntPoint& aDelta, } } #endif // NS_LEOPARD_AND_LATER + // Invalidate the area that was scrolled into view from outside the window + // First, compute the destination region whose source was outside the + // window. We do this by subtracting from destRegion the window bounds, + // translated by the scroll amount. + NSView* rootView = [[mView window] contentView]; + NSRect rootViewRect = [mView convertRect:[rootView bounds] fromView: rootView]; + nsIntRect windowBounds; + NSRectToGeckoRect(rootViewRect, windowBounds); + destRegion.Sub(destRegion, windowBounds + aDelta); + nsIntRegionRectIterator iter(destRegion); + const nsIntRect* invalidate; + while ((invalidate = iter.Next()) != nsnull) { + NSRect rect; + GeckoRectToNSRect(*invalidate, rect); + [mView setNeedsDisplayInRect:rect]; + } // Leopard, at least, has a nasty bug where calling scrollRect:by: doesn't // actually trigger a window update. A window update is only triggered diff --git a/widget/src/cocoa/nsCocoaWindow.mm b/widget/src/cocoa/nsCocoaWindow.mm index d2f56efbe4be..04322c9e5f2d 100644 --- a/widget/src/cocoa/nsCocoaWindow.mm +++ b/widget/src/cocoa/nsCocoaWindow.mm @@ -1371,8 +1371,7 @@ NS_IMETHODIMP nsCocoaWindow::SetFocus(PRBool aState) if (mPopupContentView) { mPopupContentView->SetFocus(aState); } - else if (aState && [mWindow isVisible]) { - // if the window is shown, move it to the front + else if (aState && ([mWindow isVisible] || [mWindow isMiniaturized])) { [mWindow setAcceptsMouseMovedEvents:YES]; [mWindow makeKeyAndOrderFront:nil]; SendSetZLevelEvent(); diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index a49dc6c13536..01b3e5df76a6 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -1002,8 +1002,8 @@ void ScrollRectIterBase::Move(ScrollRect** aUnmovedLink) // which adds an O(n^2) cost to this algorithm (where n is the number of // rectangles across x). The reverse-x ordering from InitialSortComparator // avoids this for the case when rectangles are aligned in y. - for (ScrollRect** nextLink = aUnmovedLink; - ScrollRect* otherRect = *nextLink; ) { + for (ScrollRect** nextLink = aUnmovedLink; *nextLink; ) { + ScrollRect* otherRect = *nextLink; NS_ASSERTION(otherRect->y >= rect->y, "Scroll rectangles out of order"); if (otherRect->y >= rect->YMost()) // doesn't overlap vertically break; @@ -1098,6 +1098,7 @@ case _value: eventName.AssignWithConversion(_name) ; break _ASSIGN_eventName(NS_MOUSE_MOVE,"NS_MOUSE_MOVE"); _ASSIGN_eventName(NS_MOVE,"NS_MOVE"); _ASSIGN_eventName(NS_LOAD,"NS_LOAD"); + _ASSIGN_eventName(NS_POPSTATE,"NS_POPSTATE"); _ASSIGN_eventName(NS_PAGE_UNLOAD,"NS_PAGE_UNLOAD"); _ASSIGN_eventName(NS_HASHCHANGE,"NS_HASHCHANGE"); _ASSIGN_eventName(NS_PAINT,"NS_PAINT"); diff --git a/xpcom/ds/nsIVariant.idl b/xpcom/ds/nsIVariant.idl index 2c9d9e96cd42..6cdffe00e326 100644 --- a/xpcom/ds/nsIVariant.idl +++ b/xpcom/ds/nsIVariant.idl @@ -77,6 +77,11 @@ interface nsIDataType : nsISupports const PRUint16 VTYPE_EMPTY = 255; }; +%{ C++ +#include "jspubtd.h" +%} + +native JSVal(jsval); /** * XPConnect has magic to transparently convert between nsIVariant and JS types. @@ -86,7 +91,7 @@ interface nsIDataType : nsISupports * JS type anyway. */ -[scriptable, uuid(6c9eb060-8c6a-11d5-90f3-0010a4e73d9a)] +[scriptable, uuid(81e4c2de-acac-4ad6-901a-b5fb1b851a0d)] interface nsIVariant : nsISupports { [noscript] readonly attribute PRUint16 dataType; @@ -112,6 +117,7 @@ interface nsIVariant : nsISupports [noscript] string getAsString(); [noscript] wstring getAsWString(); [noscript] nsISupports getAsISupports(); + [noscript] JSVal getAsJSVal(); [noscript] void getAsInterface(out nsIIDPtr iid, [iid_is(iid), retval] out nsQIResult iface); diff --git a/xpcom/ds/nsVariant.cpp b/xpcom/ds/nsVariant.cpp index eb8abb07d77f..101cf1b7dba9 100644 --- a/xpcom/ds/nsVariant.cpp +++ b/xpcom/ds/nsVariant.cpp @@ -1886,6 +1886,13 @@ NS_IMETHODIMP nsVariant::GetAsISupports(nsISupports **_retval) return nsVariant::ConvertToISupports(mData, _retval); } +/* jsval getAsJSVal() */ +NS_IMETHODIMP nsVariant::GetAsJSVal(jsval *_retval) +{ + // Can only get the JSVal from an XPCVariant. + return NS_ERROR_CANNOT_CONVERT_DATA; +} + /* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */ NS_IMETHODIMP nsVariant::GetAsInterface(nsIID * *iid, void * *iface) { diff --git a/xpcom/proxy/public/nsIProxyCreateInstance.idl b/xpcom/proxy/public/nsIProxyCreateInstance.idl deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/xpcom/proxy/public/nsProxyEvent.h b/xpcom/proxy/public/nsProxyEvent.h deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix.s deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_aix64.s deleted file mode 100644 index e69de29bb2d1..000000000000