зеркало из https://github.com/mozilla/pjs.git
Merge mozilla-central into electrolysis.
This commit is contained in:
Коммит
8411a08769
|
@ -44,7 +44,7 @@ interface nsIFrame;
|
||||||
interface nsObjectFrame;
|
interface nsObjectFrame;
|
||||||
interface nsIContent;
|
interface nsIContent;
|
||||||
|
|
||||||
[uuid(e0498def-1552-4763-8c47-6c6cc36c7aa0)]
|
[uuid(84a3ab70-8f7e-4610-9cd8-bd69308b76c5)]
|
||||||
interface nsIAccessibilityService : nsIAccessibleRetrieval
|
interface nsIAccessibilityService : nsIAccessibleRetrieval
|
||||||
{
|
{
|
||||||
nsIAccessible createOuterDocAccessible(in nsIDOMNode aNode);
|
nsIAccessible createOuterDocAccessible(in nsIDOMNode aNode);
|
||||||
|
@ -74,19 +74,6 @@ interface nsIAccessibilityService : nsIAccessibleRetrieval
|
||||||
nsIAccessible createHTMLTextFieldAccessible(in nsIFrame aFrame);
|
nsIAccessible createHTMLTextFieldAccessible(in nsIFrame aFrame);
|
||||||
nsIAccessible createHTMLCaptionAccessible(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
|
// For gtk+ native window accessible
|
||||||
nsIAccessible addNativeRootAccessible(in voidPtr aAtkAccessible);
|
nsIAccessible addNativeRootAccessible(in voidPtr aAtkAccessible);
|
||||||
void removeNativeRootAccessible(in nsIAccessible aRootAccessible);
|
void removeNativeRootAccessible(in nsIAccessible aRootAccessible);
|
||||||
|
|
|
@ -56,7 +56,7 @@ interface nsIDOMDOMStringList;
|
||||||
*
|
*
|
||||||
* @status UNDER_REVIEW
|
* @status UNDER_REVIEW
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(244e4c67-a1d3-44f2-9cab-cdaa31b68046)]
|
[scriptable, uuid(7eb49afb-6298-4ce6-816f-9615936540f4)]
|
||||||
interface nsIAccessibleRetrieval : nsISupports
|
interface nsIAccessibleRetrieval : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -92,26 +92,6 @@ interface nsIAccessibleRetrieval : nsISupports
|
||||||
*/
|
*/
|
||||||
nsIDOMNode getRelevantContentNodeFor(in nsIDOMNode aNode);
|
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.
|
* Return an nsIAccessible for a DOM node in the given pres shell.
|
||||||
* Create a new accessible of the appropriate type if necessary,
|
* Create a new accessible of the appropriate type if necessary,
|
||||||
|
|
|
@ -295,8 +295,7 @@ nsAccReorderEvent::HasAccessibleInReasonSubtree()
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
nsAccessNode::GetAccService()->GetAccessibleFor(mReasonNode,
|
GetAccService()->GetAccessibleFor(mReasonNode, getter_AddRefs(accessible));
|
||||||
getter_AddRefs(accessible));
|
|
||||||
|
|
||||||
return accessible || nsAccUtils::HasAccessibleChildren(mReasonNode);
|
return accessible || nsAccUtils::HasAccessibleChildren(mReasonNode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,8 +172,7 @@ nsAccUtils::GetPositionAndSizeForXULSelectControlItem(nsIDOMNode *aNode,
|
||||||
nsCOMPtr<nsIDOMNode> currNode(do_QueryInterface(currItem));
|
nsCOMPtr<nsIDOMNode> currNode(do_QueryInterface(currItem));
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessible> itemAcc;
|
nsCOMPtr<nsIAccessible> itemAcc;
|
||||||
nsAccessNode::GetAccService()->GetAccessibleFor(currNode,
|
GetAccService()->GetAccessibleFor(currNode, getter_AddRefs(itemAcc));
|
||||||
getter_AddRefs(itemAcc));
|
|
||||||
if (!itemAcc ||
|
if (!itemAcc ||
|
||||||
State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) {
|
State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) {
|
||||||
(*aSetSize)--;
|
(*aSetSize)--;
|
||||||
|
@ -214,8 +213,7 @@ nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIDOMNode *aNode,
|
||||||
container->GetItemAtIndex(index, getter_AddRefs(item));
|
container->GetItemAtIndex(index, getter_AddRefs(item));
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessible> itemAcc;
|
nsCOMPtr<nsIAccessible> itemAcc;
|
||||||
nsAccessNode::GetAccService()->GetAccessibleFor(item,
|
GetAccService()->GetAccessibleFor(item, getter_AddRefs(itemAcc));
|
||||||
getter_AddRefs(itemAcc));
|
|
||||||
|
|
||||||
if (itemAcc) {
|
if (itemAcc) {
|
||||||
PRUint32 itemRole = Role(itemAcc);
|
PRUint32 itemRole = Role(itemAcc);
|
||||||
|
@ -236,8 +234,7 @@ nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIDOMNode *aNode,
|
||||||
container->GetItemAtIndex(index, getter_AddRefs(item));
|
container->GetItemAtIndex(index, getter_AddRefs(item));
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessible> itemAcc;
|
nsCOMPtr<nsIAccessible> itemAcc;
|
||||||
nsAccessNode::GetAccService()->GetAccessibleFor(item,
|
GetAccService()->GetAccessibleFor(item, getter_AddRefs(itemAcc));
|
||||||
getter_AddRefs(itemAcc));
|
|
||||||
|
|
||||||
if (itemAcc) {
|
if (itemAcc) {
|
||||||
PRUint32 itemRole = Role(itemAcc);
|
PRUint32 itemRole = Role(itemAcc);
|
||||||
|
@ -524,8 +521,7 @@ already_AddRefed<nsIAccessible>
|
||||||
nsAccUtils::GetMultiSelectableContainer(nsIDOMNode *aNode)
|
nsAccUtils::GetMultiSelectableContainer(nsIDOMNode *aNode)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
nsAccessNode::GetAccService()->GetAccessibleFor(aNode,
|
GetAccService()->GetAccessibleFor(aNode, getter_AddRefs(accessible));
|
||||||
getter_AddRefs(accessible));
|
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessible> container =
|
nsCOMPtr<nsIAccessible> container =
|
||||||
GetSelectableContainer(accessible, State(accessible));
|
GetSelectableContainer(accessible, State(accessible));
|
||||||
|
@ -573,25 +569,20 @@ nsAccUtils::GetTextAccessibleFromSelection(nsISelection *aSelection,
|
||||||
nsCOMPtr<nsIDOMNode> resultNode =
|
nsCOMPtr<nsIDOMNode> resultNode =
|
||||||
nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
|
nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
|
||||||
|
|
||||||
nsIAccessibilityService *accService = nsAccessNode::GetAccService();
|
|
||||||
|
|
||||||
// Get text accessible containing the result node.
|
// Get text accessible containing the result node.
|
||||||
while (resultNode) {
|
while (resultNode) {
|
||||||
// Make sure to get the correct starting node for selection events inside
|
// Make sure to get the correct starting node for selection events inside
|
||||||
// XBL content trees.
|
// XBL content trees.
|
||||||
nsCOMPtr<nsIDOMNode> relevantNode;
|
nsCOMPtr<nsIDOMNode> relevantNode;
|
||||||
nsresult rv = accService->
|
GetAccService()->GetRelevantContentNodeFor(resultNode,
|
||||||
GetRelevantContentNodeFor(resultNode, getter_AddRefs(relevantNode));
|
getter_AddRefs(relevantNode));
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return nsnull;
|
|
||||||
|
|
||||||
if (relevantNode)
|
if (relevantNode)
|
||||||
resultNode.swap(relevantNode);
|
resultNode.swap(relevantNode);
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> content = do_QueryInterface(resultNode);
|
nsCOMPtr<nsIContent> content = do_QueryInterface(resultNode);
|
||||||
if (!content || !content->IsNodeOfType(nsINode::eTEXT)) {
|
if (!content || !content->IsNodeOfType(nsINode::eTEXT)) {
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
accService->GetAccessibleFor(resultNode, getter_AddRefs(accessible));
|
GetAccService()->GetAccessibleFor(resultNode, getter_AddRefs(accessible));
|
||||||
if (accessible) {
|
if (accessible) {
|
||||||
nsIAccessibleText *textAcc = nsnull;
|
nsIAccessibleText *textAcc = nsnull;
|
||||||
CallQueryInterface(accessible, &textAcc);
|
CallQueryInterface(accessible, &textAcc);
|
||||||
|
@ -956,8 +947,7 @@ PRBool
|
||||||
nsAccUtils::IsNodeRelevant(nsIDOMNode *aNode)
|
nsAccUtils::IsNodeRelevant(nsIDOMNode *aNode)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMNode> relevantNode;
|
nsCOMPtr<nsIDOMNode> relevantNode;
|
||||||
nsAccessNode::GetAccService()->GetRelevantContentNodeFor(aNode,
|
GetAccService()->GetRelevantContentNodeFor(aNode, getter_AddRefs(relevantNode));
|
||||||
getter_AddRefs(relevantNode));
|
|
||||||
return aNode == relevantNode;
|
return aNode == relevantNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,12 +82,6 @@ nsAccessNodeHashtable nsAccessNode::gGlobalDocAccessibleCache;
|
||||||
|
|
||||||
nsApplicationAccessibleWrap *nsAccessNode::gApplicationAccessible = nsnull;
|
nsApplicationAccessibleWrap *nsAccessNode::gApplicationAccessible = nsnull;
|
||||||
|
|
||||||
nsIAccessibilityService*
|
|
||||||
nsAccessNode::GetAccService()
|
|
||||||
{
|
|
||||||
return nsAccessibilityService::GetAccessibilityService();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class nsAccessNode
|
* Class nsAccessNode
|
||||||
*/
|
*/
|
||||||
|
@ -157,15 +151,12 @@ nsAccessNode::Init()
|
||||||
if (presShell) {
|
if (presShell) {
|
||||||
nsCOMPtr<nsIDOMNode> docNode(do_QueryInterface(presShell->GetDocument()));
|
nsCOMPtr<nsIDOMNode> docNode(do_QueryInterface(presShell->GetDocument()));
|
||||||
if (docNode) {
|
if (docNode) {
|
||||||
nsIAccessibilityService *accService = GetAccService();
|
|
||||||
if (accService) {
|
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
accService->GetAccessibleInShell(docNode, presShell,
|
GetAccService()->GetAccessibleInShell(docNode, presShell,
|
||||||
getter_AddRefs(accessible));
|
getter_AddRefs(accessible));
|
||||||
docAccessible = do_QueryInterface(accessible);
|
docAccessible = do_QueryInterface(accessible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
NS_ASSERTION(docAccessible, "Cannot cache new nsAccessNode");
|
NS_ASSERTION(docAccessible, "Cannot cache new nsAccessNode");
|
||||||
if (!docAccessible) {
|
if (!docAccessible) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
@ -473,15 +464,13 @@ nsAccessNode::MakeAccessNode(nsIDOMNode *aNode, nsIAccessNode **aAccessNode)
|
||||||
{
|
{
|
||||||
*aAccessNode = nsnull;
|
*aAccessNode = nsnull;
|
||||||
|
|
||||||
nsIAccessibilityService *accService = GetAccService();
|
|
||||||
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessNode> accessNode;
|
nsCOMPtr<nsIAccessNode> accessNode;
|
||||||
accService->GetCachedAccessNode(aNode, mWeakShell, getter_AddRefs(accessNode));
|
GetAccService()->GetCachedAccessNode(aNode, mWeakShell,
|
||||||
|
getter_AddRefs(accessNode));
|
||||||
|
|
||||||
if (!accessNode) {
|
if (!accessNode) {
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
accService->GetAccessibleInWeakShell(aNode, mWeakShell,
|
GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell,
|
||||||
getter_AddRefs(accessible));
|
getter_AddRefs(accessible));
|
||||||
|
|
||||||
accessNode = do_QueryInterface(accessible);
|
accessNode = do_QueryInterface(accessible);
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
#include "nsIStringBundle.h"
|
#include "nsIStringBundle.h"
|
||||||
#include "nsWeakReference.h"
|
#include "nsWeakReference.h"
|
||||||
#include "nsInterfaceHashtable.h"
|
#include "nsInterfaceHashtable.h"
|
||||||
#include "nsIAccessibilityService.h"
|
#include "nsAccessibilityService.h"
|
||||||
|
|
||||||
class nsIPresShell;
|
class nsIPresShell;
|
||||||
class nsPresContext;
|
class nsPresContext;
|
||||||
|
@ -145,7 +145,7 @@ class nsAccessNode: public nsIAccessNode
|
||||||
already_AddRefed<nsRootAccessible> GetRootAccessible();
|
already_AddRefed<nsRootAccessible> GetRootAccessible();
|
||||||
|
|
||||||
static nsIDOMNode *gLastFocusedNode;
|
static nsIDOMNode *gLastFocusedNode;
|
||||||
static nsIAccessibilityService* GetAccService();
|
|
||||||
already_AddRefed<nsIDOMNode> GetCurrentFocus();
|
already_AddRefed<nsIDOMNode> GetCurrentFocus();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1173,26 +1173,6 @@ nsAccessibilityService::GetAttachedAccessibleFor(nsIDOMNode *aNode,
|
||||||
return GetAccessibleFor(aNode, aAccessible);
|
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<nsIWebNavigation> webNav(do_GetInterface(aWin));
|
|
||||||
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(webNav));
|
|
||||||
if (!docShell)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIPresShell> presShell;
|
|
||||||
docShell->GetPresShell(getter_AddRefs(presShell));
|
|
||||||
return GetAccessibleInShell(aNode, presShell, aAccessible);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode,
|
NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode,
|
||||||
nsIPresShell *aPresShell,
|
nsIPresShell *aPresShell,
|
||||||
nsIAccessible **aAccessible)
|
nsIAccessible **aAccessible)
|
||||||
|
@ -1209,7 +1189,8 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode,
|
||||||
nsnull, &isHiddenUnused, aAccessible);
|
nsnull, &isHiddenUnused, aAccessible);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode,
|
nsresult
|
||||||
|
nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode,
|
||||||
nsIWeakReference *aWeakShell,
|
nsIWeakReference *aWeakShell,
|
||||||
nsIAccessible **aAccessible)
|
nsIAccessible **aAccessible)
|
||||||
{
|
{
|
||||||
|
@ -1272,7 +1253,8 @@ static PRBool HasRelatedContent(nsIContent *aContent)
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
|
nsresult
|
||||||
|
nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
|
||||||
nsIPresShell *aPresShell,
|
nsIPresShell *aPresShell,
|
||||||
nsIWeakReference *aWeakShell,
|
nsIWeakReference *aWeakShell,
|
||||||
nsIFrame *aFrameHint,
|
nsIFrame *aFrameHint,
|
||||||
|
@ -2054,37 +2036,26 @@ nsAccessibilityService::InvalidateSubtreeFor(nsIPresShell *aShell,
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return accessibility service; creating one if necessary.
|
||||||
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
nsAccessibilityService::GetAccessibilityService(nsIAccessibilityService** aResult)
|
NS_GetAccessibilityService(nsIAccessibilityService** aResult)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
|
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
|
||||||
*aResult = nsnull;
|
*aResult = nsnull;
|
||||||
|
|
||||||
if (!gAccessibilityService) {
|
if (!nsAccessibilityService::gAccessibilityService) {
|
||||||
gAccessibilityService = new nsAccessibilityService();
|
nsAccessibilityService::gAccessibilityService = new nsAccessibilityService();
|
||||||
NS_ENSURE_TRUE(gAccessibilityService, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(nsAccessibilityService::gAccessibilityService, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
gIsShutdown = PR_FALSE;
|
nsAccessibilityService::gIsShutdown = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_ADDREF(*aResult = gAccessibilityService);
|
NS_ADDREF(*aResult = nsAccessibilityService::gAccessibilityService);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIAccessibilityService*
|
|
||||||
nsAccessibilityService::GetAccessibilityService()
|
|
||||||
{
|
|
||||||
NS_ASSERTION(!gIsShutdown,
|
|
||||||
"Going to deal with shutdown accessibility service!");
|
|
||||||
return gAccessibilityService;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
NS_GetAccessibilityService(nsIAccessibilityService** aResult)
|
|
||||||
{
|
|
||||||
return nsAccessibilityService::GetAccessibilityService(aResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsAccessibilityService::GetAccessibleForDeckChildren(nsIDOMNode *aNode, nsIAccessible** aAccessible)
|
nsAccessibilityService::GetAccessibleForDeckChildren(nsIDOMNode *aNode, nsIAccessible** aAccessible)
|
||||||
{
|
{
|
||||||
|
|
|
@ -81,21 +81,35 @@ public:
|
||||||
static nsresult GetShellFromNode(nsIDOMNode *aNode,
|
static nsresult GetShellFromNode(nsIDOMNode *aNode,
|
||||||
nsIWeakReference **weakShell);
|
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.
|
* Indicates whether accessibility service was shutdown.
|
||||||
*/
|
*/
|
||||||
static PRBool gIsShutdown;
|
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:
|
private:
|
||||||
/**
|
/**
|
||||||
* Return presentation shell, DOM node for the given frame.
|
* Return presentation shell, DOM node for the given frame.
|
||||||
|
@ -170,10 +184,24 @@ private:
|
||||||
*/
|
*/
|
||||||
void ProcessDocLoadEvent(nsIWebProgress *aWebProgress, PRUint32 aEventType);
|
void ProcessDocLoadEvent(nsIWebProgress *aWebProgress, PRUint32 aEventType);
|
||||||
|
|
||||||
|
friend nsAccessibilityService* GetAccService();
|
||||||
|
|
||||||
|
friend nsresult NS_GetAccessibilityService(nsIAccessibilityService** aResult);
|
||||||
|
|
||||||
|
|
||||||
NS_DECL_RUNNABLEMETHOD_ARG2(nsAccessibilityService, ProcessDocLoadEvent,
|
NS_DECL_RUNNABLEMETHOD_ARG2(nsAccessibilityService, ProcessDocLoadEvent,
|
||||||
nsCOMPtr<nsIWebProgress>, PRUint32)
|
nsCOMPtr<nsIWebProgress>, PRUint32)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the accessibility service instance. (Handy global function)
|
||||||
|
*/
|
||||||
|
inline nsAccessibilityService*
|
||||||
|
GetAccService()
|
||||||
|
{
|
||||||
|
return nsAccessibilityService::gAccessibilityService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map nsIAccessibleRole constants to strings. Used by
|
* Map nsIAccessibleRole constants to strings. Used by
|
||||||
* nsIAccessibleRetrieval::getStringRole() method.
|
* nsIAccessibleRetrieval::getStringRole() method.
|
||||||
|
|
|
@ -3096,13 +3096,13 @@ nsAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError)
|
||||||
already_AddRefed<nsIAccessible>
|
already_AddRefed<nsIAccessible>
|
||||||
nsAccessible::GetFirstAvailableAccessible(nsIDOMNode *aStartNode)
|
nsAccessible::GetFirstAvailableAccessible(nsIDOMNode *aStartNode)
|
||||||
{
|
{
|
||||||
nsIAccessibilityService *accService = GetAccService();
|
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
nsCOMPtr<nsIDOMTreeWalker> walker;
|
nsCOMPtr<nsIDOMTreeWalker> walker;
|
||||||
nsCOMPtr<nsIDOMNode> currentNode(aStartNode);
|
nsCOMPtr<nsIDOMNode> currentNode(aStartNode);
|
||||||
|
|
||||||
while (currentNode) {
|
while (currentNode) {
|
||||||
accService->GetAccessibleInWeakShell(currentNode, mWeakShell, getter_AddRefs(accessible)); // AddRef'd
|
GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell,
|
||||||
|
getter_AddRefs(accessible));
|
||||||
if (accessible)
|
if (accessible)
|
||||||
return accessible.forget();
|
return accessible.forget();
|
||||||
|
|
||||||
|
|
|
@ -46,11 +46,11 @@
|
||||||
#include "nsIContent.h"
|
#include "nsIContent.h"
|
||||||
#include "nsIDOMXULElement.h"
|
#include "nsIDOMXULElement.h"
|
||||||
#include "nsIPresShell.h"
|
#include "nsIPresShell.h"
|
||||||
|
#include "nsAccessibilityService.h"
|
||||||
#include "nsWeakReference.h"
|
#include "nsWeakReference.h"
|
||||||
|
|
||||||
nsAccessibleTreeWalker::nsAccessibleTreeWalker(nsIWeakReference* aPresShell, nsIDOMNode* aNode, PRBool aWalkAnonContent):
|
nsAccessibleTreeWalker::nsAccessibleTreeWalker(nsIWeakReference* aPresShell, nsIDOMNode* aNode, PRBool aWalkAnonContent):
|
||||||
mWeakShell(aPresShell),
|
mWeakShell(aPresShell),
|
||||||
mAccService(do_GetService("@mozilla.org/accessibilityService;1")),
|
|
||||||
mWalkAnonContent(aWalkAnonContent)
|
mWalkAnonContent(aWalkAnonContent)
|
||||||
{
|
{
|
||||||
mState.domNode = aNode;
|
mState.domNode = aNode;
|
||||||
|
@ -294,14 +294,10 @@ nsAccessibleTreeWalker::WalkFrames()
|
||||||
*/
|
*/
|
||||||
PRBool nsAccessibleTreeWalker::GetAccessible()
|
PRBool nsAccessibleTreeWalker::GetAccessible()
|
||||||
{
|
{
|
||||||
if (!mAccService) {
|
|
||||||
return PR_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
mState.accessible = nsnull;
|
mState.accessible = nsnull;
|
||||||
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
|
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
|
||||||
|
|
||||||
mAccService->GetAccessible(mState.domNode, presShell, mWeakShell,
|
GetAccService()->GetAccessible(mState.domNode, presShell, mWeakShell,
|
||||||
mState.frame.GetFrame(), &mState.isHidden,
|
mState.frame.GetFrame(), &mState.isHidden,
|
||||||
getter_AddRefs(mState.accessible));
|
getter_AddRefs(mState.accessible));
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@
|
||||||
#include "nsIAccessible.h"
|
#include "nsIAccessible.h"
|
||||||
#include "nsIDOMNode.h"
|
#include "nsIDOMNode.h"
|
||||||
#include "nsIDOMNodeList.h"
|
#include "nsIDOMNodeList.h"
|
||||||
#include "nsIAccessibilityService.h"
|
|
||||||
#include "nsIWeakReference.h"
|
#include "nsIWeakReference.h"
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
|
|
||||||
|
@ -132,7 +131,6 @@ protected:
|
||||||
void GetNextDOMNode();
|
void GetNextDOMNode();
|
||||||
|
|
||||||
nsCOMPtr<nsIWeakReference> mWeakShell;
|
nsCOMPtr<nsIWeakReference> mWeakShell;
|
||||||
nsCOMPtr<nsIAccessibilityService> mAccService;
|
|
||||||
PRBool mWalkAnonContent;
|
PRBool mWalkAnonContent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2113,9 +2113,6 @@ nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
|
||||||
nsCOMPtr<nsIDOMNode> currentNode(aNode), parentNode;
|
nsCOMPtr<nsIDOMNode> currentNode(aNode), parentNode;
|
||||||
nsCOMPtr<nsIAccessNode> accessNode;
|
nsCOMPtr<nsIAccessNode> accessNode;
|
||||||
|
|
||||||
nsIAccessibilityService *accService = GetAccService();
|
|
||||||
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
currentNode->GetParentNode(getter_AddRefs(parentNode));
|
currentNode->GetParentNode(getter_AddRefs(parentNode));
|
||||||
currentNode = parentNode;
|
currentNode = parentNode;
|
||||||
|
@ -2126,11 +2123,12 @@ nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> relevantNode;
|
nsCOMPtr<nsIDOMNode> relevantNode;
|
||||||
if (NS_SUCCEEDED(accService->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
|
if (NS_SUCCEEDED(GetAccService()->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
|
||||||
currentNode = relevantNode;
|
currentNode = relevantNode;
|
||||||
}
|
}
|
||||||
if (aCanCreate) {
|
if (aCanCreate) {
|
||||||
accService->GetAccessibleInWeakShell(currentNode, mWeakShell, aAccessible);
|
GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell,
|
||||||
|
aAccessible);
|
||||||
}
|
}
|
||||||
else { // Only return cached accessibles, don't create anything
|
else { // Only return cached accessibles, don't create anything
|
||||||
nsCOMPtr<nsIAccessNode> accessNode;
|
nsCOMPtr<nsIAccessNode> accessNode;
|
||||||
|
|
|
@ -89,11 +89,10 @@ nsRelUtils::AddTargetFromContent(PRUint32 aRelationType,
|
||||||
if (!aContent)
|
if (!aContent)
|
||||||
return NS_OK_NO_RELATION_TARGET;
|
return NS_OK_NO_RELATION_TARGET;
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessibilityService> accService = nsAccessNode::GetAccService();
|
|
||||||
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
accService->GetAccessibleFor(node, getter_AddRefs(accessible));
|
GetAccService()->GetAccessibleFor(node, getter_AddRefs(accessible));
|
||||||
return AddTarget(aRelationType, aRelation, accessible);
|
return AddTarget(aRelationType, aRelation, accessible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,14 +152,14 @@ nsTextEquivUtils::AppendTextEquivFromContent(nsIAccessible *aInitiatorAcc,
|
||||||
nsIFrame *frame = aContent->GetPrimaryFrame();
|
nsIFrame *frame = aContent->GetPrimaryFrame();
|
||||||
PRBool isVisible = frame && frame->GetStyleVisibility()->IsVisible();
|
PRBool isVisible = frame && frame->GetStyleVisibility()->IsVisible();
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv = NS_ERROR_FAILURE;
|
||||||
PRBool goThroughDOMSubtree = PR_TRUE;
|
PRBool goThroughDOMSubtree = PR_TRUE;
|
||||||
|
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
rv = nsAccessNode::GetAccService()->
|
GetAccService()->GetAccessibleInShell(DOMNode, shell,
|
||||||
GetAccessibleInShell(DOMNode, shell, getter_AddRefs(accessible));
|
getter_AddRefs(accessible));
|
||||||
if (NS_SUCCEEDED(rv) && accessible) {
|
if (accessible) {
|
||||||
rv = AppendFromAccessible(accessible, aString);
|
rv = AppendFromAccessible(accessible, aString);
|
||||||
goThroughDOMSubtree = PR_FALSE;
|
goThroughDOMSubtree = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,8 +110,8 @@ void nsHTMLSelectableAccessible::iterator::CalcSelectionCount(PRInt32 *aSelectio
|
||||||
(*aSelectionCount)++;
|
(*aSelectionCount)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibilityService *aAccService,
|
void
|
||||||
nsIMutableArray *aSelectedAccessibles,
|
nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles,
|
||||||
nsPresContext *aContext)
|
nsPresContext *aContext)
|
||||||
{
|
{
|
||||||
PRBool isSelected = PR_FALSE;
|
PRBool isSelected = PR_FALSE;
|
||||||
|
@ -121,7 +121,8 @@ void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibil
|
||||||
mOption->GetSelected(&isSelected);
|
mOption->GetSelected(&isSelected);
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
nsCOMPtr<nsIDOMNode> optionNode(do_QueryInterface(mOption));
|
nsCOMPtr<nsIDOMNode> optionNode(do_QueryInterface(mOption));
|
||||||
aAccService->GetAccessibleInWeakShell(optionNode, mWeakShell, getter_AddRefs(tempAccess));
|
GetAccService()->GetAccessibleInWeakShell(optionNode, mWeakShell,
|
||||||
|
getter_AddRefs(tempAccess));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,8 +130,8 @@ void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibil
|
||||||
aSelectedAccessibles->AppendElement(static_cast<nsISupports*>(tempAccess), PR_FALSE);
|
aSelectedAccessibles->AppendElement(static_cast<nsISupports*>(tempAccess), PR_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex,
|
PRBool
|
||||||
nsIAccessibilityService *aAccService,
|
nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex,
|
||||||
nsPresContext *aContext,
|
nsPresContext *aContext,
|
||||||
nsIAccessible **aAccessible)
|
nsIAccessible **aAccessible)
|
||||||
{
|
{
|
||||||
|
@ -143,7 +144,7 @@ PRBool nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIn
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
if (mSelCount == aIndex) {
|
if (mSelCount == aIndex) {
|
||||||
nsCOMPtr<nsIDOMNode> optionNode(do_QueryInterface(mOption));
|
nsCOMPtr<nsIDOMNode> optionNode(do_QueryInterface(mOption));
|
||||||
aAccService->GetAccessibleInWeakShell(optionNode, mWeakShell, aAccessible);
|
GetAccService()->GetAccessibleInWeakShell(optionNode, mWeakShell, aAccessible);
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
mSelCount++;
|
mSelCount++;
|
||||||
|
@ -201,10 +202,6 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectedChildren(nsIArray **_retval
|
||||||
{
|
{
|
||||||
*_retval = nsnull;
|
*_retval = nsnull;
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
|
|
||||||
if (!accService)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIMutableArray> selectedAccessibles =
|
nsCOMPtr<nsIMutableArray> selectedAccessibles =
|
||||||
do_CreateInstance(NS_ARRAY_CONTRACTID);
|
do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||||
NS_ENSURE_STATE(selectedAccessibles);
|
NS_ENSURE_STATE(selectedAccessibles);
|
||||||
|
@ -215,7 +212,7 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectedChildren(nsIArray **_retval
|
||||||
|
|
||||||
nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
|
nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
|
||||||
while (iter.Advance())
|
while (iter.Advance())
|
||||||
iter.AddAccessibleIfSelected(accService, selectedAccessibles, context);
|
iter.AddAccessibleIfSelected(selectedAccessibles, context);
|
||||||
|
|
||||||
PRUint32 uLength = 0;
|
PRUint32 uLength = 0;
|
||||||
selectedAccessibles->GetLength(&uLength);
|
selectedAccessibles->GetLength(&uLength);
|
||||||
|
@ -231,17 +228,13 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccess
|
||||||
{
|
{
|
||||||
*_retval = nsnull;
|
*_retval = nsnull;
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
|
|
||||||
if (!accService)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
nsPresContext *context = GetPresContext();
|
nsPresContext *context = GetPresContext();
|
||||||
if (!context)
|
if (!context)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
|
nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
|
||||||
while (iter.Advance())
|
while (iter.Advance())
|
||||||
if (iter.GetAccessibleIfSelected(aIndex, accService, context, _retval))
|
if (iter.GetAccessibleIfSelected(aIndex, context, _retval))
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
// No matched item found
|
// No matched item found
|
||||||
|
@ -426,7 +419,6 @@ nsHTMLSelectListAccessible::CacheOptSiblings(nsIContent *aParentContent)
|
||||||
nsHTMLSelectOptionAccessible::nsHTMLSelectOptionAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
|
nsHTMLSelectOptionAccessible::nsHTMLSelectOptionAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
|
||||||
nsHyperTextAccessibleWrap(aDOMNode, aShell)
|
nsHyperTextAccessibleWrap(aDOMNode, aShell)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
|
|
||||||
nsCOMPtr<nsIDOMNode> parentNode;
|
nsCOMPtr<nsIDOMNode> parentNode;
|
||||||
aDOMNode->GetParentNode(getter_AddRefs(parentNode));
|
aDOMNode->GetParentNode(getter_AddRefs(parentNode));
|
||||||
nsCOMPtr<nsIAccessible> parentAccessible;
|
nsCOMPtr<nsIAccessible> parentAccessible;
|
||||||
|
@ -436,7 +428,8 @@ nsHyperTextAccessibleWrap(aDOMNode, aShell)
|
||||||
// GetParent would normally return. This is because the
|
// GetParent would normally return. This is because the
|
||||||
// nsHTMLComboboxListAccessible is inserted into the accessible hierarchy
|
// nsHTMLComboboxListAccessible is inserted into the accessible hierarchy
|
||||||
// where there is no DOM node for it.
|
// 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 (parentAccessible) {
|
||||||
if (nsAccUtils::RoleInternal(parentAccessible) ==
|
if (nsAccUtils::RoleInternal(parentAccessible) ==
|
||||||
nsIAccessibleRole::ROLE_COMBOBOX) {
|
nsIAccessibleRole::ROLE_COMBOBOX) {
|
||||||
|
@ -839,16 +832,13 @@ nsIContent* nsHTMLSelectOptionAccessible::GetSelectState(PRUint32* aState,
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> selectNode(do_QueryInterface(content));
|
nsCOMPtr<nsIDOMNode> selectNode(do_QueryInterface(content));
|
||||||
if (selectNode) {
|
if (selectNode) {
|
||||||
nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
|
|
||||||
if (accService) {
|
|
||||||
nsCOMPtr<nsIAccessible> selAcc;
|
nsCOMPtr<nsIAccessible> selAcc;
|
||||||
accService->GetAccessibleFor(selectNode, getter_AddRefs(selAcc));
|
GetAccService()->GetAccessibleFor(selectNode, getter_AddRefs(selAcc));
|
||||||
if (selAcc) {
|
if (selAcc) {
|
||||||
selAcc->GetState(aState, aExtraState);
|
selAcc->GetState(aState, aExtraState);
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nsnull;
|
return nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1026,13 +1016,12 @@ nsHTMLComboboxAccessible::GetFocusedOptionAccessible()
|
||||||
}
|
}
|
||||||
nsCOMPtr<nsIDOMNode> focusedOptionNode;
|
nsCOMPtr<nsIDOMNode> focusedOptionNode;
|
||||||
nsHTMLSelectOptionAccessible::GetFocusedOptionNode(mDOMNode, getter_AddRefs(focusedOptionNode));
|
nsHTMLSelectOptionAccessible::GetFocusedOptionNode(mDOMNode, getter_AddRefs(focusedOptionNode));
|
||||||
nsIAccessibilityService *accService = GetAccService();
|
if (!focusedOptionNode) {
|
||||||
if (!focusedOptionNode || !accService) {
|
|
||||||
return nsnull;
|
return nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIAccessible *optionAccessible;
|
nsIAccessible *optionAccessible;
|
||||||
accService->GetAccessibleInWeakShell(focusedOptionNode, mWeakShell,
|
GetAccService()->GetAccessibleInWeakShell(focusedOptionNode, mWeakShell,
|
||||||
&optionAccessible);
|
&optionAccessible);
|
||||||
return optionAccessible;
|
return optionAccessible;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
#include "nsIDOMHTMLOptionsCollection.h"
|
#include "nsIDOMHTMLOptionsCollection.h"
|
||||||
#include "nsIDOMHTMLOptionElement.h"
|
#include "nsIDOMHTMLOptionElement.h"
|
||||||
#include "nsIDOMNode.h"
|
#include "nsIDOMNode.h"
|
||||||
#include "nsIAccessibilityService.h"
|
|
||||||
#include "nsAccessibleTreeWalker.h"
|
#include "nsAccessibleTreeWalker.h"
|
||||||
|
|
||||||
class nsIMutableArray;
|
class nsIMutableArray;
|
||||||
|
@ -104,10 +103,10 @@ protected:
|
||||||
|
|
||||||
void CalcSelectionCount(PRInt32 *aSelectionCount);
|
void CalcSelectionCount(PRInt32 *aSelectionCount);
|
||||||
void Select(PRBool aSelect);
|
void Select(PRBool aSelect);
|
||||||
void AddAccessibleIfSelected(nsIAccessibilityService *aAccService,
|
void AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles,
|
||||||
nsIMutableArray *aSelectedAccessibles,
|
|
||||||
nsPresContext *aContext);
|
nsPresContext *aContext);
|
||||||
PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsIAccessibilityService *aAccService, nsPresContext *aContext, nsIAccessible **_retval);
|
PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsPresContext *aContext,
|
||||||
|
nsIAccessible **aAccessible);
|
||||||
|
|
||||||
PRBool Advance();
|
PRBool Advance();
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
#include "nsAccessNodeWrap.h"
|
#include "nsAccessNodeWrap.h"
|
||||||
#include "ISimpleDOMNode_i.c"
|
#include "ISimpleDOMNode_i.c"
|
||||||
#include "nsAccessibilityAtoms.h"
|
#include "nsAccessibilityAtoms.h"
|
||||||
#include "nsIAccessibilityService.h"
|
|
||||||
#include "nsIAccessible.h"
|
#include "nsIAccessible.h"
|
||||||
#include "nsAttrName.h"
|
#include "nsAttrName.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
|
@ -411,13 +410,10 @@ ISimpleDOMNode* nsAccessNodeWrap::MakeAccessNode(nsIDOMNode *node)
|
||||||
if (!doc)
|
if (!doc)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
|
|
||||||
if (!accService)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ISimpleDOMNode *iNode = NULL;
|
ISimpleDOMNode *iNode = NULL;
|
||||||
nsCOMPtr<nsIAccessible> nsAcc;
|
nsCOMPtr<nsIAccessible> nsAcc;
|
||||||
accService->GetAccessibleInWeakShell(node, mWeakShell, getter_AddRefs(nsAcc));
|
GetAccService()->GetAccessibleInWeakShell(node, mWeakShell,
|
||||||
|
getter_AddRefs(nsAcc));
|
||||||
if (nsAcc) {
|
if (nsAcc) {
|
||||||
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(nsAcc));
|
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(nsAcc));
|
||||||
NS_ASSERTION(accessNode, "nsIAccessible impl does not inherit from nsIAccessNode");
|
NS_ASSERTION(accessNode, "nsIAccessible impl does not inherit from nsIAccessNode");
|
||||||
|
|
|
@ -125,7 +125,6 @@ nsXFormsAccessible::CacheSelectChildren(nsIDOMNode *aContainerNode)
|
||||||
nsCOMPtr<nsIAccessible> accessible;
|
nsCOMPtr<nsIAccessible> accessible;
|
||||||
nsRefPtr<nsAccessible> acc;
|
nsRefPtr<nsAccessible> acc;
|
||||||
|
|
||||||
PRUint32 childLength = 0;
|
|
||||||
for (PRUint32 index = 0; index < length; index++) {
|
for (PRUint32 index = 0; index < length; index++) {
|
||||||
nsCOMPtr<nsIDOMNode> child;
|
nsCOMPtr<nsIDOMNode> child;
|
||||||
children->Item(index, getter_AddRefs(child));
|
children->Item(index, getter_AddRefs(child));
|
||||||
|
|
|
@ -120,9 +120,6 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
|
|
||||||
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIMutableArray> selectedAccessibles =
|
nsCOMPtr<nsIMutableArray> selectedAccessibles =
|
||||||
do_CreateInstance(NS_ARRAY_CONTRACTID);
|
do_CreateInstance(NS_ARRAY_CONTRACTID);
|
||||||
NS_ENSURE_STATE(selectedAccessibles);
|
NS_ENSURE_STATE(selectedAccessibles);
|
||||||
|
@ -138,7 +135,7 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre
|
||||||
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
|
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
|
||||||
xulMultiSelect->GetSelectedItem(index, getter_AddRefs(selectedItem));
|
xulMultiSelect->GetSelectedItem(index, getter_AddRefs(selectedItem));
|
||||||
nsCOMPtr<nsIDOMNode> selectedNode(do_QueryInterface(selectedItem));
|
nsCOMPtr<nsIDOMNode> selectedNode(do_QueryInterface(selectedItem));
|
||||||
accService->GetAccessibleInWeakShell(selectedNode, mWeakShell,
|
GetAccService()->GetAccessibleInWeakShell(selectedNode, mWeakShell,
|
||||||
getter_AddRefs(selectedAccessible));
|
getter_AddRefs(selectedAccessible));
|
||||||
if (selectedAccessible)
|
if (selectedAccessible)
|
||||||
selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE);
|
selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE);
|
||||||
|
@ -149,7 +146,7 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre
|
||||||
mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
|
mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
|
||||||
nsCOMPtr<nsIDOMNode> selectedNode(do_QueryInterface(selectedItem));
|
nsCOMPtr<nsIDOMNode> selectedNode(do_QueryInterface(selectedItem));
|
||||||
if(selectedNode) {
|
if(selectedNode) {
|
||||||
accService->GetAccessibleInWeakShell(selectedNode, mWeakShell,
|
GetAccService()->GetAccessibleInWeakShell(selectedNode, mWeakShell,
|
||||||
getter_AddRefs(selectedAccessible));
|
getter_AddRefs(selectedAccessible));
|
||||||
if (selectedAccessible)
|
if (selectedAccessible)
|
||||||
selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE);
|
selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE);
|
||||||
|
@ -183,15 +180,13 @@ NS_IMETHODIMP nsXULSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccessi
|
||||||
mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
|
mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
|
||||||
|
|
||||||
if (selectedItem) {
|
if (selectedItem) {
|
||||||
nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
|
GetAccService()->GetAccessibleInWeakShell(selectedItem, mWeakShell,
|
||||||
if (accService) {
|
aAccessible);
|
||||||
accService->GetAccessibleInWeakShell(selectedItem, mWeakShell, aAccessible);
|
|
||||||
if (*aAccessible) {
|
if (*aAccessible) {
|
||||||
NS_ADDREF(*aAccessible);
|
NS_ADDREF(*aAccessible);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -354,8 +349,8 @@ nsXULMenuitemAccessible::GetStateInternal(PRUint32 *aState,
|
||||||
grandParentAcc->GetState(&grandParentState, &grandParentExtState);
|
grandParentAcc->GetState(&grandParentState, &grandParentExtState);
|
||||||
*aState &= ~(nsIAccessibleStates::STATE_OFFSCREEN |
|
*aState &= ~(nsIAccessibleStates::STATE_OFFSCREEN |
|
||||||
nsIAccessibleStates::STATE_INVISIBLE);
|
nsIAccessibleStates::STATE_INVISIBLE);
|
||||||
*aState |= grandParentState & nsIAccessibleStates::STATE_OFFSCREEN |
|
*aState |= (grandParentState & nsIAccessibleStates::STATE_OFFSCREEN) |
|
||||||
grandParentState & nsIAccessibleStates::STATE_INVISIBLE;
|
(grandParentState & nsIAccessibleStates::STATE_INVISIBLE);
|
||||||
if (aExtraState) {
|
if (aExtraState) {
|
||||||
*aExtraState |=
|
*aExtraState |=
|
||||||
grandParentExtState & nsIAccessibleStates::EXT_STATE_OPAQUE;
|
grandParentExtState & nsIAccessibleStates::EXT_STATE_OPAQUE;
|
||||||
|
|
|
@ -40,6 +40,10 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tabpanels {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
%ifdef MOZ_WIDGET_GTK2
|
%ifdef MOZ_WIDGET_GTK2
|
||||||
/* Favicons override the "images-in-menus" metric in xul.css */
|
/* Favicons override the "images-in-menus" metric in xul.css */
|
||||||
.alltabs-item > .menu-iconic-left {
|
.alltabs-item > .menu-iconic-left {
|
||||||
|
|
|
@ -1335,6 +1335,14 @@ SessionStoreService.prototype = {
|
||||||
catch (ex) { debug(ex); }
|
catch (ex) { debug(ex); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aEntry.docIdentifier) {
|
||||||
|
entry.docIdentifier = aEntry.docIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aEntry.stateData) {
|
||||||
|
entry.stateData = aEntry.stateData;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(aEntry instanceof Ci.nsISHContainer)) {
|
if (!(aEntry instanceof Ci.nsISHContainer)) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -2038,9 +2046,11 @@ SessionStoreService.prototype = {
|
||||||
delete this._windows[aWindow.__SSi]._restoring;
|
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: {} };
|
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
|
* @param aIdMap
|
||||||
* Hash for ensuring unique frame IDs
|
* 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;
|
var _this = this;
|
||||||
while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) {
|
while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) {
|
||||||
aTabs.shift(); // this tab got removed before being completely restored
|
aTabs.shift(); // this tab got removed before being completely restored
|
||||||
|
@ -2090,7 +2101,8 @@ SessionStoreService.prototype = {
|
||||||
//XXXzpao Wallpaper patch for bug 514751
|
//XXXzpao Wallpaper patch for bug 514751
|
||||||
if (!tabData.entries[i].url)
|
if (!tabData.entries[i].url)
|
||||||
continue;
|
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
|
// 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);
|
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
|
* Hash for ensuring unique frame IDs
|
||||||
* @returns nsISHEntry
|
* @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"].
|
var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
|
||||||
createInstance(Ci.nsISHEntry);
|
createInstance(Ci.nsISHEntry);
|
||||||
|
|
||||||
|
@ -2196,6 +2212,10 @@ SessionStoreService.prototype = {
|
||||||
shEntry.ID = id;
|
shEntry.ID = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aEntry.stateData) {
|
||||||
|
shEntry.stateData = aEntry.stateData;
|
||||||
|
}
|
||||||
|
|
||||||
if (aEntry.scroll) {
|
if (aEntry.scroll) {
|
||||||
var scrollPos = (aEntry.scroll || "0,0").split(",");
|
var scrollPos = (aEntry.scroll || "0,0").split(",");
|
||||||
scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
|
scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
|
||||||
|
@ -2216,6 +2236,28 @@ SessionStoreService.prototype = {
|
||||||
shEntry.postData = stream;
|
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
|
if (aEntry.owner_b64) { // Firefox 3
|
||||||
var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
|
var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
|
||||||
createInstance(Ci.nsIStringInputStream);
|
createInstance(Ci.nsIStringInputStream);
|
||||||
|
@ -2237,7 +2279,8 @@ SessionStoreService.prototype = {
|
||||||
//XXXzpao Wallpaper patch for bug 514751
|
//XXXzpao Wallpaper patch for bug 514751
|
||||||
if (!aEntry.children[i].url)
|
if (!aEntry.children[i].url)
|
||||||
continue;
|
continue;
|
||||||
shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap), i);
|
shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap,
|
||||||
|
aDocIdentMap), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@ _BROWSER_TEST_FILES = \
|
||||||
browser_491577.js \
|
browser_491577.js \
|
||||||
browser_493467.js \
|
browser_493467.js \
|
||||||
browser_495495.js \
|
browser_495495.js \
|
||||||
|
browser_500328.js \
|
||||||
browser_506482.js \
|
browser_506482.js \
|
||||||
browser_514751.js \
|
browser_514751.js \
|
||||||
browser_522545.js \
|
browser_522545.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 <justin.lebar@gmail.com>
|
||||||
|
* 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);
|
||||||
|
}
|
|
@ -1111,11 +1111,6 @@ statusbarpanel#statusbar-display {
|
||||||
list-style-image: url("chrome://global/skin/icons/notloading_16.png");
|
list-style-image: url("chrome://global/skin/icons/notloading_16.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tabpanels {
|
|
||||||
-moz-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tabs */
|
/* Tabs */
|
||||||
.tabbrowser-tab {
|
.tabbrowser-tab {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
|
|
|
@ -399,7 +399,6 @@ menubutton:not([disabled="true"]):hover:active {
|
||||||
-moz-image-region: rect(23px, 36px, 46px, 0px);
|
-moz-image-region: rect(23px, 36px, 46px, 0px);
|
||||||
}
|
}
|
||||||
#back-button:hover:active:not([disabled]),
|
#back-button:hover:active:not([disabled]),
|
||||||
#back-button[buttondown="true"]:not([disabled]),
|
|
||||||
#back-button[open="true"] {
|
#back-button[open="true"] {
|
||||||
-moz-image-region: rect(46px, 36px, 69px, 0px);
|
-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);
|
-moz-image-region: rect(23px, 72px, 46px, 36px);
|
||||||
}
|
}
|
||||||
#forward-button:hover:active:not([disabled]),
|
#forward-button:hover:active:not([disabled]),
|
||||||
#forward-button[buttondown="true"]:not([disabled]),
|
|
||||||
#forward-button[open="true"] {
|
#forward-button[open="true"] {
|
||||||
-moz-image-region: rect(46px, 72px, 69px, 36px);
|
-moz-image-region: rect(46px, 72px, 69px, 36px);
|
||||||
}
|
}
|
||||||
|
@ -1591,10 +1589,6 @@ tabbrowser > tabbox {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
tabbrowser > tabbox > tabpanels {
|
|
||||||
-moz-appearance: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tab Drag and Drop
|
* Tab Drag and Drop
|
||||||
*/
|
*/
|
||||||
|
@ -1782,10 +1776,6 @@ tabbrowser > tabbox > tabpanels {
|
||||||
list-style-image: url("chrome://global/skin/icons/closetab-active.png");
|
list-style-image: url("chrome://global/skin/icons/closetab-active.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
tabpanels.plain {
|
|
||||||
background-color: #fff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bookmarks toolbar */
|
/* Bookmarks toolbar */
|
||||||
.toolbar-drop-indicator {
|
.toolbar-drop-indicator {
|
||||||
list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
|
list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);
|
||||||
|
|
|
@ -1177,10 +1177,6 @@ statusbarpanel#statusbar-display {
|
||||||
border-bottom: 1px solid threedshadow;
|
border-bottom: 1px solid threedshadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
tabpanels {
|
|
||||||
-moz-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tabbrowser-tab focus ring */
|
/* tabbrowser-tab focus ring */
|
||||||
.tabbrowser-tab > .tab-text {
|
.tabbrowser-tab > .tab-text {
|
||||||
border: 1px dotted transparent;
|
border: 1px dotted transparent;
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
interface nsIURI;
|
interface nsIURI;
|
||||||
interface nsIChannel;
|
interface nsIChannel;
|
||||||
|
|
||||||
[scriptable, uuid(c0dbfd5e-b7ae-4c18-8674-82492f35d715)]
|
[scriptable, uuid(50eda256-4dd2-4c7c-baed-96983910af9f)]
|
||||||
interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
||||||
{
|
{
|
||||||
///////////////// Security Checks //////////////////
|
///////////////// Security Checks //////////////////
|
||||||
|
@ -54,14 +54,6 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
|
||||||
in JSVal aProperty,
|
in JSVal aProperty,
|
||||||
in PRUint32 aAction);
|
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".
|
* Check that the script currently running in context "cx" can load "uri".
|
||||||
*
|
*
|
||||||
|
|
|
@ -410,8 +410,7 @@ public:
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
CheckSameOriginPrincipal(nsIPrincipal* aSubject,
|
CheckSameOriginPrincipal(nsIPrincipal* aSubject,
|
||||||
nsIPrincipal* aObject,
|
nsIPrincipal* aObject);
|
||||||
PRBool aIsCheckConnect);
|
|
||||||
static PRUint32
|
static PRUint32
|
||||||
HashPrincipalByOrigin(nsIPrincipal* aPrincipal);
|
HashPrincipalByOrigin(nsIPrincipal* aPrincipal);
|
||||||
|
|
||||||
|
@ -458,8 +457,7 @@ private:
|
||||||
nsresult
|
nsresult
|
||||||
CheckSameOriginDOMProp(nsIPrincipal* aSubject,
|
CheckSameOriginDOMProp(nsIPrincipal* aSubject,
|
||||||
nsIPrincipal* aObject,
|
nsIPrincipal* aObject,
|
||||||
PRUint32 aAction,
|
PRUint32 aAction);
|
||||||
PRBool aIsCheckConnect);
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
LookupPolicy(nsIPrincipal* principal,
|
LookupPolicy(nsIPrincipal* principal,
|
||||||
|
|
|
@ -363,8 +363,7 @@ nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
|
||||||
// Codebases are equal if they have the same origin.
|
// Codebases are equal if they have the same origin.
|
||||||
*aResult =
|
*aResult =
|
||||||
NS_SUCCEEDED(nsScriptSecurityManager::CheckSameOriginPrincipal(this,
|
NS_SUCCEEDED(nsScriptSecurityManager::CheckSameOriginPrincipal(this,
|
||||||
aOther,
|
aOther));
|
||||||
PR_FALSE));
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -563,34 +563,6 @@ nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx,
|
||||||
aClassName, aProperty, nsnull);
|
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
|
NS_IMETHODIMP
|
||||||
nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
|
nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
|
||||||
nsIURI* aTargetURI)
|
nsIURI* aTargetURI)
|
||||||
|
@ -750,7 +722,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
|
||||||
}
|
}
|
||||||
if(NS_SUCCEEDED(rv))
|
if(NS_SUCCEEDED(rv))
|
||||||
rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
|
rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
|
||||||
aAction, aTargetURI != nsnull);
|
aAction);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -943,8 +915,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
|
||||||
/* static */
|
/* static */
|
||||||
nsresult
|
nsresult
|
||||||
nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
|
nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
|
||||||
nsIPrincipal* aObject,
|
nsIPrincipal* aObject)
|
||||||
PRBool aIsCheckConnect)
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
** Get origin of subject and object and compare.
|
** Get origin of subject and object and compare.
|
||||||
|
@ -952,23 +923,13 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
|
||||||
if (aSubject == aObject)
|
if (aSubject == aObject)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
// These booleans are only used when !aIsCheckConnect. Default
|
// Default to false, and change if that turns out wrong.
|
||||||
// them to false, and change if that turns out wrong.
|
|
||||||
PRBool subjectSetDomain = PR_FALSE;
|
PRBool subjectSetDomain = PR_FALSE;
|
||||||
PRBool objectSetDomain = PR_FALSE;
|
PRBool objectSetDomain = PR_FALSE;
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> subjectURI;
|
nsCOMPtr<nsIURI> subjectURI;
|
||||||
nsCOMPtr<nsIURI> objectURI;
|
nsCOMPtr<nsIURI> objectURI;
|
||||||
|
|
||||||
if (aIsCheckConnect)
|
|
||||||
{
|
|
||||||
// Don't use domain for CheckConnect calls, since that's called for
|
|
||||||
// data-only load checks like XMLHTTPRequest (bug 290100).
|
|
||||||
aSubject->GetURI(getter_AddRefs(subjectURI));
|
|
||||||
aObject->GetURI(getter_AddRefs(objectURI));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aSubject->GetDomain(getter_AddRefs(subjectURI));
|
aSubject->GetDomain(getter_AddRefs(subjectURI));
|
||||||
if (!subjectURI) {
|
if (!subjectURI) {
|
||||||
aSubject->GetURI(getter_AddRefs(subjectURI));
|
aSubject->GetURI(getter_AddRefs(subjectURI));
|
||||||
|
@ -982,7 +943,6 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
|
||||||
} else {
|
} else {
|
||||||
objectSetDomain = PR_TRUE;
|
objectSetDomain = PR_TRUE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (SecurityCompareURIs(subjectURI, objectURI))
|
if (SecurityCompareURIs(subjectURI, objectURI))
|
||||||
{ // If either the subject or the object has changed its principal by
|
{ // If either the subject or the object has changed its principal by
|
||||||
|
@ -990,12 +950,6 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
|
||||||
// done so in order to be considered the same origin. This prevents
|
// done so in order to be considered the same origin. This prevents
|
||||||
// DNS spoofing based on document.domain (154930)
|
// 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 both or neither explicitly set their domain, allow the access
|
||||||
if (subjectSetDomain == objectSetDomain)
|
if (subjectSetDomain == objectSetDomain)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -1009,7 +963,7 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
|
||||||
|
|
||||||
// It's important that
|
// It's important that
|
||||||
//
|
//
|
||||||
// CheckSameOriginPrincipal(A, B, PR_FALSE) == NS_OK
|
// CheckSameOriginPrincipal(A, B) == NS_OK
|
||||||
//
|
//
|
||||||
// imply
|
// imply
|
||||||
//
|
//
|
||||||
|
@ -1032,22 +986,14 @@ nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal)
|
||||||
nsresult
|
nsresult
|
||||||
nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
|
nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
|
||||||
nsIPrincipal* aObject,
|
nsIPrincipal* aObject,
|
||||||
PRUint32 aAction,
|
PRUint32 aAction)
|
||||||
PRBool aIsCheckConnect)
|
|
||||||
{
|
{
|
||||||
nsresult rv;
|
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;
|
PRBool subsumes;
|
||||||
rv = aSubject->Subsumes(aObject, &subsumes);
|
rv = aSubject->Subsumes(aObject, &subsumes);
|
||||||
if (NS_SUCCEEDED(rv) && !subsumes) {
|
if (NS_SUCCEEDED(rv) && !subsumes) {
|
||||||
rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
|
rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv))
|
if (NS_SUCCEEDED(rv))
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
|
|
||||||
interface nsIDOMFileError;
|
interface nsIDOMFileError;
|
||||||
|
|
||||||
[scriptable, uuid(0845E8AE-56BD-4F0E-962A-3B3E92638A0B)]
|
[scriptable, uuid(16753172-6890-4e6a-8c10-a7ff30c5ef22)]
|
||||||
interface nsIDOMFile : nsISupports
|
interface nsIDOMFile : nsISupports
|
||||||
{
|
{
|
||||||
//fileName and fileSize are now deprecated attributes
|
//fileName and fileSize are now deprecated attributes
|
||||||
|
@ -47,6 +47,7 @@ interface nsIDOMFile : nsISupports
|
||||||
readonly attribute unsigned long long fileSize;
|
readonly attribute unsigned long long fileSize;
|
||||||
|
|
||||||
readonly attribute DOMString name;
|
readonly attribute DOMString name;
|
||||||
|
readonly attribute DOMString mozFullPath;
|
||||||
readonly attribute unsigned long long size;
|
readonly attribute unsigned long long size;
|
||||||
readonly attribute DOMString type;
|
readonly attribute DOMString type;
|
||||||
|
|
||||||
|
|
|
@ -106,8 +106,8 @@ class nsIBoxObject;
|
||||||
|
|
||||||
// IID for the nsIDocument interface
|
// IID for the nsIDocument interface
|
||||||
#define NS_IDOCUMENT_IID \
|
#define NS_IDOCUMENT_IID \
|
||||||
{ 0xb04d9176, 0xf087, 0x4d3c, \
|
{ 0x6b2f1996, 0x95d4, 0x48db, \
|
||||||
{ 0x87, 0x11, 0x13, 0x9d, 0x19, 0x95, 0x43, 0x55 } }
|
{0xaf, 0xd1, 0xfd, 0xaa, 0x75, 0x4c, 0x79, 0x92 } }
|
||||||
|
|
||||||
// Flag for AddStyleSheet().
|
// Flag for AddStyleSheet().
|
||||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||||
|
@ -1225,6 +1225,28 @@ public:
|
||||||
Doc_Theme_Bright
|
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,
|
* 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
|
* Doc_Theme_Dark for a dark theme, Doc_Theme_Bright for a light theme, and
|
||||||
|
@ -1388,6 +1410,8 @@ protected:
|
||||||
nsCOMPtr<nsIDocument> mDisplayDocument;
|
nsCOMPtr<nsIDocument> mDisplayDocument;
|
||||||
|
|
||||||
PRUint32 mEventsSuppressed;
|
PRUint32 mEventsSuppressed;
|
||||||
|
|
||||||
|
nsString mPendingStateObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
|
||||||
|
|
|
@ -407,6 +407,7 @@ nsContentUtils::InitializeEventTable() {
|
||||||
{ &nsGkAtoms::onchange, { NS_FORM_CHANGE, EventNameType_HTMLXUL }},
|
{ &nsGkAtoms::onchange, { NS_FORM_CHANGE, EventNameType_HTMLXUL }},
|
||||||
{ &nsGkAtoms::onselect, { NS_FORM_SELECTED, EventNameType_HTMLXUL }},
|
{ &nsGkAtoms::onselect, { NS_FORM_SELECTED, EventNameType_HTMLXUL }},
|
||||||
{ &nsGkAtoms::onload, { NS_LOAD, EventNameType_All }},
|
{ &nsGkAtoms::onload, { NS_LOAD, EventNameType_All }},
|
||||||
|
{ &nsGkAtoms::onpopstate, { NS_POPSTATE, EventNameType_HTMLXUL }},
|
||||||
{ &nsGkAtoms::onunload, { NS_PAGE_UNLOAD,
|
{ &nsGkAtoms::onunload, { NS_PAGE_UNLOAD,
|
||||||
(EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
|
(EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
|
||||||
{ &nsGkAtoms::onhashchange, { NS_HASHCHANGE, EventNameType_HTMLXUL }},
|
{ &nsGkAtoms::onhashchange, { NS_HASHCHANGE, EventNameType_HTMLXUL }},
|
||||||
|
|
|
@ -108,6 +108,16 @@ nsDOMFile::GetName(nsAString &aFileName)
|
||||||
return mFile->GetLeafName(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
|
NS_IMETHODIMP
|
||||||
nsDOMFile::GetSize(PRUint64 *aFileSize)
|
nsDOMFile::GetSize(PRUint64 *aFileSize)
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,6 +46,11 @@
|
||||||
* Base class for all our document implementations.
|
* 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 "plstr.h"
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
|
|
||||||
|
@ -184,13 +189,6 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
|
||||||
// FOR CSP (autogenerated by xpidl)
|
// FOR CSP (autogenerated by xpidl)
|
||||||
#include "nsIContentSecurityPolicy.h"
|
#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 */
|
/* Keeps track of whether or not CSP is enabled */
|
||||||
static PRBool gCSPEnabled = PR_TRUE;
|
static PRBool gCSPEnabled = PR_TRUE;
|
||||||
|
|
||||||
|
|
|
@ -650,6 +650,7 @@ GK_ATOM(onkeypress, "onkeypress")
|
||||||
GK_ATOM(onkeyup, "onkeyup")
|
GK_ATOM(onkeyup, "onkeyup")
|
||||||
GK_ATOM(onLoad, "onLoad")
|
GK_ATOM(onLoad, "onLoad")
|
||||||
GK_ATOM(onload, "onload")
|
GK_ATOM(onload, "onload")
|
||||||
|
GK_ATOM(onpopstate, "onpopstate")
|
||||||
GK_ATOM(only, "only") // this one is not an event
|
GK_ATOM(only, "only") // this one is not an event
|
||||||
GK_ATOM(onmousedown, "onmousedown")
|
GK_ATOM(onmousedown, "onmousedown")
|
||||||
GK_ATOM(onmousemove, "onmousemove")
|
GK_ATOM(onmousemove, "onmousemove")
|
||||||
|
|
|
@ -2402,9 +2402,13 @@ WebGLContext::ValidateGL()
|
||||||
|
|
||||||
//fprintf(stderr, "GL_MAX_VERTEX_ATTRIBS: %d\n", val);
|
//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) {
|
if (val == 0) {
|
||||||
LogMessage("GL_MAX_TEXTURE_UNITS is 0!");
|
LogMessage("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is 0!");
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ CPPSRCS = \
|
||||||
nsDOMEventTargetHelper.cpp \
|
nsDOMEventTargetHelper.cpp \
|
||||||
nsDOMScrollAreaEvent.cpp \
|
nsDOMScrollAreaEvent.cpp \
|
||||||
nsDOMTransitionEvent.cpp \
|
nsDOMTransitionEvent.cpp \
|
||||||
|
nsDOMPopStateEvent.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
# we don't want the shared lib, but we want to force the creation of a static lib.
|
# we don't want the shared lib, but we want to force the creation of a static lib.
|
||||||
|
|
|
@ -59,12 +59,13 @@
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
#include "nsIScriptSecurityManager.h"
|
#include "nsIScriptSecurityManager.h"
|
||||||
#include "nsIScriptError.h"
|
#include "nsIScriptError.h"
|
||||||
|
#include "nsDOMPopStateEvent.h"
|
||||||
|
|
||||||
static const char* const sEventNames[] = {
|
static const char* const sEventNames[] = {
|
||||||
"mousedown", "mouseup", "click", "dblclick", "mouseover",
|
"mousedown", "mouseup", "click", "dblclick", "mouseover",
|
||||||
"mouseout", "mousemove", "contextmenu", "keydown", "keyup", "keypress",
|
"mouseout", "mousemove", "contextmenu", "keydown", "keyup", "keypress",
|
||||||
"focus", "blur", "load", "beforeunload", "unload", "hashchange", "abort", "error",
|
"focus", "blur", "load", "popstate", "beforeunload", "unload", "hashchange",
|
||||||
"submit", "reset", "change", "select", "input" ,"text",
|
"abort", "error", "submit", "reset", "change", "select", "input", "text",
|
||||||
"compositionstart", "compositionend", "popupshowing", "popupshown",
|
"compositionstart", "compositionend", "popupshowing", "popupshown",
|
||||||
"popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate",
|
"popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate",
|
||||||
"dragenter", "dragover", "dragexit", "dragdrop", "draggesture",
|
"dragenter", "dragover", "dragexit", "dragdrop", "draggesture",
|
||||||
|
@ -1328,6 +1329,8 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
|
||||||
return sEventNames[eDOMEvents_close];
|
return sEventNames[eDOMEvents_close];
|
||||||
case NS_LOAD:
|
case NS_LOAD:
|
||||||
return sEventNames[eDOMEvents_load];
|
return sEventNames[eDOMEvents_load];
|
||||||
|
case NS_POPSTATE:
|
||||||
|
return sEventNames[eDOMEvents_popstate];
|
||||||
case NS_BEFORE_PAGE_UNLOAD:
|
case NS_BEFORE_PAGE_UNLOAD:
|
||||||
return sEventNames[eDOMEvents_beforeunload];
|
return sEventNames[eDOMEvents_beforeunload];
|
||||||
case NS_PAGE_UNLOAD:
|
case NS_PAGE_UNLOAD:
|
||||||
|
|
|
@ -58,7 +58,7 @@ class nsDOMEvent : public nsIDOMEvent,
|
||||||
{
|
{
|
||||||
public:
|
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 {
|
enum nsDOMEvents {
|
||||||
eDOMEvents_mousedown=0,
|
eDOMEvents_mousedown=0,
|
||||||
eDOMEvents_mouseup,
|
eDOMEvents_mouseup,
|
||||||
|
@ -74,6 +74,7 @@ public:
|
||||||
eDOMEvents_focus,
|
eDOMEvents_focus,
|
||||||
eDOMEvents_blur,
|
eDOMEvents_blur,
|
||||||
eDOMEvents_load,
|
eDOMEvents_load,
|
||||||
|
eDOMEvents_popstate,
|
||||||
eDOMEvents_beforeunload,
|
eDOMEvents_beforeunload,
|
||||||
eDOMEvents_unload,
|
eDOMEvents_unload,
|
||||||
eDOMEvents_hashchange,
|
eDOMEvents_hashchange,
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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<nsIVariant> mState;
|
||||||
|
};
|
||||||
|
|
||||||
|
nsresult NS_NewDOMPopStateEvent(nsIDOMEvent** aInstancePtrResult,
|
||||||
|
nsPresContext* aPresContext,
|
||||||
|
nsEvent* aEvent);
|
||||||
|
|
||||||
|
#endif // nsDOMPopStateEvent_h__
|
|
@ -48,6 +48,7 @@
|
||||||
#include "nsFixedSizeAllocator.h"
|
#include "nsFixedSizeAllocator.h"
|
||||||
#include "nsINode.h"
|
#include "nsINode.h"
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
|
#include "nsDOMPopStateEvent.h"
|
||||||
|
|
||||||
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
|
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
|
||||||
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
|
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
|
||||||
|
@ -796,6 +797,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
|
||||||
// is probably wrong!
|
// is probably wrong!
|
||||||
if (aEventType.LowerCaseEqualsLiteral("transitionevent"))
|
if (aEventType.LowerCaseEqualsLiteral("transitionevent"))
|
||||||
return NS_NewDOMTransitionEvent(aDOMEvent, aPresContext, nsnull);
|
return NS_NewDOMTransitionEvent(aDOMEvent, aPresContext, nsnull);
|
||||||
|
if (aEventType.LowerCaseEqualsLiteral("popstateevent"))
|
||||||
|
return NS_NewDOMPopStateEvent(aDOMEvent, aPresContext, nsnull);
|
||||||
|
|
||||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -692,9 +692,30 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||||
loadAsHtml5 = PR_FALSE;
|
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;
|
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<nsIURI> 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
|
#ifdef DEBUG
|
||||||
else {
|
else {
|
||||||
NS_ASSERTION(mIsRegularHTML,
|
NS_ASSERTION(mIsRegularHTML,
|
||||||
|
|
|
@ -44,6 +44,12 @@ namespace mozilla {
|
||||||
class SMILBoolType : public nsISMILType
|
class SMILBoolType : public nsISMILType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Singleton for nsSMILValue objects to hold onto.
|
||||||
|
static SMILBoolType sSingleton;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// nsISMILType Methods
|
||||||
|
// -------------------
|
||||||
virtual nsresult Init(nsSMILValue& aValue) const;
|
virtual nsresult Init(nsSMILValue& aValue) const;
|
||||||
virtual void Destroy(nsSMILValue&) const;
|
virtual void Destroy(nsSMILValue&) const;
|
||||||
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
||||||
|
@ -57,10 +63,11 @@ public:
|
||||||
double aUnitDistance,
|
double aUnitDistance,
|
||||||
nsSMILValue& aResult) const;
|
nsSMILValue& aResult) const;
|
||||||
|
|
||||||
static SMILBoolType sSingleton;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Private constructor & destructor: prevent instances beyond my singleton,
|
||||||
|
// and prevent others from deleting my singleton.
|
||||||
SMILBoolType() {}
|
SMILBoolType() {}
|
||||||
|
~SMILBoolType() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -44,6 +44,12 @@ namespace mozilla {
|
||||||
class SMILEnumType : public nsISMILType
|
class SMILEnumType : public nsISMILType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Singleton for nsSMILValue objects to hold onto.
|
||||||
|
static SMILEnumType sSingleton;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// nsISMILType Methods
|
||||||
|
// -------------------
|
||||||
virtual nsresult Init(nsSMILValue& aValue) const;
|
virtual nsresult Init(nsSMILValue& aValue) const;
|
||||||
virtual void Destroy(nsSMILValue&) const;
|
virtual void Destroy(nsSMILValue&) const;
|
||||||
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
||||||
|
@ -57,10 +63,11 @@ public:
|
||||||
double aUnitDistance,
|
double aUnitDistance,
|
||||||
nsSMILValue& aResult) const;
|
nsSMILValue& aResult) const;
|
||||||
|
|
||||||
static SMILEnumType sSingleton;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Private constructor & destructor: prevent instances beyond my singleton,
|
||||||
|
// and prevent others from deleting my singleton.
|
||||||
SMILEnumType() {}
|
SMILEnumType() {}
|
||||||
|
~SMILEnumType() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -75,7 +75,12 @@ class nsSMILValue;
|
||||||
|
|
||||||
class nsISMILType
|
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
|
* Initialises aValue and sets it to some identity value such that adding
|
||||||
* aValue to another value of the same type has no effect.
|
* aValue to another value of the same type has no effect.
|
||||||
|
@ -211,11 +216,12 @@ public:
|
||||||
double aUnitDistance,
|
double aUnitDistance,
|
||||||
nsSMILValue& aResult) const = 0;
|
nsSMILValue& aResult) const = 0;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Virtual destructor: Nothing to do here, but subclasses
|
* Protected destructor, to ensure that no one accidentally deletes an
|
||||||
* may need it.
|
* instance of this class.
|
||||||
|
* (The only instances in existence should be singletons - one per subclass.)
|
||||||
*/
|
*/
|
||||||
virtual ~nsISMILType() {};
|
~nsISMILType() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NS_ISMILTYPE_H_
|
#endif // NS_ISMILTYPE_H_
|
||||||
|
|
|
@ -46,13 +46,16 @@
|
||||||
#include "nsIContent.h"
|
#include "nsIContent.h"
|
||||||
#include "nsIDOMElement.h"
|
#include "nsIDOMElement.h"
|
||||||
|
|
||||||
|
// Helper function
|
||||||
static PRBool
|
static PRBool
|
||||||
GetCSSComputedValue(nsIContent* aElem,
|
GetCSSComputedValue(nsIContent* aElem,
|
||||||
nsCSSProperty aPropID,
|
nsCSSProperty aPropID,
|
||||||
nsAString& aResult)
|
nsAString& aResult)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID),
|
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aPropID),
|
||||||
PR_FALSE);
|
"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();
|
nsIDocument* doc = aElem->GetCurrentDoc();
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
|
@ -73,8 +76,7 @@ GetCSSComputedValue(nsIContent* aElem,
|
||||||
nsresult rv = NS_NewComputedDOMStyle(domElement, EmptyString(), shell,
|
nsresult rv = NS_NewComputedDOMStyle(domElement, EmptyString(), shell,
|
||||||
getter_AddRefs(computedStyle));
|
getter_AddRefs(computedStyle));
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv) && computedStyle) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
// NOTE: This will produce an empty string for shorthand values
|
|
||||||
computedStyle->GetPropertyValue(aPropID, aResult);
|
computedStyle->GetPropertyValue(aPropID, aResult);
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -94,6 +96,20 @@ nsSMILCSSProperty::nsSMILCSSProperty(nsCSSProperty aPropID,
|
||||||
nsSMILValue
|
nsSMILValue
|
||||||
nsSMILCSSProperty::GetBaseValue() const
|
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
|
// (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)
|
// (saving old override style value, so we can set it again when we're done)
|
||||||
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
|
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
|
||||||
|
@ -118,18 +134,11 @@ nsSMILCSSProperty::GetBaseValue() const
|
||||||
overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal);
|
overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (4) Create a nsSMILValue from the computed style
|
||||||
nsSMILValue baseValue;
|
nsSMILValue baseValue;
|
||||||
if (didGetComputedVal) {
|
if (didGetComputedVal) {
|
||||||
// (4) Create the nsSMILValue from the computed style value
|
nsSMILCSSValueType::ValueFromString(mPropID, mElement,
|
||||||
nsSMILCSSValueType::sSingleton.Init(baseValue);
|
computedStyleVal, 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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return baseValue;
|
return baseValue;
|
||||||
}
|
}
|
||||||
|
@ -140,14 +149,9 @@ nsSMILCSSProperty::ValueFromString(const nsAString& aStr,
|
||||||
nsSMILValue& aValue) const
|
nsSMILValue& aValue) const
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
|
||||||
nsSMILCSSValueType::sSingleton.Init(aValue);
|
|
||||||
PRBool success =
|
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
|
||||||
nsSMILCSSValueType::sSingleton.ValueFromString(mPropID, mElement,
|
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
|
||||||
aStr, aValue);
|
|
||||||
if (!success) {
|
|
||||||
nsSMILCSSValueType::sSingleton.Destroy(aValue);
|
|
||||||
}
|
|
||||||
return success ? NS_OK : NS_ERROR_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -155,32 +159,29 @@ nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
// Convert nsSMILValue to string
|
||||||
nsAutoString valStr;
|
nsAutoString valStr;
|
||||||
|
if (!nsSMILCSSValueType::ValueToString(aValue, valStr)) {
|
||||||
|
NS_WARNING("Failed to convert nsSMILValue for CSS property into a string");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (nsSMILCSSValueType::sSingleton.ValueToString(aValue, valStr)) {
|
// Use string value to style the target element
|
||||||
// Apply the style to the target element
|
|
||||||
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
|
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
|
||||||
mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
|
mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
|
||||||
NS_ABORT_IF_FALSE(overrideStyle, "Need a non-null overrideStyle");
|
NS_ABORT_IF_FALSE(overrideStyle, "Need a non-null overrideStyle");
|
||||||
|
|
||||||
nsCOMPtr<nsICSSDeclaration> overrideDecl =
|
nsCOMPtr<nsICSSDeclaration> overrideDecl = do_QueryInterface(overrideStyle);
|
||||||
do_QueryInterface(overrideStyle);
|
|
||||||
if (overrideDecl) {
|
if (overrideDecl) {
|
||||||
overrideDecl->SetPropertyValue(mPropID, valStr);
|
overrideDecl->SetPropertyValue(mPropID, valStr);
|
||||||
}
|
}
|
||||||
} else {
|
return NS_OK;
|
||||||
NS_WARNING("Failed to convert nsSMILValue for CSS property into a string");
|
|
||||||
rv = NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsSMILCSSProperty::ClearAnimValue()
|
nsSMILCSSProperty::ClearAnimValue()
|
||||||
{
|
{
|
||||||
// Put empty string in override style for property propID
|
// Put empty string in override style for our property
|
||||||
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
|
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
|
||||||
mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
|
mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
|
||||||
nsCOMPtr<nsICSSDeclaration> overrideDecl = do_QueryInterface(overrideStyle);
|
nsCOMPtr<nsICSSDeclaration> overrideDecl = do_QueryInterface(overrideStyle);
|
||||||
|
|
|
@ -303,59 +303,79 @@ GetPresContextForElement(nsIContent* aElem)
|
||||||
return shell ? shell->GetPresContext() : nsnull;
|
return shell ? shell->GetPresContext() : nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRBool
|
// Helper function to parse a string into a nsStyleAnimation::Value
|
||||||
nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
|
static PRBool
|
||||||
|
ValueFromStringHelper(nsCSSProperty aPropID,
|
||||||
nsIContent* aTargetElement,
|
nsIContent* aTargetElement,
|
||||||
|
nsPresContext* aPresContext,
|
||||||
const nsAString& aString,
|
const nsAString& aString,
|
||||||
nsSMILValue& aValue) const
|
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
|
// 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
|
// barf, and then manually make the parsed value negative.
|
||||||
// solution to let us accept some otherwise out-of-bounds CSS values -- bug
|
// (This is a partial solution to let us accept some otherwise out-of-bounds
|
||||||
// 501188 will provide a more complete fix.)
|
// CSS values. Bug 501188 will provide a more complete fix.)
|
||||||
PRBool isNegative = PR_FALSE;
|
PRBool isNegative = PR_FALSE;
|
||||||
PRUint32 subStringBegin = 0;
|
PRUint32 subStringBegin = 0;
|
||||||
PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
|
PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
|
||||||
if (absValuePos > 0) {
|
if (absValuePos > 0) {
|
||||||
subStringBegin = (PRUint32)absValuePos;
|
|
||||||
isNegative = PR_TRUE;
|
isNegative = PR_TRUE;
|
||||||
|
subStringBegin = (PRUint32)absValuePos; // Start parsing after '-' sign
|
||||||
}
|
}
|
||||||
nsDependentSubstring subString(aString, subStringBegin);
|
nsDependentSubstring subString(aString, subStringBegin);
|
||||||
nsStyleAnimation::Value parsedValue;
|
if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement,
|
||||||
if (nsStyleAnimation::ComputeValue(aPropID, aTargetElement,
|
subString, aStyleAnimValue)) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
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
|
PRBool
|
||||||
nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
|
nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
|
||||||
nsAString& aString) const
|
nsAString& aString)
|
||||||
{
|
{
|
||||||
NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton,
|
NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton,
|
||||||
"Passed-in value is wrong type");
|
"Unexpected SMIL value type");
|
||||||
const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
|
const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
|
||||||
return !wrapper ||
|
return !wrapper ||
|
||||||
nsStyleAnimation::UncomputeValue(wrapper->mPropID, wrapper->mPresContext,
|
nsStyleAnimation::UncomputeValue(wrapper->mPropID, wrapper->mPresContext,
|
||||||
|
|
|
@ -54,8 +54,12 @@ class nsAString;
|
||||||
class nsSMILCSSValueType : public nsISMILType
|
class nsSMILCSSValueType : public nsISMILType
|
||||||
{
|
{
|
||||||
public:
|
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 nsresult Init(nsSMILValue& aValue) const;
|
||||||
NS_OVERRIDE virtual void Destroy(nsSMILValue&) const;
|
NS_OVERRIDE virtual void Destroy(nsSMILValue&) const;
|
||||||
NS_OVERRIDE virtual nsresult Assign(nsSMILValue& aDest,
|
NS_OVERRIDE virtual nsresult Assign(nsSMILValue& aDest,
|
||||||
|
@ -71,24 +75,29 @@ public:
|
||||||
double aUnitDistance,
|
double aUnitDistance,
|
||||||
nsSMILValue& aResult) const;
|
nsSMILValue& aResult) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Helper Methods
|
||||||
|
// --------------
|
||||||
/**
|
/**
|
||||||
* Sets up the given nsSMILValue to represent the given string value. The
|
* 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
|
* string is interpreted as a value for the given property on the given
|
||||||
* element.
|
* element.
|
||||||
*
|
*
|
||||||
* Note: aValue is expected to be freshly initialized (i.e. it should already
|
* On failure, this method leaves aValue.mType == nsSMILNullType::sSingleton.
|
||||||
* have been passed into nsSMILCSSValueType::Init(), and it should not have
|
* Otherwise, this method leaves aValue.mType == this class's singleton.
|
||||||
* been set up further via e.g. Assign() or another ValueFromString() call.)
|
|
||||||
*
|
*
|
||||||
* @param aPropID The property for which we're parsing a value.
|
* @param aPropID The property for which we're parsing a value.
|
||||||
* @param aTargetElement The target element to whom the property/value
|
* @param aTargetElement The target element to whom the property/value
|
||||||
* setting applies.
|
* setting applies.
|
||||||
* @param aString The string to be parsed as a CSS value.
|
* @param aString The string to be parsed as a CSS value.
|
||||||
* @param [out] aValue The nsSMILValue to be populated.
|
* @param [out] aValue The nsSMILValue to be populated. Should
|
||||||
* @return PR_TRUE on success, PR_FALSE on failure.
|
* initially be null-typed.
|
||||||
|
* @pre aValue.IsNull()
|
||||||
|
* @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton
|
||||||
*/
|
*/
|
||||||
PRBool ValueFromString(nsCSSProperty aPropID, nsIContent* aTargetElement,
|
static void ValueFromString(nsCSSProperty aPropID,
|
||||||
const nsAString& aString, nsSMILValue& aValue) const;
|
nsIContent* aTargetElement,
|
||||||
|
const nsAString& aString, nsSMILValue& aValue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a string representation of the given nsSMILValue.
|
* 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.
|
* @param [out] aString The string to be populated with the given value.
|
||||||
* @return PR_TRUE on success, PR_FALSE on failure.
|
* @return PR_TRUE on success, PR_FALSE on failure.
|
||||||
*/
|
*/
|
||||||
PRBool ValueToString(const nsSMILValue& aValue, nsAString& aString) const;
|
static PRBool ValueToString(const nsSMILValue& aValue, nsAString& aString);
|
||||||
|
|
||||||
// Singleton for nsSMILValue objects to hold onto.
|
|
||||||
static nsSMILCSSValueType sSingleton;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Private constructor & destructor: prevent instances beyond my singleton,
|
||||||
|
// and prevent others from deleting my singleton.
|
||||||
nsSMILCSSValueType() {}
|
nsSMILCSSValueType() {}
|
||||||
|
~nsSMILCSSValueType() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NS_SMILCSSVALUETYPE_H_
|
#endif // NS_SMILCSSVALUETYPE_H_
|
||||||
|
|
|
@ -44,6 +44,12 @@
|
||||||
class nsSMILFloatType : public nsISMILType
|
class nsSMILFloatType : public nsISMILType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Singleton for nsSMILValue objects to hold onto.
|
||||||
|
static nsSMILFloatType sSingleton;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// nsISMILType Methods
|
||||||
|
// -------------------
|
||||||
virtual nsresult Init(nsSMILValue& aValue) const;
|
virtual nsresult Init(nsSMILValue& aValue) const;
|
||||||
virtual void Destroy(nsSMILValue&) const;
|
virtual void Destroy(nsSMILValue&) const;
|
||||||
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
||||||
|
@ -57,10 +63,11 @@ public:
|
||||||
double aUnitDistance,
|
double aUnitDistance,
|
||||||
nsSMILValue& aResult) const;
|
nsSMILValue& aResult) const;
|
||||||
|
|
||||||
static nsSMILFloatType sSingleton;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Private constructor & destructor: prevent instances beyond my singleton,
|
||||||
|
// and prevent others from deleting my singleton.
|
||||||
nsSMILFloatType() {}
|
nsSMILFloatType() {}
|
||||||
|
~nsSMILFloatType() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NS_SMILFLOATTYPE_H_
|
#endif // NS_SMILFLOATTYPE_H_
|
||||||
|
|
|
@ -44,6 +44,12 @@
|
||||||
class nsSMILNullType : public nsISMILType
|
class nsSMILNullType : public nsISMILType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Singleton for nsSMILValue objects to hold onto.
|
||||||
|
static nsSMILNullType sSingleton;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// nsISMILType Methods
|
||||||
|
// -------------------
|
||||||
virtual nsresult Init(nsSMILValue& aValue) const { return NS_OK; }
|
virtual nsresult Init(nsSMILValue& aValue) const { return NS_OK; }
|
||||||
virtual void Destroy(nsSMILValue& aValue) const {}
|
virtual void Destroy(nsSMILValue& aValue) const {}
|
||||||
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
||||||
|
@ -60,7 +66,11 @@ public:
|
||||||
double aUnitDistance,
|
double aUnitDistance,
|
||||||
nsSMILValue& aResult) const;
|
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_
|
#endif // NS_SMILNULLTYPE_H_
|
||||||
|
|
|
@ -50,12 +50,6 @@
|
||||||
#include "nsISVGValue.h"
|
#include "nsISVGValue.h"
|
||||||
#include "prdtoa.h"
|
#include "prdtoa.h"
|
||||||
|
|
||||||
nsISMILType*
|
|
||||||
nsSVGTransformSMILAttr::GetSMILType() const
|
|
||||||
{
|
|
||||||
return &nsSVGTransformSMILType::sSingleton;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
|
nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
|
||||||
const nsISMILAnimationElement* aSrcElement,
|
const nsISMILAnimationElement* aSrcElement,
|
||||||
|
@ -65,32 +59,21 @@ nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
|
||||||
NS_ASSERTION(aValue.IsNull(),
|
NS_ASSERTION(aValue.IsNull(),
|
||||||
"aValue should have been cleared before calling ValueFromString");
|
"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 nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
|
||||||
|
|
||||||
const nsIAtom* transformType = typeAttr
|
const nsIAtom* transformType = typeAttr
|
||||||
? typeAttr->GetAtomValue()
|
? typeAttr->GetAtomValue()
|
||||||
: nsGkAtoms::translate;
|
: nsGkAtoms::translate;
|
||||||
|
|
||||||
nsresult rv = ParseValue(aStr, transformType, val);
|
ParseValue(aStr, transformType, aValue);
|
||||||
if (NS_FAILED(rv))
|
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
|
||||||
return rv;
|
|
||||||
|
|
||||||
aValue = val;
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsSMILValue
|
nsSMILValue
|
||||||
nsSVGTransformSMILAttr::GetBaseValue() const
|
nsSVGTransformSMILAttr::GetBaseValue() const
|
||||||
{
|
{
|
||||||
nsSVGTransformSMILType *type = &nsSVGTransformSMILType::sSingleton;
|
nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
|
||||||
nsSMILValue val(type);
|
|
||||||
if (val.IsNull())
|
if (val.IsNull())
|
||||||
return val;
|
return val; // Initialization failed
|
||||||
|
|
||||||
nsIDOMSVGTransformList *list = mVal->mBaseVal.get();
|
nsIDOMSVGTransformList *list = mVal->mBaseVal.get();
|
||||||
|
|
||||||
|
@ -149,19 +132,12 @@ nsSVGTransformSMILAttr::SetAnimValue(const nsSMILValue& aValue)
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Implementation helpers
|
// Implementation helpers
|
||||||
|
|
||||||
nsresult
|
void
|
||||||
nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
|
nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
|
||||||
const nsIAtom* aTransformType,
|
const nsIAtom* aTransformType,
|
||||||
nsSMILValue& aResult) const
|
nsSMILValue& aResult)
|
||||||
{
|
{
|
||||||
nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton;
|
NS_ASSERTION(aResult.IsNull(), "Unexpected type for SMIL value");
|
||||||
NS_ASSERTION(
|
|
||||||
type == static_cast<nsSVGTransformSMILType const *>(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);
|
|
||||||
|
|
||||||
float params[3] = { 0.f };
|
float params[3] = { 0.f };
|
||||||
PRInt32 numParsed = ParseParameterList(aSpec, params, 3);
|
PRInt32 numParsed = ParseParameterList(aSpec, params, 3);
|
||||||
|
@ -170,12 +146,12 @@ nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
|
||||||
if (aTransformType == nsGkAtoms::translate) {
|
if (aTransformType == nsGkAtoms::translate) {
|
||||||
// tx [ty=0]
|
// tx [ty=0]
|
||||||
if (numParsed != 1 && numParsed != 2)
|
if (numParsed != 1 && numParsed != 2)
|
||||||
return NS_ERROR_FAILURE;
|
return;
|
||||||
transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE;
|
transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE;
|
||||||
} else if (aTransformType == nsGkAtoms::scale) {
|
} else if (aTransformType == nsGkAtoms::scale) {
|
||||||
// sx [sy=sx]
|
// sx [sy=sx]
|
||||||
if (numParsed != 1 && numParsed != 2)
|
if (numParsed != 1 && numParsed != 2)
|
||||||
return NS_ERROR_FAILURE;
|
return;
|
||||||
if (numParsed == 1) {
|
if (numParsed == 1) {
|
||||||
params[1] = params[0];
|
params[1] = params[0];
|
||||||
}
|
}
|
||||||
|
@ -183,35 +159,41 @@ nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
|
||||||
} else if (aTransformType == nsGkAtoms::rotate) {
|
} else if (aTransformType == nsGkAtoms::rotate) {
|
||||||
// r [cx=0 cy=0]
|
// r [cx=0 cy=0]
|
||||||
if (numParsed != 1 && numParsed != 3)
|
if (numParsed != 1 && numParsed != 3)
|
||||||
return NS_ERROR_FAILURE;
|
return;
|
||||||
transformType = nsSVGSMILTransform::TRANSFORM_ROTATE;
|
transformType = nsSVGSMILTransform::TRANSFORM_ROTATE;
|
||||||
} else if (aTransformType == nsGkAtoms::skewX) {
|
} else if (aTransformType == nsGkAtoms::skewX) {
|
||||||
// x-angle
|
// x-angle
|
||||||
if (numParsed != 1)
|
if (numParsed != 1)
|
||||||
return NS_ERROR_FAILURE;
|
return;
|
||||||
transformType = nsSVGSMILTransform::TRANSFORM_SKEWX;
|
transformType = nsSVGSMILTransform::TRANSFORM_SKEWX;
|
||||||
} else if (aTransformType == nsGkAtoms::skewY) {
|
} else if (aTransformType == nsGkAtoms::skewY) {
|
||||||
// y-angle
|
// y-angle
|
||||||
if (numParsed != 1)
|
if (numParsed != 1)
|
||||||
return NS_ERROR_FAILURE;
|
return;
|
||||||
transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
|
transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
|
||||||
} else {
|
} else {
|
||||||
return NS_ERROR_FAILURE;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->AppendTransform(nsSVGSMILTransform(transformType, params),
|
nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
|
||||||
aResult);
|
nsSVGSMILTransform transform(transformType, params);
|
||||||
|
if (NS_FAILED(nsSVGTransformSMILType::AppendTransform(transform, val))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success! Initialize our outparam with parsed value.
|
||||||
|
aResult = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PRBool
|
inline PRBool
|
||||||
nsSVGTransformSMILAttr::IsSpace(const char c) const
|
IsSpace(const char c)
|
||||||
{
|
{
|
||||||
return (c == 0x9 || c == 0xA || c == 0xD || c == 0x20);
|
return (c == 0x9 || c == 0xA || c == 0xD || c == 0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
nsSVGTransformSMILAttr::SkipWsp(nsACString::const_iterator& aIter,
|
SkipWsp(nsACString::const_iterator& aIter,
|
||||||
const nsACString::const_iterator& aIterEnd) const
|
const nsACString::const_iterator& aIterEnd)
|
||||||
{
|
{
|
||||||
while (aIter != aIterEnd && IsSpace(*aIter))
|
while (aIter != aIterEnd && IsSpace(*aIter))
|
||||||
++aIter;
|
++aIter;
|
||||||
|
@ -220,7 +202,7 @@ nsSVGTransformSMILAttr::SkipWsp(nsACString::const_iterator& aIter,
|
||||||
PRInt32
|
PRInt32
|
||||||
nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec,
|
nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec,
|
||||||
float* aVars,
|
float* aVars,
|
||||||
PRInt32 aNVars) const
|
PRInt32 aNVars)
|
||||||
{
|
{
|
||||||
NS_ConvertUTF16toUTF8 spec(aSpec);
|
NS_ConvertUTF16toUTF8 spec(aSpec);
|
||||||
|
|
||||||
|
@ -258,9 +240,10 @@ nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec,
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue(
|
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;
|
PRUint16 svgTransformType = nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX;
|
||||||
aTransform->GetType(&svgTransformType);
|
aTransform->GetType(&svgTransformType);
|
||||||
|
@ -328,10 +311,9 @@ nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue(
|
||||||
matrix->GetD(&mx[3]);
|
matrix->GetD(&mx[3]);
|
||||||
matrix->GetE(&mx[4]);
|
matrix->GetE(&mx[4]);
|
||||||
matrix->GetF(&mx[5]);
|
matrix->GetF(&mx[5]);
|
||||||
rv = type->AppendTransform(nsSVGSMILTransform(mx), aValue);
|
return nsSVGTransformSMILType::AppendTransform(nsSVGSMILTransform(mx),
|
||||||
transformType = nsSVGSMILTransform::TRANSFORM_MATRIX;
|
aValue);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case nsIDOMSVGTransform::SVG_TRANSFORM_UNKNOWN:
|
case nsIDOMSVGTransform::SVG_TRANSFORM_UNKNOWN:
|
||||||
// If it's 'unknown', it's probably not initialised, so just skip it.
|
// If it's 'unknown', it's probably not initialised, so just skip it.
|
||||||
|
@ -342,12 +324,11 @@ nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue(
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transformType != nsSVGSMILTransform::TRANSFORM_MATRIX) {
|
NS_ABORT_IF_FALSE(transformType != nsSVGSMILTransform::TRANSFORM_MATRIX,
|
||||||
rv =
|
"generalized matrix case should have returned above");
|
||||||
type->AppendTransform(nsSVGSMILTransform(transformType, params), aValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return nsSVGTransformSMILType::
|
||||||
|
AppendTransform(nsSVGSMILTransform(transformType, params), aValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -396,40 +377,34 @@ nsSVGTransformSMILAttr::UpdateFromSMILValue(
|
||||||
nsresult
|
nsresult
|
||||||
nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue(
|
nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue(
|
||||||
const nsSVGSMILTransform& aSMILTransform,
|
const nsSVGSMILTransform& aSMILTransform,
|
||||||
nsIDOMSVGTransform* aSVGTransform) const
|
nsIDOMSVGTransform* aSVGTransform)
|
||||||
{
|
{
|
||||||
nsresult rv = NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
switch (aSMILTransform.mTransformType)
|
switch (aSMILTransform.mTransformType)
|
||||||
{
|
{
|
||||||
case nsSVGSMILTransform::TRANSFORM_TRANSLATE:
|
case nsSVGSMILTransform::TRANSFORM_TRANSLATE:
|
||||||
rv = aSVGTransform->SetTranslate(aSMILTransform.mParams[0],
|
return aSVGTransform->SetTranslate(aSMILTransform.mParams[0],
|
||||||
aSMILTransform.mParams[1]);
|
aSMILTransform.mParams[1]);
|
||||||
break;
|
|
||||||
|
|
||||||
case nsSVGSMILTransform::TRANSFORM_SCALE:
|
case nsSVGSMILTransform::TRANSFORM_SCALE:
|
||||||
rv = aSVGTransform->SetScale(aSMILTransform.mParams[0],
|
return aSVGTransform->SetScale(aSMILTransform.mParams[0],
|
||||||
aSMILTransform.mParams[1]);
|
aSMILTransform.mParams[1]);
|
||||||
break;
|
|
||||||
|
|
||||||
case nsSVGSMILTransform::TRANSFORM_ROTATE:
|
case nsSVGSMILTransform::TRANSFORM_ROTATE:
|
||||||
rv = aSVGTransform->SetRotate(aSMILTransform.mParams[0],
|
return aSVGTransform->SetRotate(aSMILTransform.mParams[0],
|
||||||
aSMILTransform.mParams[1],
|
aSMILTransform.mParams[1],
|
||||||
aSMILTransform.mParams[2]);
|
aSMILTransform.mParams[2]);
|
||||||
break;
|
|
||||||
|
|
||||||
case nsSVGSMILTransform::TRANSFORM_SKEWX:
|
case nsSVGSMILTransform::TRANSFORM_SKEWX:
|
||||||
rv = aSVGTransform->SetSkewX(aSMILTransform.mParams[0]);
|
return aSVGTransform->SetSkewX(aSMILTransform.mParams[0]);
|
||||||
break;
|
|
||||||
|
|
||||||
case nsSVGSMILTransform::TRANSFORM_SKEWY:
|
case nsSVGSMILTransform::TRANSFORM_SKEWY:
|
||||||
rv = aSVGTransform->SetSkewY(aSMILTransform.mParams[0]);
|
return aSVGTransform->SetSkewY(aSMILTransform.mParams[0]);
|
||||||
break;
|
|
||||||
|
|
||||||
case nsSVGSMILTransform::TRANSFORM_MATRIX:
|
case nsSVGSMILTransform::TRANSFORM_MATRIX:
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIDOMSVGMatrix> svgMatrix;
|
nsCOMPtr<nsIDOMSVGMatrix> svgMatrix;
|
||||||
rv = NS_NewSVGMatrix(getter_AddRefs(svgMatrix),
|
nsresult rv =
|
||||||
|
NS_NewSVGMatrix(getter_AddRefs(svgMatrix),
|
||||||
aSMILTransform.mParams[0],
|
aSMILTransform.mParams[0],
|
||||||
aSMILTransform.mParams[1],
|
aSMILTransform.mParams[1],
|
||||||
aSMILTransform.mParams[2],
|
aSMILTransform.mParams[2],
|
||||||
|
@ -437,11 +412,13 @@ nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue(
|
||||||
aSMILTransform.mParams[4],
|
aSMILTransform.mParams[4],
|
||||||
aSMILTransform.mParams[5]);
|
aSMILTransform.mParams[5]);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
NS_ENSURE_TRUE(svgMatrix,NS_ERROR_FAILURE);
|
NS_ABORT_IF_FALSE(svgMatrix,
|
||||||
rv = aSVGTransform->SetMatrix(svgMatrix);
|
"NS_NewSVGMatrix succeeded, so it should have "
|
||||||
|
"given us a non-null result");
|
||||||
|
return aSVGTransform->SetMatrix(svgMatrix);
|
||||||
}
|
}
|
||||||
break;
|
default:
|
||||||
|
NS_WARNING("Unexpected transform type");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,11 +54,9 @@ class nsSVGTransformSMILAttr : public nsISMILAttr
|
||||||
public:
|
public:
|
||||||
nsSVGTransformSMILAttr(nsSVGAnimatedTransformList* aTransform,
|
nsSVGTransformSMILAttr(nsSVGAnimatedTransformList* aTransform,
|
||||||
nsSVGElement* aSVGElement)
|
nsSVGElement* aSVGElement)
|
||||||
: mVal(aTransform),
|
: mVal(aTransform) {}
|
||||||
mSVGElement(aSVGElement) {}
|
|
||||||
|
|
||||||
// nsISMILAttr methods
|
// nsISMILAttr methods
|
||||||
virtual nsISMILType* GetSMILType() const;
|
|
||||||
virtual nsresult ValueFromString(const nsAString& aStr,
|
virtual nsresult ValueFromString(const nsAString& aStr,
|
||||||
const nsISMILAnimationElement* aSrcElement,
|
const nsISMILAnimationElement* aSrcElement,
|
||||||
nsSMILValue& aValue) const;
|
nsSMILValue& aValue) const;
|
||||||
|
@ -67,30 +65,24 @@ public:
|
||||||
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
|
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsresult ParseValue(const nsAString& aSpec,
|
static void ParseValue(const nsAString& aSpec,
|
||||||
const nsIAtom* aTransformType,
|
const nsIAtom* aTransformType,
|
||||||
nsSMILValue& aResult) const;
|
nsSMILValue& aResult);
|
||||||
PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars,
|
static PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars,
|
||||||
PRInt32 aNVars) const;
|
PRInt32 aNVars);
|
||||||
PRBool IsSpace(const char c) const;
|
static nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform,
|
||||||
void SkipWsp(nsACString::const_iterator& aIter,
|
nsSMILValue& aValue);
|
||||||
const nsACString::const_iterator& aIterEnd) const;
|
static nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList,
|
||||||
nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform,
|
|
||||||
nsSMILValue& aValue) const;
|
|
||||||
nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList,
|
|
||||||
const nsSMILValue& aValue);
|
const nsSMILValue& aValue);
|
||||||
nsresult GetSVGTransformFromSMILValue(
|
static nsresult GetSVGTransformFromSMILValue(
|
||||||
const nsSVGSMILTransform& aSMILTransform,
|
const nsSVGSMILTransform& aSMILTransform,
|
||||||
nsIDOMSVGTransform* aSVGTransform) const;
|
nsIDOMSVGTransform* aSVGTransform);
|
||||||
already_AddRefed<nsIDOMSVGTransform> GetSVGTransformFromSMILValue(
|
|
||||||
const nsSMILValue& aValue) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Raw pointers are OK here because this nsSVGTransformSMILAttr is both
|
// Raw pointers are OK here because this nsSVGTransformSMILAttr is both
|
||||||
// created & destroyed during a SMIL sample-step, during which time the DOM
|
// created & destroyed during a SMIL sample-step, during which time the DOM
|
||||||
// isn't modified.
|
// isn't modified.
|
||||||
nsSVGAnimatedTransformList* mVal;
|
nsSVGAnimatedTransformList* mVal;
|
||||||
nsSVGElement* mSVGElement;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NS_SVGTRANSFORMSMILATTR_H_
|
#endif // NS_SVGTRANSFORMSMILATTR_H_
|
||||||
|
|
|
@ -42,28 +42,20 @@
|
||||||
|
|
||||||
/*static*/ nsSVGTransformSMILType nsSVGTransformSMILType::sSingleton;
|
/*static*/ nsSVGTransformSMILType nsSVGTransformSMILType::sSingleton;
|
||||||
|
|
||||||
|
typedef nsTArray<nsSVGSMILTransform> TransformArray;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// nsISMILType implementation
|
// nsISMILType implementation
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsSVGTransformSMILType::Init(nsSMILValue &aValue) const
|
nsSVGTransformSMILType::Init(nsSMILValue &aValue) const
|
||||||
{
|
{
|
||||||
NS_PRECONDITION(aValue.mType == this || aValue.IsNull(),
|
NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");
|
||||||
"Unexpected value type");
|
|
||||||
NS_ASSERTION(aValue.mType != this || aValue.mU.mPtr,
|
|
||||||
"Invalid nsSMILValue of SVG transform type: NULL data member");
|
|
||||||
|
|
||||||
if (aValue.mType != this || !aValue.mU.mPtr) {
|
|
||||||
// Different type, or no data member: allocate memory and set type
|
|
||||||
TransformArray* transforms = new TransformArray(1);
|
TransformArray* transforms = new TransformArray(1);
|
||||||
NS_ENSURE_TRUE(transforms, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(transforms, NS_ERROR_OUT_OF_MEMORY);
|
||||||
aValue.mU.mPtr = transforms;
|
aValue.mU.mPtr = transforms;
|
||||||
aValue.mType = this;
|
aValue.mType = this;
|
||||||
} else {
|
|
||||||
// Same type, just set clear
|
|
||||||
TransformArray* transforms = static_cast<TransformArray*>(aValue.mU.mPtr);
|
|
||||||
transforms->Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -313,10 +305,11 @@ nsSVGTransformSMILType::Interpolate(const nsSMILValue& aStartVal,
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Transform array accessors
|
// Transform array accessors
|
||||||
|
|
||||||
|
// static
|
||||||
PRUint32
|
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 =
|
const TransformArray& transforms =
|
||||||
*static_cast<const TransformArray*>(aValue.mU.mPtr);
|
*static_cast<const TransformArray*>(aValue.mU.mPtr);
|
||||||
|
@ -324,11 +317,12 @@ nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue) const
|
||||||
return transforms.Length();
|
return transforms.Length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
const nsSVGSMILTransform*
|
const nsSVGSMILTransform*
|
||||||
nsSVGTransformSMILType::GetTransformAt(PRUint32 aIndex,
|
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 =
|
const TransformArray& transforms =
|
||||||
*static_cast<const TransformArray*>(aValue.mU.mPtr);
|
*static_cast<const TransformArray*>(aValue.mU.mPtr);
|
||||||
|
@ -341,16 +335,14 @@ nsSVGTransformSMILType::GetTransformAt(PRUint32 aIndex,
|
||||||
return &transforms[aIndex];
|
return &transforms[aIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
nsSVGTransformSMILType::AppendTransform(const nsSVGSMILTransform& aTransform,
|
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<TransformArray*>(aValue.mU.mPtr);
|
TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr);
|
||||||
|
return transforms.AppendElement(aTransform) ?
|
||||||
nsSVGSMILTransform* transform = transforms.AppendElement(aTransform);
|
NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||||
NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,12 @@ class nsSMILValue;
|
||||||
class nsSVGTransformSMILType : public nsISMILType
|
class nsSVGTransformSMILType : public nsISMILType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// nsISMILType
|
// Singleton for nsSMILValue objects to hold onto.
|
||||||
|
static nsSVGTransformSMILType sSingleton;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// nsISMILType Methods
|
||||||
|
// -------------------
|
||||||
virtual nsresult Init(nsSMILValue& aValue) const;
|
virtual nsresult Init(nsSMILValue& aValue) const;
|
||||||
virtual void Destroy(nsSMILValue& aValue) const;
|
virtual void Destroy(nsSMILValue& aValue) const;
|
||||||
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
||||||
|
@ -122,20 +127,22 @@ public:
|
||||||
const nsSMILValue& aEndVal,
|
const nsSMILValue& aEndVal,
|
||||||
double aUnitDistance,
|
double aUnitDistance,
|
||||||
nsSMILValue& aResult) const;
|
nsSMILValue& aResult) const;
|
||||||
|
|
||||||
|
public:
|
||||||
// Transform array accessors
|
// Transform array accessors
|
||||||
PRUint32 GetNumTransforms(const nsSMILValue& aValue) const;
|
// -------------------------
|
||||||
const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex,
|
static PRUint32 GetNumTransforms(const nsSMILValue& aValue);
|
||||||
const nsSMILValue& aValue) const;
|
static const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex,
|
||||||
nsresult AppendTransform(const nsSVGSMILTransform& aTransform,
|
const nsSMILValue& aValue);
|
||||||
nsSMILValue& aValue) const;
|
static nsresult AppendTransform(const nsSVGSMILTransform& aTransform,
|
||||||
|
nsSMILValue& aValue);
|
||||||
|
|
||||||
static nsSVGTransformSMILType sSingleton;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
typedef nsTArray<nsSVGSMILTransform> TransformArray;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Private constructor & destructor: prevent instances beyond my singleton,
|
||||||
|
// and prevent others from deleting my singleton.
|
||||||
nsSVGTransformSMILType() {}
|
nsSVGTransformSMILType() {}
|
||||||
|
~nsSVGTransformSMILType() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NS_SVGTRANSFORMSMILTYPE_H_
|
#endif // NS_SVGTRANSFORMSMILTYPE_H_
|
||||||
|
|
|
@ -52,6 +52,7 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||||
const debug = false;
|
const debug = false;
|
||||||
|
|
||||||
var expectedConsoleMessages = [];
|
var expectedConsoleMessages = [];
|
||||||
|
var expectLoggedMessages = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].
|
const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].
|
||||||
|
@ -88,6 +89,9 @@ function test_template()
|
||||||
if (needsOpen)
|
if (needsOpen)
|
||||||
root.open = true;
|
root.open = true;
|
||||||
|
|
||||||
|
if (expectLoggedMessages)
|
||||||
|
expectLoggedMessages();
|
||||||
|
|
||||||
checkResults(root, 0);
|
checkResults(root, 0);
|
||||||
|
|
||||||
if (changes.length) {
|
if (changes.length) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<window title="XUL Template Tests" width="500" height="600"
|
<window title="XUL Template Tests" width="500" height="600"
|
||||||
onload="expectLoggedMessages(); test_template();"
|
onload="test_template();"
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||||
<script type="application/javascript"
|
<script type="application/javascript"
|
||||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||||
|
@ -37,7 +37,7 @@ var expectedOutput =
|
||||||
Components.classes["@mozilla.org/consoleservice;1"].
|
Components.classes["@mozilla.org/consoleservice;1"].
|
||||||
getService(Components.interfaces.nsIConsoleService).reset();
|
getService(Components.interfaces.nsIConsoleService).reset();
|
||||||
|
|
||||||
function expectLoggedMessages()
|
expectLoggedMessages = function()
|
||||||
{
|
{
|
||||||
// check log to ensure that two rows have been added
|
// check log to ensure that two rows have been added
|
||||||
var initialNumber = Number(document.getElementById("root").firstChild.nextSibling.id.substring(3));
|
var initialNumber = Number(document.getElementById("root").firstChild.nextSibling.id.substring(3));
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<body onload="test();">
|
||||||
|
<script>
|
||||||
|
function test() {
|
||||||
|
// Test that calling pushState() with a state object which calls
|
||||||
|
// history.back() doesn't crash. We need to make sure that there's at least
|
||||||
|
// one entry in the history before we do anything else.
|
||||||
|
history.pushState(null, "");
|
||||||
|
|
||||||
|
x = {};
|
||||||
|
x.toJSON = { history.back(); return "{a:1}"; };
|
||||||
|
history.pushState(x, "");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -6,3 +6,4 @@ load 430628-1.html
|
||||||
load 432114-1.html
|
load 432114-1.html
|
||||||
load 432114-2.html
|
load 432114-2.html
|
||||||
load 436900-1.html
|
load 436900-1.html
|
||||||
|
load 500328-1.html
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
#include "nsIURIClassifier.h"
|
#include "nsIURIClassifier.h"
|
||||||
#include "nsIOfflineCacheUpdate.h"
|
#include "nsIOfflineCacheUpdate.h"
|
||||||
#include "nsCPrefetchService.h"
|
#include "nsCPrefetchService.h"
|
||||||
|
#include "nsJSON.h"
|
||||||
|
|
||||||
// we want to explore making the document own the load group
|
// we want to explore making the document own the load group
|
||||||
// so we can associate the document URI with 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);
|
ForEachPing(content, SendPing, &info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
//*** nsDocShell: Object Management
|
//*** nsDocShell: Object Management
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
@ -863,6 +866,14 @@ NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
|
||||||
mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
|
mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
|
||||||
return *aSink ? NS_OK : NS_NOINTERFACE;
|
return *aSink ? NS_OK : NS_NOINTERFACE;
|
||||||
}
|
}
|
||||||
|
else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
|
||||||
|
NS_SUCCEEDED(EnsureContentViewer())) {
|
||||||
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||||
|
mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
|
||||||
|
if (!domDoc)
|
||||||
|
return NS_NOINTERFACE;
|
||||||
|
return domDoc->QueryInterface(aIID, aSink);
|
||||||
|
}
|
||||||
else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
|
else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
|
||||||
*aSink = nsnull;
|
*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
|
// 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
|
// 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
|
// 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.
|
// LOAD_BYPASS_HISTORY.
|
||||||
PRBool inOnLoadHandler=PR_FALSE;
|
PRBool inOnLoadHandler=PR_FALSE;
|
||||||
parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
|
parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
|
||||||
|
@ -3226,11 +3237,11 @@ nsDocShell::GetChildSHEntry(PRInt32 aChildOffset, nsISHEntry ** aResult)
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
|
nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
|
||||||
PRInt32 aChildOffset)
|
PRInt32 aChildOffset, PRUint32 loadType)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
if (mLSHE) {
|
if (mLSHE && loadType != LOAD_PUSHSTATE) {
|
||||||
/* You get here if you are currently building a
|
/* You get here if you are currently building a
|
||||||
* hierarchy ie.,you just visited a frameset page
|
* hierarchy ie.,you just visited a frameset page
|
||||||
*/
|
*/
|
||||||
|
@ -3285,7 +3296,8 @@ nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
|
||||||
nsCOMPtr<nsIDocShellHistory> parent =
|
nsCOMPtr<nsIDocShellHistory> parent =
|
||||||
do_QueryInterface(GetAsSupports(mParent), &rv);
|
do_QueryInterface(GetAsSupports(mParent), &rv);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset);
|
rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
|
||||||
|
loadType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -3313,7 +3325,7 @@ nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, PRInt32 aChildOffset)
|
||||||
nsCOMPtr<nsIDocShellHistory> parent =
|
nsCOMPtr<nsIDocShellHistory> parent =
|
||||||
do_QueryInterface(GetAsSupports(mParent), &rv);
|
do_QueryInterface(GetAsSupports(mParent), &rv);
|
||||||
if (parent) {
|
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
|
NS_IMETHODIMP
|
||||||
nsDocShell::LoadURI(const PRUnichar * aURI,
|
nsDocShell::LoadURI(const PRUnichar * aURI,
|
||||||
PRUint32 aLoadFlags,
|
PRUint32 aLoadFlags,
|
||||||
|
@ -3846,6 +3857,13 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
|
||||||
mFailedURI = aURI;
|
mFailedURI = aURI;
|
||||||
mFailedLoadType = mLoadType;
|
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 url;
|
||||||
nsCAutoString charset;
|
nsCAutoString charset;
|
||||||
if (aURI)
|
if (aURI)
|
||||||
|
@ -5714,13 +5732,13 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
|
||||||
// We're done with the URI classifier for this channel
|
// We're done with the URI classifier for this channel
|
||||||
mClassifier = nsnull;
|
mClassifier = nsnull;
|
||||||
|
|
||||||
//
|
// Notify the ContentViewer that the Document has finished loading. This
|
||||||
// Notify the ContentViewer that the Document has finished loading...
|
// will cause any OnLoad(...) and PopState(...) handlers to fire.
|
||||||
//
|
|
||||||
// This will cause any OnLoad(...) handlers to fire, if it is a HTML
|
|
||||||
// document...
|
|
||||||
//
|
|
||||||
if (!mEODForCurrentDocument && mContentViewer) {
|
if (!mEODForCurrentDocument && mContentViewer) {
|
||||||
|
// Set the pending state object which will be returned to the page in
|
||||||
|
// the popstate event.
|
||||||
|
SetDocPendingStateObj(mLSHE);
|
||||||
|
|
||||||
mIsExecutingOnLoadHandler = PR_TRUE;
|
mIsExecutingOnLoadHandler = PR_TRUE;
|
||||||
mContentViewer->LoadComplete(aStatus);
|
mContentViewer->LoadComplete(aStatus);
|
||||||
mIsExecutingOnLoadHandler = PR_FALSE;
|
mIsExecutingOnLoadHandler = PR_FALSE;
|
||||||
|
@ -7368,6 +7386,26 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsDocShell::SetDocPendingStateObj(nsISHEntry *shEntry)
|
||||||
|
{
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDocument> 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
|
nsresult
|
||||||
nsDocShell::CheckLoadingPermissions()
|
nsDocShell::CheckLoadingPermissions()
|
||||||
|
@ -7845,19 +7883,42 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((aLoadType == LOAD_NORMAL ||
|
if (aLoadType == LOAD_NORMAL ||
|
||||||
aLoadType == LOAD_STOP_CONTENT ||
|
aLoadType == LOAD_STOP_CONTENT ||
|
||||||
LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
|
LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
|
||||||
aLoadType == LOAD_HISTORY ||
|
aLoadType == LOAD_HISTORY ||
|
||||||
aLoadType == LOAD_LINK) && allowScroll) {
|
aLoadType == LOAD_LINK) {
|
||||||
|
|
||||||
PRBool wasAnchor = PR_FALSE;
|
PRBool wasAnchor = PR_FALSE;
|
||||||
PRBool doHashchange = PR_FALSE;
|
PRBool doHashchange = PR_FALSE;
|
||||||
nscoord cx, cy;
|
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;
|
mLoadType = aLoadType;
|
||||||
mURIResultedInDocument = PR_TRUE;
|
mURIResultedInDocument = PR_TRUE;
|
||||||
|
|
||||||
|
@ -7877,6 +7938,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
||||||
mOSHE->GetOwner(getter_AddRefs(owner));
|
mOSHE->GetOwner(getter_AddRefs(owner));
|
||||||
}
|
}
|
||||||
OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE);
|
OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE);
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> postData;
|
nsCOMPtr<nsIInputStream> postData;
|
||||||
PRUint32 pageIdent = PR_UINT32_MAX;
|
PRUint32 pageIdent = PR_UINT32_MAX;
|
||||||
nsCOMPtr<nsISupports> cacheKey;
|
nsCOMPtr<nsISupports> cacheKey;
|
||||||
|
@ -7895,6 +7957,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
||||||
mOSHE->GetPageIdentifier(&pageIdent);
|
mOSHE->GetPageIdentifier(&pageIdent);
|
||||||
mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
|
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
|
/* Assign mOSHE to mLSHE. This will either be a new entry created
|
||||||
|
@ -7949,11 +8022,26 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
||||||
shEntry->SetTitle(mTitle);
|
shEntry->SetTitle(mTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doHashchange) {
|
if (sameDocIdent) {
|
||||||
nsCOMPtr<nsPIDOMWindow> window =
|
// Set the doc's URI according to the new history entry's URI
|
||||||
do_QueryInterface(mScriptGlobal);
|
nsCOMPtr<nsIURI> newURI;
|
||||||
|
mOSHE->GetURI(getter_AddRefs(newURI));
|
||||||
|
NS_ENSURE_TRUE(newURI, NS_ERROR_FAILURE);
|
||||||
|
nsCOMPtr<nsIDocument> doc =
|
||||||
|
do_GetInterface(GetAsSupports(this));
|
||||||
|
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
if (window)
|
doc->SetDocumentURI(newURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDocPendingStateObj(mOSHE);
|
||||||
|
|
||||||
|
// Dispatch the popstate and hashchange events, as appropriate
|
||||||
|
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobal);
|
||||||
|
if (window) {
|
||||||
|
window->DispatchSyncPopState();
|
||||||
|
|
||||||
|
if (doHashchange)
|
||||||
window->DispatchSyncHashchange();
|
window->DispatchSyncHashchange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8837,6 +8925,14 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
|
||||||
if (uploadChannel) {
|
if (uploadChannel) {
|
||||||
uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
|
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
|
/* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in
|
||||||
|
@ -8895,7 +8991,6 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
|
||||||
SetHistoryEntry(&mLSHE, mOSHE);
|
SetHistoryEntry(&mLSHE, mOSHE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If the user pressed shift-reload, cache will create a new cache key
|
/* If the user pressed shift-reload, cache will create a new cache key
|
||||||
* for the page. Save the new cacheKey in Session History.
|
* for the page. Save the new cacheKey in Session History.
|
||||||
* see bug 90098
|
* see bug 90098
|
||||||
|
@ -8986,6 +9081,282 @@ nsDocShell::SetReferrerURI(nsIURI * aURI)
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// nsDocShell: Session History
|
// 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<nsIDocument> 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<nsIJSContextStack> contextStack =
|
||||||
|
do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
contextStack->Push(cx);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIJSON> 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 <path>, <query>, and
|
||||||
|
// <fragment> 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<nsIDocument> 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<nsIURI> oldURI = mCurrentURI;
|
||||||
|
nsCOMPtr<nsIURI> 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<nsIScriptSecurityManager> 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<nsIScriptObjectPrincipal> docScriptObj =
|
||||||
|
do_QueryInterface(document);
|
||||||
|
|
||||||
|
if (!docScriptObj) {
|
||||||
|
return NS_ERROR_DOM_SECURITY_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPrincipal> 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<nsISHistory> 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<nsISHistoryInternal> 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<nsISHEntry> oldOSHE = mOSHE;
|
||||||
|
|
||||||
|
nsCOMPtr<nsISHEntry> 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<nsISHistory> rootSH;
|
||||||
|
GetRootSessionHistory(getter_AddRefs(rootSH));
|
||||||
|
NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
nsCOMPtr<nsISHistoryInternal> 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
|
PRBool
|
||||||
nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
|
nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
|
||||||
{
|
{
|
||||||
|
@ -9428,7 +9799,6 @@ nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
|
nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
|
||||||
{
|
{
|
||||||
|
@ -9679,9 +10049,6 @@ nsresult
|
||||||
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||||
nsIChannel * aChannel)
|
nsIChannel * aChannel)
|
||||||
{
|
{
|
||||||
if (mItemType != typeContent || !mGlobalHistory)
|
|
||||||
return NS_OK;
|
|
||||||
|
|
||||||
// If this is a POST request, we do not want to include this in global
|
// If this is a POST request, we do not want to include this in global
|
||||||
// history, so return early.
|
// history, so return early.
|
||||||
nsCOMPtr<nsIHttpChannel> hchan(do_QueryInterface(aChannel));
|
nsCOMPtr<nsIHttpChannel> hchan(do_QueryInterface(aChannel));
|
||||||
|
@ -9692,16 +10059,26 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIURI> 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;
|
PRBool visited;
|
||||||
nsresult rv = mGlobalHistory->IsVisited(aURI, &visited);
|
nsresult rv = mGlobalHistory->IsVisited(aURI, &visited);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> referrer;
|
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), aReferrer);
|
||||||
if (aChannel)
|
|
||||||
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
|
|
||||||
|
|
||||||
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), referrer);
|
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
|
@ -9714,6 +10091,7 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
|
|
|
@ -364,6 +364,10 @@ protected:
|
||||||
PRUint32 aLoadType, nscoord *cx, nscoord *cy,
|
PRUint32 aLoadType, nscoord *cx, nscoord *cy,
|
||||||
PRBool * aDoHashchange);
|
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,
|
// Returns PR_TRUE if would have called FireOnLocationChange,
|
||||||
// but did not because aFireOnLocationChange was false on entry.
|
// but did not because aFireOnLocationChange was false on entry.
|
||||||
// In this case it is the caller's responsibility to ensure
|
// In this case it is the caller's responsibility to ensure
|
||||||
|
@ -465,8 +469,11 @@ protected:
|
||||||
PRUint32 aStateFlags);
|
PRUint32 aStateFlags);
|
||||||
|
|
||||||
// Global History
|
// Global History
|
||||||
|
|
||||||
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||||
nsIChannel * aChannel);
|
nsIChannel * aChannel);
|
||||||
|
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||||
|
nsIURI * aReferrer);
|
||||||
|
|
||||||
// Helper Routines
|
// Helper Routines
|
||||||
nsresult ConfirmRepost(PRBool * aRepost);
|
nsresult ConfirmRepost(PRBool * aRepost);
|
||||||
|
@ -515,6 +522,11 @@ protected:
|
||||||
nsIChannel * aChannel,
|
nsIChannel * aChannel,
|
||||||
nsresult aResult);
|
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();
|
nsresult CheckLoadingPermissions();
|
||||||
|
|
||||||
// Security checks to prevent frameset spoofing. See comments at
|
// Security checks to prevent frameset spoofing. See comments at
|
||||||
|
|
|
@ -92,6 +92,7 @@ enum LoadType {
|
||||||
LOAD_BYPASS_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_HISTORY),
|
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 = 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_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
|
* Load type for an error page. These loads are never triggered by users of
|
||||||
* Docshell. Instead, Docshell triggers the load itself when a
|
* 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_BYPASS_HISTORY:
|
||||||
case LOAD_STOP_CONTENT:
|
case LOAD_STOP_CONTENT:
|
||||||
case LOAD_STOP_CONTENT_AND_REPLACE:
|
case LOAD_STOP_CONTENT_AND_REPLACE:
|
||||||
|
case LOAD_PUSHSTATE:
|
||||||
case LOAD_ERROR_PAGE:
|
case LOAD_ERROR_PAGE:
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,9 @@ interface nsISecureBrowserUI;
|
||||||
interface nsIDOMStorage;
|
interface nsIDOMStorage;
|
||||||
interface nsIPrincipal;
|
interface nsIPrincipal;
|
||||||
interface nsIWebBrowserPrint;
|
interface nsIWebBrowserPrint;
|
||||||
|
interface nsIVariant;
|
||||||
|
|
||||||
[scriptable, uuid(c95eaff1-14e6-4db1-a806-46be97d5a9b6)]
|
[scriptable, uuid(3adde256-05a9-43a7-a190-f8fe75eecfd6)]
|
||||||
interface nsIDocShell : nsISupports
|
interface nsIDocShell : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -169,6 +170,13 @@ interface nsIDocShell : nsISupports
|
||||||
out nsIDocShell aDocShell,
|
out nsIDocShell aDocShell,
|
||||||
out nsIRequest aRequest);
|
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
|
* Creates a DocShellLoadInfo object that you can manipulate and then pass
|
||||||
* to loadURI.
|
* to loadURI.
|
||||||
|
@ -342,6 +350,7 @@ interface nsIDocShell : nsISupports
|
||||||
const unsigned long LOAD_CMD_NORMAL = 0x1; // Normal load
|
const unsigned long LOAD_CMD_NORMAL = 0x1; // Normal load
|
||||||
const unsigned long LOAD_CMD_RELOAD = 0x2; // Reload
|
const unsigned long LOAD_CMD_RELOAD = 0x2; // Reload
|
||||||
const unsigned long LOAD_CMD_HISTORY = 0x4; // Load from history
|
const unsigned long LOAD_CMD_HISTORY = 0x4; // Load from history
|
||||||
|
const unsigned long LOAD_CMD_PUSHSTATE = 0x8; // History.pushState()
|
||||||
|
|
||||||
readonly attribute unsigned long busyFlags;
|
readonly attribute unsigned long busyFlags;
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
interface nsISHEntry;
|
interface nsISHEntry;
|
||||||
|
|
||||||
[scriptable, uuid(89caa9f0-8b1c-47fb-b0d3-f0aef0bff749)]
|
[scriptable, uuid(a89b80a8-3c44-4a25-9d2c-2fb42358b46e)]
|
||||||
interface nsIDocShellHistory : nsISupports
|
interface nsIDocShellHistory : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -48,11 +48,12 @@ interface nsIDocShellHistory : nsISupports
|
||||||
nsISHEntry getChildSHEntry(in long aChildOffset);
|
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,
|
void addChildSHEntry(in nsISHEntry aCloneReference,
|
||||||
in nsISHEntry aHistoryEntry,
|
in nsISHEntry aHistoryEntry,
|
||||||
in long aChildOffset);
|
in long aChildOffset,
|
||||||
|
in unsigned long aLoadType);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Whether this docshell should save entries in global history.
|
* Whether this docshell should save entries in global history.
|
||||||
|
|
|
@ -58,7 +58,7 @@ class nsDocShellEditorData;
|
||||||
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
|
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
|
||||||
|
|
||||||
|
|
||||||
[scriptable, uuid(09fecea6-5453-43ba-bf91-3ff32618f037)]
|
[scriptable, uuid(62b0603f-57ca-439e-a0fb-6f6978500755)]
|
||||||
interface nsISHEntry : nsIHistoryEntry
|
interface nsISHEntry : nsIHistoryEntry
|
||||||
{
|
{
|
||||||
/** URI for the document */
|
/** URI for the document */
|
||||||
|
@ -149,6 +149,21 @@ interface nsISHEntry : nsIHistoryEntry
|
||||||
*/
|
*/
|
||||||
attribute unsigned long pageIdentifier;
|
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 to set and get the cache key for the entry */
|
||||||
attribute nsISupports cacheKey;
|
attribute nsISupports cacheKey;
|
||||||
|
|
||||||
|
@ -192,6 +207,12 @@ interface nsISHEntry : nsIHistoryEntry
|
||||||
*/
|
*/
|
||||||
attribute nsISupports owner;
|
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
|
* Gets the owning pointer to the editor data assosicated with
|
||||||
* this shistory entry. This forgets its pointer, so free it when
|
* this shistory entry. This forgets its pointer, so free it when
|
||||||
|
|
|
@ -75,6 +75,7 @@ protected:
|
||||||
|
|
||||||
static HistoryTracker *gHistoryTracker = nsnull;
|
static HistoryTracker *gHistoryTracker = nsnull;
|
||||||
static PRUint32 gEntryID = 0;
|
static PRUint32 gEntryID = 0;
|
||||||
|
static PRUint64 gEntryDocIdentifier = 0;
|
||||||
|
|
||||||
nsresult nsSHEntry::Startup()
|
nsresult nsSHEntry::Startup()
|
||||||
{
|
{
|
||||||
|
@ -104,6 +105,7 @@ nsSHEntry::nsSHEntry()
|
||||||
: mLoadType(0)
|
: mLoadType(0)
|
||||||
, mID(gEntryID++)
|
, mID(gEntryID++)
|
||||||
, mPageIdentifier(mID)
|
, mPageIdentifier(mID)
|
||||||
|
, mDocIdentifier(gEntryDocIdentifier++)
|
||||||
, mScrollPositionX(0)
|
, mScrollPositionX(0)
|
||||||
, mScrollPositionY(0)
|
, mScrollPositionY(0)
|
||||||
, mIsFrameNavigation(PR_FALSE)
|
, mIsFrameNavigation(PR_FALSE)
|
||||||
|
@ -125,6 +127,7 @@ nsSHEntry::nsSHEntry(const nsSHEntry &other)
|
||||||
, mLoadType(0) // XXX why not copy?
|
, mLoadType(0) // XXX why not copy?
|
||||||
, mID(other.mID)
|
, mID(other.mID)
|
||||||
, mPageIdentifier(other.mPageIdentifier)
|
, mPageIdentifier(other.mPageIdentifier)
|
||||||
|
, mDocIdentifier(other.mDocIdentifier)
|
||||||
, mScrollPositionX(0) // XXX why not copy?
|
, mScrollPositionX(0) // XXX why not copy?
|
||||||
, mScrollPositionY(0) // XXX why not copy?
|
, mScrollPositionY(0) // XXX why not copy?
|
||||||
, mIsFrameNavigation(other.mIsFrameNavigation)
|
, mIsFrameNavigation(other.mIsFrameNavigation)
|
||||||
|
@ -393,6 +396,30 @@ NS_IMETHODIMP nsSHEntry::SetPageIdentifier(PRUint32 aPageIdentifier)
|
||||||
return NS_OK;
|
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)
|
NS_IMETHODIMP nsSHEntry::GetIsSubFrame(PRBool * aFlag)
|
||||||
{
|
{
|
||||||
*aFlag = mIsFrameNavigation;
|
*aFlag = mIsFrameNavigation;
|
||||||
|
@ -866,3 +893,17 @@ nsSHEntry::HasDetachedEditor()
|
||||||
return mEditorData != nsnull;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,7 @@ private:
|
||||||
PRUint32 mLoadType;
|
PRUint32 mLoadType;
|
||||||
PRUint32 mID;
|
PRUint32 mID;
|
||||||
PRUint32 mPageIdentifier;
|
PRUint32 mPageIdentifier;
|
||||||
|
PRInt64 mDocIdentifier;
|
||||||
PRInt32 mScrollPositionX;
|
PRInt32 mScrollPositionX;
|
||||||
PRInt32 mScrollPositionY;
|
PRInt32 mScrollPositionY;
|
||||||
PRPackedBool mIsFrameNavigation;
|
PRPackedBool mIsFrameNavigation;
|
||||||
|
@ -115,6 +116,7 @@ private:
|
||||||
nsCOMPtr<nsISupports> mOwner;
|
nsCOMPtr<nsISupports> mOwner;
|
||||||
nsExpirationState mExpirationState;
|
nsExpirationState mExpirationState;
|
||||||
nsAutoPtr<nsDocShellEditorData> mEditorData;
|
nsAutoPtr<nsDocShellEditorData> mEditorData;
|
||||||
|
nsString mStateData;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* nsSHEntry_h */
|
#endif /* nsSHEntry_h */
|
||||||
|
|
|
@ -492,9 +492,10 @@ nsSHistory::PrintHistory()
|
||||||
uri->GetSpec(url);
|
uri->GetSpec(url);
|
||||||
|
|
||||||
printf("**** SH Transaction #%d, Entry = %x\n", index, entry.get());
|
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 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
|
#endif
|
||||||
|
|
||||||
nsCOMPtr<nsISHTransaction> next;
|
nsCOMPtr<nsISHTransaction> next;
|
||||||
|
@ -1223,7 +1224,6 @@ nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd)
|
||||||
docShell = mRootDocShell;
|
docShell = mRootDocShell;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!docShell) {
|
if (!docShell) {
|
||||||
// we did not successfully go to the proper index.
|
// we did not successfully go to the proper index.
|
||||||
// return error.
|
// return error.
|
||||||
|
@ -1235,8 +1235,6 @@ nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd)
|
||||||
return InitiateLoad(nextEntry, docShell, aLoadType);
|
return InitiateLoad(nextEntry, docShell, aLoadType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound)
|
nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound)
|
||||||
{
|
{
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
#include "nsIDOMNSEvent.h"
|
#include "nsIDOMNSEvent.h"
|
||||||
#include "nsIDOMKeyEvent.h"
|
#include "nsIDOMKeyEvent.h"
|
||||||
#include "nsIDOMEventListener.h"
|
#include "nsIDOMEventListener.h"
|
||||||
|
#include "nsIDOMPopStateEvent.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsDOMWindowUtils.h"
|
#include "nsDOMWindowUtils.h"
|
||||||
|
|
||||||
|
@ -1330,13 +1331,15 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||||
|
|
||||||
NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
|
NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
|
||||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
|
NS_DEFINE_CLASSINFO_DATA(PopStateEvent, nsDOMGenericSH,
|
||||||
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH,
|
NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH,
|
||||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
NS_DEFINE_CLASSINFO_DATA(TransitionEvent, nsDOMGenericSH,
|
NS_DEFINE_CLASSINFO_DATA(TransitionEvent, nsDOMGenericSH,
|
||||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Objects that shuld be constructable through |new Name();|
|
// Objects that should be constructable through |new Name();|
|
||||||
struct nsContractIDMapData
|
struct nsContractIDMapData
|
||||||
{
|
{
|
||||||
PRInt32 mDOMClassInfoID;
|
PRInt32 mDOMClassInfoID;
|
||||||
|
@ -1420,6 +1423,7 @@ jsval nsDOMClassInfo::sOnreset_id = JSVAL_VOID;
|
||||||
jsval nsDOMClassInfo::sOnchange_id = JSVAL_VOID;
|
jsval nsDOMClassInfo::sOnchange_id = JSVAL_VOID;
|
||||||
jsval nsDOMClassInfo::sOnselect_id = JSVAL_VOID;
|
jsval nsDOMClassInfo::sOnselect_id = JSVAL_VOID;
|
||||||
jsval nsDOMClassInfo::sOnload_id = JSVAL_VOID;
|
jsval nsDOMClassInfo::sOnload_id = JSVAL_VOID;
|
||||||
|
jsval nsDOMClassInfo::sOnpopstate_id = JSVAL_VOID;
|
||||||
jsval nsDOMClassInfo::sOnbeforeunload_id = JSVAL_VOID;
|
jsval nsDOMClassInfo::sOnbeforeunload_id = JSVAL_VOID;
|
||||||
jsval nsDOMClassInfo::sOnunload_id = JSVAL_VOID;
|
jsval nsDOMClassInfo::sOnunload_id = JSVAL_VOID;
|
||||||
jsval nsDOMClassInfo::sOnhashchange_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(sOnchange_id, cx, "onchange");
|
||||||
SET_JSVAL_TO_STRING(sOnselect_id, cx, "onselect");
|
SET_JSVAL_TO_STRING(sOnselect_id, cx, "onselect");
|
||||||
SET_JSVAL_TO_STRING(sOnload_id, cx, "onload");
|
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(sOnbeforeunload_id, cx, "onbeforeunload");
|
||||||
SET_JSVAL_TO_STRING(sOnunload_id, cx, "onunload");
|
SET_JSVAL_TO_STRING(sOnunload_id, cx, "onunload");
|
||||||
SET_JSVAL_TO_STRING(sOnhashchange_id, cx, "onhashchange");
|
SET_JSVAL_TO_STRING(sOnhashchange_id, cx, "onhashchange");
|
||||||
|
@ -2232,6 +2237,11 @@ nsDOMClassInfo::Init()
|
||||||
DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
|
DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
|
||||||
DOM_CLASSINFO_MAP_END
|
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_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
|
||||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
|
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
|
||||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLDocument)
|
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLDocument)
|
||||||
|
@ -7327,7 +7337,8 @@ nsEventReceiverSH::ReallyIsEventName(jsval id, jschar aFirstChar)
|
||||||
return (id == sOnpaint_id ||
|
return (id == sOnpaint_id ||
|
||||||
id == sOnpageshow_id ||
|
id == sOnpageshow_id ||
|
||||||
id == sOnpagehide_id ||
|
id == sOnpagehide_id ||
|
||||||
id == sOnpaste_id);
|
id == sOnpaste_id ||
|
||||||
|
id == sOnpopstate_id);
|
||||||
case 'k' :
|
case 'k' :
|
||||||
return (id == sOnkeydown_id ||
|
return (id == sOnkeydown_id ||
|
||||||
id == sOnkeypress_id ||
|
id == sOnkeypress_id ||
|
||||||
|
|
|
@ -327,6 +327,7 @@ protected:
|
||||||
static jsval sOnchange_id;
|
static jsval sOnchange_id;
|
||||||
static jsval sOnselect_id;
|
static jsval sOnselect_id;
|
||||||
static jsval sOnload_id;
|
static jsval sOnload_id;
|
||||||
|
static jsval sOnpopstate_id;
|
||||||
static jsval sOnbeforeunload_id;
|
static jsval sOnbeforeunload_id;
|
||||||
static jsval sOnunload_id;
|
static jsval sOnunload_id;
|
||||||
static jsval sOnhashchange_id;
|
static jsval sOnhashchange_id;
|
||||||
|
|
|
@ -473,6 +473,7 @@ enum nsDOMClassInfoID {
|
||||||
eDOMClassInfo_PaintRequestList_id,
|
eDOMClassInfo_PaintRequestList_id,
|
||||||
|
|
||||||
eDOMClassInfo_ScrollAreaEvent_id,
|
eDOMClassInfo_ScrollAreaEvent_id,
|
||||||
|
eDOMClassInfo_PopStateEvent_id,
|
||||||
|
|
||||||
eDOMClassInfo_EventListenerInfo_id,
|
eDOMClassInfo_EventListenerInfo_id,
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
#include "nsCycleCollector.h"
|
#include "nsCycleCollector.h"
|
||||||
#include "nsCCUncollectableMarker.h"
|
#include "nsCCUncollectableMarker.h"
|
||||||
#include "nsDOMThreadService.h"
|
#include "nsDOMThreadService.h"
|
||||||
|
#include "nsAutoJSValHolder.h"
|
||||||
|
|
||||||
// Interfaces Needed
|
// Interfaces Needed
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
|
@ -112,6 +113,7 @@
|
||||||
#include "nsIDOMKeyEvent.h"
|
#include "nsIDOMKeyEvent.h"
|
||||||
#include "nsIDOMMessageEvent.h"
|
#include "nsIDOMMessageEvent.h"
|
||||||
#include "nsIDOMPopupBlockedEvent.h"
|
#include "nsIDOMPopupBlockedEvent.h"
|
||||||
|
#include "nsIDOMPopStateEvent.h"
|
||||||
#include "nsIDOMOfflineResourceList.h"
|
#include "nsIDOMOfflineResourceList.h"
|
||||||
#include "nsIDOMGeoGeolocation.h"
|
#include "nsIDOMGeoGeolocation.h"
|
||||||
#include "nsPIDOMStorage.h"
|
#include "nsPIDOMStorage.h"
|
||||||
|
@ -169,6 +171,7 @@
|
||||||
#include "nsIXULAppInfo.h"
|
#include "nsIXULAppInfo.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsFocusManager.h"
|
#include "nsFocusManager.h"
|
||||||
|
#include "nsIJSON.h"
|
||||||
#ifdef MOZ_XUL
|
#ifdef MOZ_XUL
|
||||||
#include "nsXULPopupManager.h"
|
#include "nsXULPopupManager.h"
|
||||||
#include "nsIDOMXULControlElement.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 kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
|
||||||
static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
|
static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
|
||||||
|
|
||||||
|
static const char sPopStatePrefStr[] = "browser.history.allowPopState";
|
||||||
|
|
||||||
static PRBool
|
static PRBool
|
||||||
IsAboutBlank(nsIURI* aURI)
|
IsAboutBlank(nsIURI* aURI)
|
||||||
{
|
{
|
||||||
|
@ -655,9 +660,9 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
||||||
mTimeoutPublicIdCounter(1),
|
mTimeoutPublicIdCounter(1),
|
||||||
mTimeoutFiringDepth(0),
|
mTimeoutFiringDepth(0),
|
||||||
mJSObject(nsnull),
|
mJSObject(nsnull),
|
||||||
|
mPendingStorageEventsObsolete(nsnull),
|
||||||
mTimeoutsSuspendDepth(0),
|
mTimeoutsSuspendDepth(0),
|
||||||
mFocusMethod(0),
|
mFocusMethod(0)
|
||||||
mPendingStorageEventsObsolete(nsnull)
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
, mSetOpenerWindowCalled(PR_FALSE)
|
, mSetOpenerWindowCalled(PR_FALSE)
|
||||||
#endif
|
#endif
|
||||||
|
@ -6987,7 +6992,119 @@ nsGlobalWindow::DispatchSyncHashchange()
|
||||||
PR_FALSE, PR_FALSE);
|
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<nsIVariant> 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<nsIDocument> 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<nsIJSON> 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<nsIXPConnect> 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<nsPresContext> presContext;
|
||||||
|
if (shell) {
|
||||||
|
presContext = shell->GetPresContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new popstate event
|
||||||
|
nsCOMPtr<nsIDOMEvent> domEvent;
|
||||||
|
rv = nsEventDispatcher::CreateEvent(presContext, nsnull,
|
||||||
|
NS_LITERAL_STRING("popstateevent"),
|
||||||
|
getter_AddRefs(domEvent));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
|
||||||
|
NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
// Initialize the popstate event, which does bubble but isn't cancellable.
|
||||||
|
nsCOMPtr<nsIDOMPopStateEvent> 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<nsIDOMEventTarget> 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.
|
// child lists. aFrame must be non-null.
|
||||||
static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
|
static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
|
||||||
{
|
{
|
||||||
|
|
|
@ -448,6 +448,8 @@ public:
|
||||||
virtual void SetReadyForFocus();
|
virtual void SetReadyForFocus();
|
||||||
virtual void PageHidden();
|
virtual void PageHidden();
|
||||||
virtual nsresult DispatchSyncHashchange();
|
virtual nsresult DispatchSyncHashchange();
|
||||||
|
virtual nsresult DispatchSyncPopState();
|
||||||
|
|
||||||
virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin);
|
virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin);
|
||||||
|
|
||||||
static PRBool DOMWindowDumpEnabled();
|
static PRBool DOMWindowDumpEnabled();
|
||||||
|
|
|
@ -57,6 +57,13 @@
|
||||||
#include "nsReadableUtils.h"
|
#include "nsReadableUtils.h"
|
||||||
#include "nsDOMClassInfo.h"
|
#include "nsDOMClassInfo.h"
|
||||||
#include "nsContentUtils.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
|
// History class implementation
|
||||||
|
@ -272,6 +279,47 @@ nsHistory::Go(PRInt32 aDelta)
|
||||||
return NS_OK;
|
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<nsIDocShell> 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<nsIDocShell> 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
|
NS_IMETHODIMP
|
||||||
nsHistory::Item(PRUint32 aIndex, nsAString& aReturn)
|
nsHistory::Item(PRUint32 aIndex, nsAString& aReturn)
|
||||||
{
|
{
|
||||||
|
|
|
@ -194,7 +194,6 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
nsCOMPtr<nsISupports> owner;
|
nsCOMPtr<nsISupports> owner;
|
||||||
nsCOMPtr<nsIURI> sourceURI;
|
|
||||||
|
|
||||||
if (cx) {
|
if (cx) {
|
||||||
// No cx means that there's no JS running, or at least no JS that
|
// 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)
|
!principal)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
owner = do_QueryInterface(principal);
|
owner = do_QueryInterface(principal);
|
||||||
principal->GetURI(getter_AddRefs(sourceURI));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create load info
|
// Create load info
|
||||||
|
@ -232,10 +230,12 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
|
||||||
|
|
||||||
loadInfo->SetOwner(owner);
|
loadInfo->SetOwner(owner);
|
||||||
|
|
||||||
// now set the referrer on the loadinfo
|
// Now set the referrer on the loadinfo. We need to do this in order to get
|
||||||
if (sourceURI) {
|
// the correct referrer URI from a document which was pushStated.
|
||||||
|
nsCOMPtr<nsIURI> sourceURI;
|
||||||
|
result = GetURI(getter_AddRefs(sourceURI));
|
||||||
|
if (NS_SUCCEEDED(result))
|
||||||
loadInfo->SetReferrer(sourceURI);
|
loadInfo->SetReferrer(sourceURI);
|
||||||
}
|
|
||||||
|
|
||||||
loadInfo.swap(*aLoadInfo);
|
loadInfo.swap(*aLoadInfo);
|
||||||
|
|
||||||
|
|
|
@ -461,6 +461,10 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual nsresult DispatchSyncHashchange() = 0;
|
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
|
* Tell this window that there is an observer for orientation changes
|
||||||
|
|
|
@ -39,7 +39,9 @@
|
||||||
|
|
||||||
#include "domstubs.idl"
|
#include "domstubs.idl"
|
||||||
|
|
||||||
[scriptable, uuid(896d1d20-b4c4-11d2-bd93-00805f8ae3f4)]
|
interface nsIVariant;
|
||||||
|
|
||||||
|
[scriptable, uuid(208f2af7-9f2e-497c-8a53-9e7803280898)]
|
||||||
interface nsIDOMHistory : nsISupports
|
interface nsIDOMHistory : nsISupports
|
||||||
{
|
{
|
||||||
readonly attribute long length;
|
readonly attribute long length;
|
||||||
|
@ -52,4 +54,10 @@ interface nsIDOMHistory : nsISupports
|
||||||
|
|
||||||
void go([optional] in long aDelta);
|
void go([optional] in long aDelta);
|
||||||
DOMString item(in unsigned long index);
|
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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -83,6 +83,7 @@ XPIDLSRCS = \
|
||||||
nsIDOMOrientationEvent.idl \
|
nsIDOMOrientationEvent.idl \
|
||||||
nsIDOMScrollAreaEvent.idl \
|
nsIDOMScrollAreaEvent.idl \
|
||||||
nsIDOMTransitionEvent.idl \
|
nsIDOMTransitionEvent.idl \
|
||||||
|
nsIDOMPopStateEvent.idl \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
|
@ -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);
|
||||||
|
};
|
|
@ -42,10 +42,18 @@ interface nsIInputStream;
|
||||||
interface nsIOutputStream;
|
interface nsIOutputStream;
|
||||||
interface nsIScriptGlobalObject;
|
interface nsIScriptGlobalObject;
|
||||||
|
|
||||||
|
%{ C++
|
||||||
|
#include "jspubtd.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
native JSVal(jsval);
|
||||||
|
[ptr] native JSValPtr(jsval);
|
||||||
|
[ptr] native JSContext(JSContext);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode and decode JSON text.
|
* Encode and decode JSON text.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(45464c36-efde-4cb5-8e00-07480533ff35)]
|
[scriptable, uuid(6fcf09ee-87d0-42ec-a72a-8d60114e974f)]
|
||||||
interface nsIJSON : nsISupports
|
interface nsIJSON : nsISupports
|
||||||
{
|
{
|
||||||
AString encode(/* in JSObject value */);
|
AString encode(/* in JSObject value */);
|
||||||
|
@ -59,4 +67,9 @@ interface nsIJSON : nsISupports
|
||||||
|
|
||||||
void /* JSObject */ decodeFromStream(in nsIInputStream stream,
|
void /* JSObject */ decodeFromStream(in nsIInputStream stream,
|
||||||
in long contentLength);
|
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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,5 @@ version_label=Version:
|
||||||
mimetype_label=MIME Type
|
mimetype_label=MIME Type
|
||||||
description_label=Description
|
description_label=Description
|
||||||
suffixes_label=Suffixes
|
suffixes_label=Suffixes
|
||||||
enabled_label=Enabled
|
|
||||||
yes_label=Yes
|
yes_label=Yes
|
||||||
no_label=No
|
no_label=No
|
||||||
|
|
|
@ -235,6 +235,10 @@ PluginModuleChild::InitGraphics()
|
||||||
{
|
{
|
||||||
// FIXME/cjones: is this the place for this?
|
// FIXME/cjones: is this the place for this?
|
||||||
#if defined(MOZ_WIDGET_GTK2)
|
#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);
|
gtk_init(0, 0);
|
||||||
|
|
||||||
// GtkPlug is a static class so will leak anyway but this ref makes sure.
|
// GtkPlug is a static class so will leak anyway but this ref makes sure.
|
||||||
|
|
|
@ -149,6 +149,8 @@ PluginModuleParent::WriteExtraDataForMinidump(nsIFile* dumpFile)
|
||||||
pluginFile.substr(filePos).c_str());
|
pluginFile.substr(filePos).c_str());
|
||||||
//TODO: add plugin name and version: bug 539841
|
//TODO: add plugin name and version: bug 539841
|
||||||
// (as PluginName, PluginVersion)
|
// (as PluginName, PluginVersion)
|
||||||
|
WriteExtraDataEntry(stream, "PluginName", "");
|
||||||
|
WriteExtraDataEntry(stream, "PluginVersion", "");
|
||||||
stream->Close();
|
stream->Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,9 @@ CPPSRCS = \
|
||||||
nsJSON.cpp \
|
nsJSON.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
EXPORTS = nsJSON.h \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
FORCE_STATIC_LIB = 1
|
FORCE_STATIC_LIB = 1
|
||||||
|
|
||||||
LOCAL_INCLUDES = \
|
LOCAL_INCLUDES = \
|
||||||
|
|
|
@ -195,6 +195,27 @@ WriteCallback(const jschar *buf, uint32 len, void *data)
|
||||||
return JS_TRUE;
|
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
|
nsresult
|
||||||
nsJSON::EncodeInternal(nsJSONWriter *writer)
|
nsJSON::EncodeInternal(nsJSONWriter *writer)
|
||||||
{
|
{
|
||||||
|
@ -382,6 +403,30 @@ nsJSON::DecodeFromStream(nsIInputStream *aStream, PRInt32 aContentLength)
|
||||||
return DecodeInternal(aStream, aContentLength, PR_TRUE);
|
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
|
nsresult
|
||||||
nsJSON::DecodeInternal(nsIInputStream *aStream,
|
nsJSON::DecodeInternal(nsIInputStream *aStream,
|
||||||
PRInt32 aContentLength,
|
PRInt32 aContentLength,
|
||||||
|
|
|
@ -550,8 +550,8 @@ NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||||
nsDOMStorage::nsDOMStorage()
|
nsDOMStorage::nsDOMStorage()
|
||||||
: mUseDB(PR_FALSE)
|
: mUseDB(PR_FALSE)
|
||||||
, mSessionOnly(PR_TRUE)
|
, mSessionOnly(PR_TRUE)
|
||||||
, mItemsCached(PR_FALSE)
|
|
||||||
, mStorageType(nsPIDOMStorage::Unknown)
|
, mStorageType(nsPIDOMStorage::Unknown)
|
||||||
|
, mItemsCached(PR_FALSE)
|
||||||
, mEventBroadcaster(nsnull)
|
, mEventBroadcaster(nsnull)
|
||||||
{
|
{
|
||||||
mSecurityChecker = this;
|
mSecurityChecker = this;
|
||||||
|
@ -562,10 +562,10 @@ nsDOMStorage::nsDOMStorage()
|
||||||
|
|
||||||
nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
|
nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
|
||||||
: mUseDB(PR_FALSE) // Any clone is not using the database
|
: mUseDB(PR_FALSE) // Any clone is not using the database
|
||||||
, mSessionOnly(PR_TRUE)
|
|
||||||
, mItemsCached(PR_FALSE)
|
|
||||||
, mDomain(aThat.mDomain)
|
, mDomain(aThat.mDomain)
|
||||||
|
, mSessionOnly(PR_TRUE)
|
||||||
, mStorageType(aThat.mStorageType)
|
, mStorageType(aThat.mStorageType)
|
||||||
|
, mItemsCached(PR_FALSE)
|
||||||
#ifdef MOZ_STORAGE
|
#ifdef MOZ_STORAGE
|
||||||
, mScopeDBKey(aThat.mScopeDBKey)
|
, mScopeDBKey(aThat.mScopeDBKey)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -77,6 +77,9 @@ _TEST_FILES = \
|
||||||
postMessage.jar \
|
postMessage.jar \
|
||||||
postMessage.jar^headers^ \
|
postMessage.jar^headers^ \
|
||||||
test_bug477323.html \
|
test_bug477323.html \
|
||||||
|
test_bug500328.html \
|
||||||
|
file_bug500328_1.html \
|
||||||
|
file_bug500328_2.html \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
_CHROME_FILES = \
|
_CHROME_FILES = \
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
Inner frame for testing bug 500328.
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=500328
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>test 1</title>
|
||||||
|
</head>
|
||||||
|
<body onload="load();" onpopstate="popstate(event);">
|
||||||
|
<script type="application/javascript">
|
||||||
|
function load() {
|
||||||
|
if(parent && parent.onChildLoad)
|
||||||
|
parent.onChildLoad();
|
||||||
|
if(opener && opener.onChildLoad)
|
||||||
|
opener.onChildLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
function popstate(e) {
|
||||||
|
if(parent && parent.onChildLoad)
|
||||||
|
parent.onChildPopState(e);
|
||||||
|
if(opener && opener.onChildLoad)
|
||||||
|
opener.onChildPopState(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateTo(loc) {
|
||||||
|
location = loc;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a id="link-anchor1", href="#1">Link Anchor1</a>
|
||||||
|
<a id="link-self" href="file_bug500328_1.html">Self</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
Inner frame for testing bug 500328.
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=500328
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!--
|
||||||
|
Yes, this page is basically blank. But no, about:blank wouldn't do as a
|
||||||
|
replacement, because we use this page to test that pushstate has correct
|
||||||
|
same-origin checks.
|
||||||
|
-->
|
||||||
|
file_bug500328_2.html
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,740 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=500328
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 500328</title>
|
||||||
|
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=500328">Mozilla Bug 500328</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="status"></div>
|
||||||
|
<div id="content">
|
||||||
|
<iframe id="iframe"></iframe>
|
||||||
|
<iframe id="iframe2"></iframe>
|
||||||
|
<a id="link">link</a>
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
<script type="application/javascript;version=1.7">
|
||||||
|
|
||||||
|
/** Test for Bug 500328 **/
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
var iframe = document.getElementById("iframe");
|
||||||
|
var iframeCw = iframe.contentWindow;
|
||||||
|
|
||||||
|
var iframe2 = document.getElementById("iframe2");
|
||||||
|
var iframe2Cw = iframe2.contentWindow;
|
||||||
|
|
||||||
|
var unvisitedColor;
|
||||||
|
var visitedColor;
|
||||||
|
|
||||||
|
var gCallbackOnIframeLoad = false;
|
||||||
|
var gCallbackOnPopState = false;
|
||||||
|
var gNumPopStates = 0;
|
||||||
|
var gLastPopStateEvent;
|
||||||
|
|
||||||
|
var gGen;
|
||||||
|
|
||||||
|
function statusMsg(msg) {
|
||||||
|
var msgElem = document.createElement("p");
|
||||||
|
msgElem.appendChild(document.createTextNode(msg));
|
||||||
|
|
||||||
|
document.getElementById("status").appendChild(msgElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function longWait() {
|
||||||
|
setTimeout(function() { gGen.next(); }, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shortWait() {
|
||||||
|
setTimeout(function() { gGen.next(); }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChildPopState(e) {
|
||||||
|
gNumPopStates++;
|
||||||
|
gLastPopStateEvent = e;
|
||||||
|
if (gCallbackOnPopState) {
|
||||||
|
statusMsg("Popstate(" + JSON.stringify(e.state) + "). Calling gGen.next().");
|
||||||
|
gCallbackOnPopState = false;
|
||||||
|
gGen.next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
statusMsg("Popstate(" + JSON.stringify(e.state) + "). NOT calling gGen.next().");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onChildLoad() {
|
||||||
|
if(gCallbackOnIframeLoad) {
|
||||||
|
statusMsg("Got load. About to call gGen.next().");
|
||||||
|
gCallbackOnIframeLoad = false;
|
||||||
|
gGen.next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
statusMsg("Got load, but not calling gGen.next() because gCallbackOnIframeLoad was false.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableChildLoadCallback() {
|
||||||
|
gCallbackOnIframeLoad = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableChildPopStateCallback() {
|
||||||
|
gCallbackOnPopState = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearPopStateCounter() {
|
||||||
|
gNumPopStates = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function noPopStateExpected(msg) {
|
||||||
|
is(gNumPopStates, 0, msg);
|
||||||
|
|
||||||
|
// Even if there's an error, set gNumPopStates to 0 so other tests don't
|
||||||
|
// fail.
|
||||||
|
gNumPopStates = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function popstateExpected(msg) {
|
||||||
|
is(gNumPopStates, 1, msg);
|
||||||
|
gNumPopStates = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColor(elem) {
|
||||||
|
return document.defaultView.getComputedStyle(elem, "").color;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSHistory(theWindow)
|
||||||
|
{
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
|
||||||
|
const Ci = Components.interfaces;
|
||||||
|
var sh = theWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.sessionHistory;
|
||||||
|
if (!sh || sh == null)
|
||||||
|
throw("Couldn't get shistory for window!");
|
||||||
|
|
||||||
|
return sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChromeWin(theWindow)
|
||||||
|
{
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||||
|
const Ci = Components.interfaces;
|
||||||
|
return theWindow
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||||
|
.rootTreeItem
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindow)
|
||||||
|
.QueryInterface(Ci.nsIDOMChromeWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSHTitle(sh, offset)
|
||||||
|
{
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
|
||||||
|
if (!offset)
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
// False instructs the SHistory not to modify its current index.
|
||||||
|
return sh.getEntryAtIndex(sh.index + offset, false).title;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that win's location ends with str
|
||||||
|
function locationEndsWith(win, str) {
|
||||||
|
var exp = new RegExp(str + "$");
|
||||||
|
ok(win.location.toString().match(exp),
|
||||||
|
"Wrong window location. Expected it to end with " +
|
||||||
|
str + ", but actuall was " + win.location);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectException(func, msg) {
|
||||||
|
var failed = false;
|
||||||
|
try {
|
||||||
|
func();
|
||||||
|
} catch(ex) {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(failed, msg + " succeeded, but should have failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
// We can't enable universal XPConnect privleges in this function, because
|
||||||
|
// test 5 needs to be running at normal privleges in order to test the
|
||||||
|
// same-origin policy.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PRELIMINARY:
|
||||||
|
* 1. Clear the popstate counter
|
||||||
|
* 2. Get the visited and unvisited link colors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
clearPopStateCounter();
|
||||||
|
|
||||||
|
// Set the link's href to somewhere we haven't been so we can get the
|
||||||
|
// unvisited link color.
|
||||||
|
var rand = Date.now() + "-" + Math.random();
|
||||||
|
$("link").href = rand;
|
||||||
|
unvisitedColor = getColor($("link"));
|
||||||
|
statusMsg("Unvisited color is " + unvisitedColor);
|
||||||
|
|
||||||
|
// Set the link's href to our current location so we can get the visited link
|
||||||
|
// color.
|
||||||
|
$("link").href = document.location;
|
||||||
|
visitedColor = getColor($("link"));
|
||||||
|
statusMsg("Visited color is " + visitedColor);
|
||||||
|
isnot(visitedColor, unvisitedColor, "visited/unvisited link colors are the same?");
|
||||||
|
|
||||||
|
// The URL of file_bug500328_1.html on http://localhost:8888
|
||||||
|
var innerLoc;
|
||||||
|
|
||||||
|
// Now we can start the tests
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TEST 1 tests basic pushState functionality
|
||||||
|
*/
|
||||||
|
enableChildLoadCallback();
|
||||||
|
iframeCw.location = "file_bug500328_1.html";
|
||||||
|
yield;
|
||||||
|
innerLoc = iframeCw.location.toString();
|
||||||
|
// Load should be fired before popstate.
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
yield;
|
||||||
|
popstateExpected("Expected initial popstate.");
|
||||||
|
statusMsg("Awake after first popstate.");
|
||||||
|
|
||||||
|
var testObj1 = 42;
|
||||||
|
var testObj2 = 4.2;
|
||||||
|
iframeCw.history.pushState(testObj1, "test 1");
|
||||||
|
is(iframeCw.location.search, "",
|
||||||
|
"First pushstate should leave us where we were.");
|
||||||
|
|
||||||
|
// Make sure that this pushstate doesn't trigger a hashchange.
|
||||||
|
iframeCw.onhashchange = function() {
|
||||||
|
ok(false, "Pushstate shouldn't trigger a hashchange.");
|
||||||
|
};
|
||||||
|
|
||||||
|
iframeCw.history.pushState(testObj2, "test 1#foo", "?test1#foo");
|
||||||
|
is(iframeCw.location.search, "?test1",
|
||||||
|
"Second pushstate should push us to '?test1'.");
|
||||||
|
is(iframeCw.location.hash, "#foo",
|
||||||
|
"Second pushstate should push us to '#foo'");
|
||||||
|
shortWait();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// Let the hashchange event fire, if it's going to.
|
||||||
|
longWait();
|
||||||
|
yield;
|
||||||
|
iframeCw.onhashchange = null;
|
||||||
|
|
||||||
|
statusMsg("About to go back to page 1.");
|
||||||
|
// We don't have to yield here because this back() and the resulting popstate
|
||||||
|
// are completely synchronous. In fact, if we did yield, JS would throw an
|
||||||
|
// error because we'd be calling gGen.next from within gGen.next.
|
||||||
|
iframeCw.history.back();
|
||||||
|
|
||||||
|
statusMsg("Awake after going back to page 1.");
|
||||||
|
popstateExpected("Going back to page 1 should trigger a popstate.");
|
||||||
|
is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj1),
|
||||||
|
"Wrong state object popped after going back to page 1.");
|
||||||
|
ok(iframeCw.location.toString().match(/file_bug500328_1.html$/),
|
||||||
|
"Going back to page 1 hould take us to original page.");
|
||||||
|
|
||||||
|
iframeCw.history.back();
|
||||||
|
popstateExpected("Going back to page 0 should trigger a popstate.");
|
||||||
|
is(gLastPopStateEvent.state, null,
|
||||||
|
"Going back to page 0 should pop a null state.");
|
||||||
|
is(iframeCw.location.search, "",
|
||||||
|
"Going back to page 0 should clear the querystring.");
|
||||||
|
|
||||||
|
iframeCw.history.forward();
|
||||||
|
popstateExpected("Going forward to page 1 should trigger a popstate.");
|
||||||
|
is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj1),
|
||||||
|
"Wrong state object popped after going forward to page 1.");
|
||||||
|
ok(iframeCw.location.toString().match(/file_bug500328_1.html$/),
|
||||||
|
"Going forward to page 1 should leave us at original page.");
|
||||||
|
|
||||||
|
|
||||||
|
statusMsg("About to go forward to page 2.");
|
||||||
|
iframeCw.history.forward();
|
||||||
|
statusMsg("Awake after going forward to page 2.");
|
||||||
|
popstateExpected("Going forward to page 2 should trigger a popstate.");
|
||||||
|
is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj2),
|
||||||
|
"Wrong state object popped after going forward to page 2.");
|
||||||
|
ok(iframeCw.location.toString().match(/file_bug500328_1.html\?test1#foo$/),
|
||||||
|
"Going forward to page 2 took us to " + iframeCw.location.toString());
|
||||||
|
|
||||||
|
// The iframe's current location is file_bug500328_1.html?test1#foo.
|
||||||
|
// Clicking link1 should take us to file_bug500328_1.html?test1#1.
|
||||||
|
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
sendMouseEvent({type:'click'}, 'link-anchor1', iframeCw);
|
||||||
|
yield;
|
||||||
|
popstateExpected("Clicking on link-anchor1 should trigger a popstate.");
|
||||||
|
is(iframeCw.location.search, "?test1",
|
||||||
|
"search should be ?test1 after clicking link.");
|
||||||
|
is(iframeCw.location.hash, "#1",
|
||||||
|
"hash should be #1 after clicking link.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reload file_bug500328_1.html; we're now going to test that link hrefs
|
||||||
|
* and colors are updated correctly on push/popstates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
iframe.onload = onChildLoad;
|
||||||
|
enableChildLoadCallback();
|
||||||
|
iframeCw.location = "about:blank";
|
||||||
|
yield;
|
||||||
|
iframe.onload = null;
|
||||||
|
iframeCw.location = "file_bug500328_1.html";
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
yield;
|
||||||
|
popstateExpected("No popstate after re-loading file_bug500328_1.html");
|
||||||
|
statusMsg("Done loading file_bug500328_1.html for the second time.");
|
||||||
|
|
||||||
|
var ifLink = iframeCw.document.getElementById("link-anchor1");
|
||||||
|
ifLink.href = rand;
|
||||||
|
|
||||||
|
// Poll the document until the link has the correct color, or this test times
|
||||||
|
// out. Unfortunately I can't come up with a more elegant way to do this.
|
||||||
|
// We could listen to MozAfterPaint, but that doesn't guarantee that we'll
|
||||||
|
// observe the new color.
|
||||||
|
while (getColor(ifLink) != unvisitedColor) {
|
||||||
|
// Dump so something shows up in the mochitest logs if we spin here.
|
||||||
|
dump("ifLink has wrong initial color. Spinning...\n");
|
||||||
|
setTimeout(function() { gGen.next(); }, 10);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate iframe2 to dir/${rand}
|
||||||
|
iframe2.onload = onChildLoad;
|
||||||
|
enableChildLoadCallback();
|
||||||
|
iframe2Cw.location = "mytestdir/" + rand;
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// PushState the iframe into the mytestdir directory. This should cause
|
||||||
|
// ifLink to turn purple, since we just visited mytestdir/${rand} in iframe2.
|
||||||
|
iframeCw.history.pushState(null, "foo", "mytestdir/foo");
|
||||||
|
|
||||||
|
// Check that the link's color is now visitedColor
|
||||||
|
while (getColor(ifLink) != visitedColor) {
|
||||||
|
dump("ifLink has wrong color after pushstate. Spinning...\n");
|
||||||
|
setTimeout(function() { gGen.next(); }, 10);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(ifLink.href.match("mytestdir\\/" + rand + "$"),
|
||||||
|
"inner frame's link should end with 'mytestdir/${rand}'");
|
||||||
|
|
||||||
|
// Navigate out of the mytestdir directory. This should cause ifLink to turn
|
||||||
|
// blue again.
|
||||||
|
iframeCw.history.pushState(null, "bar", "../file_bug500328_1.html");
|
||||||
|
|
||||||
|
// Check that the link's color is back to the unvisited color.
|
||||||
|
while (getColor(ifLink) != unvisitedColor) {
|
||||||
|
dump("ifLink has wrong color after pushstating out of dir. Spinning...\n");
|
||||||
|
setTimeout(function() { gGen.next(); }, 10);
|
||||||
|
yield;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(!ifLink.href.match("mytestdir"),
|
||||||
|
"inner frame's link shouldn't contain 'mytestdir'.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TEST 2 tests that pushstate's same-origin checks are correct.
|
||||||
|
*/
|
||||||
|
var filename = 'file_bug500328_2.html';
|
||||||
|
// Get the directory we're currently in
|
||||||
|
var dirname = document.location.pathname.replace(/[^\/]*$/, '');
|
||||||
|
statusMsg("Dirname is: " + dirname);
|
||||||
|
var loc = 'http://example.com' + dirname + filename;
|
||||||
|
statusMsg("About to transfer iframe to " + loc);
|
||||||
|
iframeCw.location = loc;
|
||||||
|
// We have to register a listener like this because this file is hosted on a
|
||||||
|
// different domain and can't notify us on load.
|
||||||
|
iframe.onload = onChildLoad;
|
||||||
|
enableChildLoadCallback();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// This function tries to pushstate and replacestate to the given URL and
|
||||||
|
// fails the test if the calls succeed.
|
||||||
|
var tryBadPushAndReplaceState = function(url) {
|
||||||
|
// XXX ex should be a SECURITY_ERR, not a plain Error.
|
||||||
|
|
||||||
|
var hist = iframeCw.history;
|
||||||
|
var url2 = url + dirname + filename;
|
||||||
|
|
||||||
|
expectException(function() { hist.pushState({}, "foo", url); },
|
||||||
|
'pushState to ' + url);
|
||||||
|
|
||||||
|
expectException(function() { hist.pushState({}, "foo", url2); },
|
||||||
|
'pushState to ' + url2);
|
||||||
|
|
||||||
|
expectException(function() { hist.replaceState({}, "foo", url); },
|
||||||
|
'replaceState to ' + url);
|
||||||
|
|
||||||
|
expectException(function() { hist.replaceState({}, "foo", url2); },
|
||||||
|
'replaceState to ' + url2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're currently at http://example.com/[dirname]/[filename]
|
||||||
|
tryBadPushAndReplaceState("https://example.com");
|
||||||
|
tryBadPushAndReplaceState("http://foo.example.com");
|
||||||
|
tryBadPushAndReplaceState("http://example.com:1234");
|
||||||
|
tryBadPushAndReplaceState("http://example.com.a");
|
||||||
|
tryBadPushAndReplaceState("http://example.con");
|
||||||
|
tryBadPushAndReplaceState("http://eexample.com");
|
||||||
|
tryBadPushAndReplaceState("http://me@example.com");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TEST 3 tests that the session history entries' titles are properly sync'ed
|
||||||
|
* after push/pop states.
|
||||||
|
*
|
||||||
|
* We have to run this test in a popup rather than an iframe because only the
|
||||||
|
* root docshell has a session history object.
|
||||||
|
*/
|
||||||
|
statusMsg("About to open popup.");
|
||||||
|
var popup = window.open("file_bug500328_1.html", "popup0",
|
||||||
|
"height=200,width=200,location=yes," +
|
||||||
|
"menubar=yes,status=yes,toolbar=yes,dependent=yes");
|
||||||
|
|
||||||
|
var shistory = getSHistory(popup);
|
||||||
|
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
yield;
|
||||||
|
popstateExpected("Didn't get popstate after opening window.");
|
||||||
|
|
||||||
|
popup.history.pushState(null, "title 0");
|
||||||
|
ok(!getChromeWin(popup).document
|
||||||
|
.getElementById("Browser:Back").hasAttribute("disabled"),
|
||||||
|
"Back button was not enabled after initial pushstate.");
|
||||||
|
|
||||||
|
popup.document.title = "title 1";
|
||||||
|
|
||||||
|
// Yield to the event loop so listeners will be notified of the title change
|
||||||
|
// and so that the hash change we trigger below generates a new session
|
||||||
|
// history entry.
|
||||||
|
shortWait();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// Check that the current session history entry's title has been updated to
|
||||||
|
// reflect the new document title.
|
||||||
|
is(getSHTitle(shistory), "title 1", "SHEntry title test 1");
|
||||||
|
|
||||||
|
// Change the page's hash to #1, which will trigger a popstate event.
|
||||||
|
// We don't have to wait, because this happens synchronously.
|
||||||
|
popup.location.hash = "#1";
|
||||||
|
popstateExpected("Didn't get popstate after changing hash.");
|
||||||
|
|
||||||
|
popup.document.title = "title 2";
|
||||||
|
|
||||||
|
// Yield so listeners will be notified of the title change we just performed.
|
||||||
|
shortWait();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
is(getSHTitle(shistory), "title 2", "SHEntry title test 2");
|
||||||
|
|
||||||
|
// Go back. Happens synchronously. We should get a popstate.
|
||||||
|
statusMsg("About to go back.");
|
||||||
|
popup.history.go(-1);
|
||||||
|
popstateExpected("Didn't get a popstate after going back.");
|
||||||
|
|
||||||
|
// Even though we went back, we expect the SHEntry title to remain the same
|
||||||
|
// because the document didn't change.
|
||||||
|
is(getSHTitle(shistory), "title 2", "SHEntry title test 3");
|
||||||
|
|
||||||
|
popup.document.title = "Changed 1";
|
||||||
|
shortWait();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// This check is really a test of bug 509055.
|
||||||
|
is(getSHTitle(shistory), "Changed 1", "SHEntry title test 4");
|
||||||
|
|
||||||
|
popup.close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TEST 4 tests replaceState and that we don't get double popstates on
|
||||||
|
* window.open. It also stress-tests the system and its interaction with
|
||||||
|
* bfcache by making many push/replace state calls.
|
||||||
|
*/
|
||||||
|
popup = window.open("file_bug500328_1.html", "popup1",
|
||||||
|
"height=200,width=200,location=yes," +
|
||||||
|
"menubar=yes,status=yes,toolbar=yes,dependent=yes");
|
||||||
|
|
||||||
|
// The initial about:blank load into the new window shouldn't result in us
|
||||||
|
// seeing a popstate. Once file_bug500328_1.html is loaded, it'll overwrite
|
||||||
|
// popup.onpopstate, and this assertion won't fire for that popstate and
|
||||||
|
// others after.
|
||||||
|
//
|
||||||
|
// If we fired the popstate event asynchronously, we'd expect this assert to
|
||||||
|
// fire.
|
||||||
|
popup.onpopstate = function() {
|
||||||
|
ok(false, "Initial load of popup shouldn't give us a popstate.");
|
||||||
|
};
|
||||||
|
|
||||||
|
shistory = getSHistory(popup);
|
||||||
|
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
yield;
|
||||||
|
statusMsg("Awake after loading content into popup.");
|
||||||
|
|
||||||
|
popup.history.replaceState({n:1, ok:true}, "state 1", "good1.html");
|
||||||
|
locationEndsWith(popup, "good1.html");
|
||||||
|
is(getSHTitle(shistory), "state 1", "SHEntry title 'state 1'");
|
||||||
|
|
||||||
|
// Flush the event loop so our next load creates a new session history entry.
|
||||||
|
shortWait();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
popup.location = "file_bug500328_1.html";
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// Flush the event loop so nsDocShell::OnNewURI runs and our load is recorded
|
||||||
|
// properly. OnNewURI is called after PopState fires, because OnNewURI
|
||||||
|
// results from an async event, while PopState is sync. We'd have to do the
|
||||||
|
// same thing if we were listening to onload here, so this isn't
|
||||||
|
// unreasonable.
|
||||||
|
shortWait();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// Now go back and make sure everything is as it should be.
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
popup.history.back();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// Flush the event loop so the document's location is updated.
|
||||||
|
shortWait();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// We had some popstates above without corresponding popstateExpected()
|
||||||
|
// calls, so we need to clear the counter.
|
||||||
|
clearPopStateCounter();
|
||||||
|
|
||||||
|
locationEndsWith(popup, "good1.html");
|
||||||
|
is(JSON.stringify(gLastPopStateEvent.state), '{"n":1,"ok":true}',
|
||||||
|
"Wrong state popped after going back to initial state.");
|
||||||
|
|
||||||
|
// We're back at state 0, which was replaceState-ed to state1.html. Let's do
|
||||||
|
// some push/pop/replaces to make sure everything works OK when we involve
|
||||||
|
// large numbers of SHEntries.
|
||||||
|
for(var i = 2; i <= 30; i++) {
|
||||||
|
if (i % 3 == 0) {
|
||||||
|
popup.history.pushState({n:i, ok:true}, "state " + i, "good" + i + ".html");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
popup.history.pushState({n:i}, "state " + i, "state" + i + ".html");
|
||||||
|
for(var j = 0; j < i % 4; j++) {
|
||||||
|
popup.history.replaceState({n:i, nn:j}, "state " + i + ", " + j);
|
||||||
|
}
|
||||||
|
popup.history.replaceState({n:i, ok:true}, "state " + i, "good" + i + ".html");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var i = 29; i >= 1; i--) {
|
||||||
|
popup.history.back();
|
||||||
|
popstateExpected("Didn't get a popstate on iteration " + i);
|
||||||
|
locationEndsWith(popup, "good" + i + ".html");
|
||||||
|
is(gLastPopStateEvent.state.n, i, "Bad counter on last popstate event.");
|
||||||
|
ok(gLastPopStateEvent.state.ok,
|
||||||
|
"Last popstate event should have 'ok' set to true.");
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TEST 5 tests misc security features and implementation details of
|
||||||
|
* Push/ReplaceState
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test that we can't push/replace an object with a large (over 640k
|
||||||
|
* characters) JSON representation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// (In case you're curious, this loop generates an object which serializes to
|
||||||
|
// 694581 characters.)
|
||||||
|
var bigObject = new Object();
|
||||||
|
for(var i = 0; i < 51200; i++) {
|
||||||
|
bigObject[i] = i;
|
||||||
|
}
|
||||||
|
// statusMsg("Big object has size " + JSON.stringify(bigObject).length);
|
||||||
|
|
||||||
|
// We shouldn't be able to pushstate this large object, due to space
|
||||||
|
// constraints.
|
||||||
|
expectException(
|
||||||
|
function() { iframeCw.history.pushState(bigObject, "foo"); },
|
||||||
|
"pushState-ing large object");
|
||||||
|
|
||||||
|
expectException(
|
||||||
|
function() { iframeCw.history.replaceState(bigObject, "foo"); },
|
||||||
|
"replaceState-ing large object");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure we can't push/replace state on an iframe of a different origin.
|
||||||
|
* This will work if this function has requested Universal XPConnect
|
||||||
|
* privileges, so any code which needs those privileges can't be in this
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
enableChildLoadCallback();
|
||||||
|
iframeCw.location = "http://example.com";
|
||||||
|
iframe.onload = onChildLoad;
|
||||||
|
yield;
|
||||||
|
iframe.onload = null;
|
||||||
|
|
||||||
|
expectException(
|
||||||
|
function() { iframeCw.history.pushState({}, "foo"); },
|
||||||
|
"pushState-ing in a different origin");
|
||||||
|
|
||||||
|
expectException(
|
||||||
|
function() { iframeCw.history.replaceState({}, "foo"); },
|
||||||
|
"replaceState-ing in a different origin");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we do the following:
|
||||||
|
* * Start at page A.
|
||||||
|
* * PushState to page B.
|
||||||
|
* * Refresh. The server responds with a 404
|
||||||
|
* * Go back.
|
||||||
|
* Then at the end, page A should be displayed, not the 404 page.
|
||||||
|
*/
|
||||||
|
enableChildLoadCallback();
|
||||||
|
iframe.onload = onChildLoad;
|
||||||
|
iframeCw.location = "about:blank";
|
||||||
|
yield;
|
||||||
|
iframe.onload = null;
|
||||||
|
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
// navigate to http://localhost:8888/[...]/file_bug500328_1.html
|
||||||
|
iframeCw.location = innerLoc;
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// Let the PopState handler finish. If we call refresh (below) from within
|
||||||
|
// the handler, we get slightly confused and can't tell that we're at a 404
|
||||||
|
// after the refresh.
|
||||||
|
shortWait();
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// PushState to a URL which doesn't exist
|
||||||
|
iframeCw.history.pushState({}, "", rand);
|
||||||
|
|
||||||
|
// Refresh. We'll end up a 404 page.
|
||||||
|
iframe.onload = onChildLoad;
|
||||||
|
enableChildLoadCallback();
|
||||||
|
iframeCw.location.reload(true);
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// Since the last page was a 404, going back should actually show the
|
||||||
|
// contents of the old page, instead of persisting the contents of the 404
|
||||||
|
// page.
|
||||||
|
clearPopStateCounter();
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
iframeCw.history.back();
|
||||||
|
yield;
|
||||||
|
popstateExpected("Didn't get popstate after going back.");
|
||||||
|
|
||||||
|
// Make sure that we're actually showing the contents of
|
||||||
|
// file_bug500328_1.html, as opposed to the 404 page.
|
||||||
|
var identifierElem = iframeCw.document.getElementById("link-anchor1");
|
||||||
|
ok(identifierElem != undefined && identifierElem != null,
|
||||||
|
"iframe didn't contain file_bug500328_1.html's contents.");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TEST 6 tests that the referrer is set properly after push/replace states.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First, a simple test:
|
||||||
|
* * Load file_bug500328_1.html into iframe
|
||||||
|
* * PushState to newpage1.html#foo
|
||||||
|
* * Instruct the iframe to load file_bug500328_1.html into itself.
|
||||||
|
* The referer should be newpage1.html, without the hash.
|
||||||
|
*
|
||||||
|
* This also tests that we can call pushState from within the onload handler.
|
||||||
|
*/
|
||||||
|
enableChildLoadCallback();
|
||||||
|
iframeCw.location = "file_bug500328_1.html";
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// Run within the onload handler. This should work without issue.
|
||||||
|
iframeCw.history.pushState(null, "", "newpage1.html");
|
||||||
|
|
||||||
|
// iframeCw.navigateTo() causes the iframe to set its location on our
|
||||||
|
// behalf. We can't just set its location ourselves, because then *we*
|
||||||
|
// become the referrer.
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
iframeCw.navigateTo("file_bug500328_1.html");
|
||||||
|
yield;
|
||||||
|
|
||||||
|
ok(iframeCw.document.referrer.toString().match(/newpage1.html$/),
|
||||||
|
"Wrong referrer after replaceState. Expected newpage1.html, but was " +
|
||||||
|
iframeCw.document.referrer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We're back at file_bug500328_1.html. Now do the following:
|
||||||
|
* * replaceState to newpage2.html#foo
|
||||||
|
* * Click a link back to file_bug500328_1.html
|
||||||
|
* The referrer should be newpage2.html, without the hash.
|
||||||
|
*/
|
||||||
|
iframeCw.history.replaceState(null, null, "newpage2.html#foo");
|
||||||
|
enableChildPopStateCallback();
|
||||||
|
sendMouseEvent({type:'click'}, 'link-self', iframeCw);
|
||||||
|
yield;
|
||||||
|
|
||||||
|
ok(iframeCw.document.referrer.toString().match(/newpage2.html$/),
|
||||||
|
"Wrong referrer after replaceState. Expected newpage2.html, but was " +
|
||||||
|
iframeCw.document.referrer);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up a cycle with the popstate event to make sure it's properly
|
||||||
|
* collected.
|
||||||
|
*/
|
||||||
|
var evt = document.createEvent("popstateevent");
|
||||||
|
evt.initEvent("foo", false, false, evt);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
SimpleTest.finish();
|
||||||
|
statusMsg("********** Finished tests ***********");
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
yield;
|
||||||
|
|
||||||
|
// I don't think this will actually make the mochitest fail, but there's
|
||||||
|
// not much we can do about this. Realistically, though, regressions are
|
||||||
|
// not likely to fire extra events -- this trap is here mostly to catch
|
||||||
|
// errors made while wriring tests.
|
||||||
|
ok(false, "Got extra event!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
statusMsg("XXXXXXXXXXXXXX");
|
||||||
|
while(true) {
|
||||||
|
yield;
|
||||||
|
statusMsg("Woken up.");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Important: Wait to start the tests until the page has loaded. Otherwise,
|
||||||
|
// the test will occasionally fail when it begins running before the iframes
|
||||||
|
// have finished their initial load of about:blank.
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
gGen = runTest();
|
||||||
|
gGen.next();
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -135,9 +135,6 @@ nsresult nsDateTimeFormatMac::FormatTMTime(nsILocale* locale,
|
||||||
return NS_OK;
|
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_mon >= 0, "tm is not set correctly");
|
||||||
NS_ASSERTION(tmTime->tm_mday >= 1, "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");
|
NS_ASSERTION(tmTime->tm_hour >= 0, "tm is not set correctly");
|
||||||
|
|
|
@ -57,7 +57,6 @@
|
||||||
|
|
||||||
native COMVARIANT(VARIANT);
|
native COMVARIANT(VARIANT);
|
||||||
[ptr] native COMVARIANTPtr(VARIANT);
|
[ptr] native COMVARIANTPtr(VARIANT);
|
||||||
native JSVal(jsval);
|
|
||||||
[ptr] native JSContextPtr(JSContext);
|
[ptr] native JSContextPtr(JSContext);
|
||||||
|
|
||||||
interface IDispatch;
|
interface IDispatch;
|
||||||
|
|
|
@ -59,11 +59,12 @@
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
|
// NB: JSVal is declared in nsIVariant.idl
|
||||||
|
|
||||||
[ptr] native JSContextPtr(JSContext);
|
[ptr] native JSContextPtr(JSContext);
|
||||||
[ptr] native JSClassPtr(JSClass);
|
[ptr] native JSClassPtr(JSClass);
|
||||||
[ptr] native JSObjectPtr(JSObject);
|
[ptr] native JSObjectPtr(JSObject);
|
||||||
[ptr] native JSValPtr(jsval);
|
[ptr] native JSValPtr(jsval);
|
||||||
native JSVal(jsval);
|
|
||||||
native JSEqualityOp(JSEqualityOp);
|
native JSEqualityOp(JSEqualityOp);
|
||||||
native JSID(jsid);
|
native JSID(jsid);
|
||||||
[ptr] native voidPtrPtr(void*);
|
[ptr] native voidPtrPtr(void*);
|
||||||
|
@ -530,6 +531,12 @@ interface nsIXPConnect : nsISupports
|
||||||
in nsIIDRef aIID,
|
in nsIIDRef aIID,
|
||||||
[iid_is(aIID),retval] out nsQIResult result);
|
[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.
|
* This only succeeds if the JSObject is a nsIXPConnectWrappedNative.
|
||||||
* A new wrapper is *never* constructed.
|
* A new wrapper is *never* constructed.
|
||||||
|
|
|
@ -1358,14 +1358,6 @@ FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext,
|
||||||
return NS_OK;
|
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); */
|
/* [noscript] void checkLoadURIFromScript (in JSContextPtr cx, in nsIURI uri); */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx, nsIURI *uri)
|
FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx, nsIURI *uri)
|
||||||
|
|
|
@ -1051,7 +1051,7 @@ InitWebGLTypes(JSContext *aJSContext, JSObject *aGlobalJSObj)
|
||||||
// Alias WebGLArrayBuffer -> ArrayBuffer
|
// Alias WebGLArrayBuffer -> ArrayBuffer
|
||||||
if(!JS_GetProperty(aJSContext, aGlobalJSObj, "ArrayBuffer", &v) ||
|
if(!JS_GetProperty(aJSContext, aGlobalJSObj, "ArrayBuffer", &v) ||
|
||||||
!JS_DefineProperty(aJSContext, aGlobalJSObj, "WebGLArrayBuffer", v,
|
!JS_DefineProperty(aJSContext, aGlobalJSObj, "WebGLArrayBuffer", v,
|
||||||
NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE))
|
NULL, NULL, JSPROP_PERMANENT))
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
|
|
||||||
const int webglTypes[] = {
|
const int webglTypes[] = {
|
||||||
|
@ -1080,7 +1080,7 @@ InitWebGLTypes(JSContext *aJSContext, JSObject *aGlobalJSObj)
|
||||||
{
|
{
|
||||||
if(!JS_GetProperty(aJSContext, aGlobalJSObj, js::TypedArray::slowClasses[webglTypes[i]].name, &v) ||
|
if(!JS_GetProperty(aJSContext, aGlobalJSObj, js::TypedArray::slowClasses[webglTypes[i]].name, &v) ||
|
||||||
!JS_DefineProperty(aJSContext, aGlobalJSObj, webglNames[i], v,
|
!JS_DefineProperty(aJSContext, aGlobalJSObj, webglNames[i], v,
|
||||||
NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE))
|
NULL, NULL, JSPROP_PERMANENT))
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1370,6 +1370,25 @@ nsXPConnect::WrapJS(JSContext * aJSContext,
|
||||||
return NS_OK;
|
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); */
|
/* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter,
|
nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter,
|
||||||
|
|
|
@ -4198,6 +4198,10 @@ public:
|
||||||
|
|
||||||
static XPCVariant* newVariant(XPCCallContext& ccx, jsval aJSVal);
|
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;}
|
jsval GetJSVal() const {return mJSVal;}
|
||||||
|
|
||||||
XPCVariant(XPCCallContext& ccx, jsval aJSVal);
|
XPCVariant(XPCCallContext& ccx, jsval aJSVal);
|
||||||
|
|
|
@ -390,6 +390,14 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx)
|
||||||
NS_SUCCEEDED(nsVariant::SetFromInterface(&mData, iid, wrapper));
|
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
|
// static
|
||||||
JSBool
|
JSBool
|
||||||
XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
|
XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
|
||||||
|
@ -402,30 +410,29 @@ XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
|
||||||
if (NS_FAILED(variant->GetDataType(&type)))
|
if (NS_FAILED(variant->GetDataType(&type)))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
|
jsval realVal;
|
||||||
if(xpcvariant)
|
nsresult rv = variant->GetAsJSVal(&realVal);
|
||||||
{
|
|
||||||
jsval realVal = xpcvariant->GetJSVal();
|
if(NS_SUCCEEDED(rv) &&
|
||||||
if(JSVAL_IS_PRIMITIVE(realVal) ||
|
(JSVAL_IS_PRIMITIVE(realVal) ||
|
||||||
type == nsIDataType::VTYPE_ARRAY ||
|
type == nsIDataType::VTYPE_ARRAY ||
|
||||||
type == nsIDataType::VTYPE_EMPTY_ARRAY ||
|
type == nsIDataType::VTYPE_EMPTY_ARRAY ||
|
||||||
type == nsIDataType::VTYPE_ID)
|
type == nsIDataType::VTYPE_ID))
|
||||||
{
|
{
|
||||||
// Not a JSObject (or is a JSArray or is a JSObject representing
|
// It's not a JSObject (or it's a JSArray or a JSObject representing an
|
||||||
// an nsID),.
|
// nsID). Just pass through the underlying data.
|
||||||
// So, just pass through the underlying data.
|
|
||||||
*pJSVal = realVal;
|
*pJSVal = realVal;
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(xpcvariant->mReturnRawObject)
|
nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
|
||||||
|
if(xpcvariant && xpcvariant->mReturnRawObject)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
|
NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
|
||||||
type == nsIDataType::VTYPE_INTERFACE_IS,
|
type == nsIDataType::VTYPE_INTERFACE_IS,
|
||||||
"Weird variant");
|
"Weird variant");
|
||||||
*pJSVal = realVal;
|
*pJSVal = realVal;
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
|
||||||
|
|
||||||
// else, it's an object and we really need to double wrap it if we've
|
// 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.
|
// already decided that its 'natural' type is as some sort of interface.
|
||||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче