Merge mozilla-central into electrolysis.

This commit is contained in:
Benjamin Smedberg 2010-02-03 13:28:22 -05:00
Родитель 9f9e76e90a df14ccf559
Коммит 8411a08769
158 изменённых файлов: 3311 добавлений и 1071 удалений

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

@ -44,7 +44,7 @@ interface nsIFrame;
interface nsObjectFrame;
interface nsIContent;
[uuid(e0498def-1552-4763-8c47-6c6cc36c7aa0)]
[uuid(84a3ab70-8f7e-4610-9cd8-bd69308b76c5)]
interface nsIAccessibilityService : nsIAccessibleRetrieval
{
nsIAccessible createOuterDocAccessible(in nsIDOMNode aNode);
@ -74,19 +74,6 @@ interface nsIAccessibilityService : nsIAccessibleRetrieval
nsIAccessible createHTMLTextFieldAccessible(in nsIFrame aFrame);
nsIAccessible createHTMLCaptionAccessible(in nsIFrame aFrame);
/**
* Return an accessible for the given DOM node.
*
* @param aNode [in] the given node
* @param aPresShell [in] the pres shell of the node
* @param aWeakShell [in] the weak shell for the pres shell
* @param aFrameHint [in] the frame of the given node
* @param aIsHidden [out] indicates whether the node's frame is hidden
*/
nsIAccessible getAccessible(in nsIDOMNode aNode, in nsIPresShell aPresShell,
in nsIWeakReference aWeakShell,
in nsIFrame aFrameHint, out boolean aIsHidden);
// For gtk+ native window accessible
nsIAccessible addNativeRootAccessible(in voidPtr aAtkAccessible);
void removeNativeRootAccessible(in nsIAccessible aRootAccessible);

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

@ -56,7 +56,7 @@ interface nsIDOMDOMStringList;
*
* @status UNDER_REVIEW
*/
[scriptable, uuid(244e4c67-a1d3-44f2-9cab-cdaa31b68046)]
[scriptable, uuid(7eb49afb-6298-4ce6-816f-9615936540f4)]
interface nsIAccessibleRetrieval : nsISupports
{
/**
@ -92,26 +92,6 @@ interface nsIAccessibleRetrieval : nsISupports
*/
nsIDOMNode getRelevantContentNodeFor(in nsIDOMNode aNode);
/**
* Return an nsIAccessible for a DOM node in pres shell for this DOM window.
* Create a new accessible of the appropriate type if necessary,
* or use one from the accessibility cache if it already exists.
* @param aNode The DOM node to get an accessible for.
* @param aDOMWin The DOM window containing the node.
* @return The nsIAccessible for the given DOM node.
*/
nsIAccessible getAccessibleInWindow(in nsIDOMNode aNode, in nsIDOMWindow aDOMWin);
/**
* Return an nsIAccessible for a DOM node in the given weak shell.
* Create a new accessible of the appropriate type if necessary,
* or use one from the accessibility cache if it already exists.
* @param aNode The DOM node to get an accessible for.
* @param aPresShell The presentation shell which contains layout info for the DOM node.
* @return The nsIAccessible for the given DOM node.
*/
nsIAccessible getAccessibleInWeakShell(in nsIDOMNode aNode, in nsIWeakReference aPresShell);
/**
* Return an nsIAccessible for a DOM node in the given pres shell.
* Create a new accessible of the appropriate type if necessary,

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

@ -295,8 +295,7 @@ nsAccReorderEvent::HasAccessibleInReasonSubtree()
return PR_FALSE;
nsCOMPtr<nsIAccessible> accessible;
nsAccessNode::GetAccService()->GetAccessibleFor(mReasonNode,
getter_AddRefs(accessible));
GetAccService()->GetAccessibleFor(mReasonNode, getter_AddRefs(accessible));
return accessible || nsAccUtils::HasAccessibleChildren(mReasonNode);
}

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

@ -172,8 +172,7 @@ nsAccUtils::GetPositionAndSizeForXULSelectControlItem(nsIDOMNode *aNode,
nsCOMPtr<nsIDOMNode> currNode(do_QueryInterface(currItem));
nsCOMPtr<nsIAccessible> itemAcc;
nsAccessNode::GetAccService()->GetAccessibleFor(currNode,
getter_AddRefs(itemAcc));
GetAccService()->GetAccessibleFor(currNode, getter_AddRefs(itemAcc));
if (!itemAcc ||
State(itemAcc) & nsIAccessibleStates::STATE_INVISIBLE) {
(*aSetSize)--;
@ -214,8 +213,7 @@ nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIDOMNode *aNode,
container->GetItemAtIndex(index, getter_AddRefs(item));
nsCOMPtr<nsIAccessible> itemAcc;
nsAccessNode::GetAccService()->GetAccessibleFor(item,
getter_AddRefs(itemAcc));
GetAccService()->GetAccessibleFor(item, getter_AddRefs(itemAcc));
if (itemAcc) {
PRUint32 itemRole = Role(itemAcc);
@ -236,8 +234,7 @@ nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIDOMNode *aNode,
container->GetItemAtIndex(index, getter_AddRefs(item));
nsCOMPtr<nsIAccessible> itemAcc;
nsAccessNode::GetAccService()->GetAccessibleFor(item,
getter_AddRefs(itemAcc));
GetAccService()->GetAccessibleFor(item, getter_AddRefs(itemAcc));
if (itemAcc) {
PRUint32 itemRole = Role(itemAcc);
@ -524,8 +521,7 @@ already_AddRefed<nsIAccessible>
nsAccUtils::GetMultiSelectableContainer(nsIDOMNode *aNode)
{
nsCOMPtr<nsIAccessible> accessible;
nsAccessNode::GetAccService()->GetAccessibleFor(aNode,
getter_AddRefs(accessible));
GetAccService()->GetAccessibleFor(aNode, getter_AddRefs(accessible));
nsCOMPtr<nsIAccessible> container =
GetSelectableContainer(accessible, State(accessible));
@ -573,25 +569,20 @@ nsAccUtils::GetTextAccessibleFromSelection(nsISelection *aSelection,
nsCOMPtr<nsIDOMNode> resultNode =
nsCoreUtils::GetDOMNodeFromDOMPoint(focusNode, focusOffset);
nsIAccessibilityService *accService = nsAccessNode::GetAccService();
// Get text accessible containing the result node.
while (resultNode) {
// Make sure to get the correct starting node for selection events inside
// XBL content trees.
nsCOMPtr<nsIDOMNode> relevantNode;
nsresult rv = accService->
GetRelevantContentNodeFor(resultNode, getter_AddRefs(relevantNode));
if (NS_FAILED(rv))
return nsnull;
GetAccService()->GetRelevantContentNodeFor(resultNode,
getter_AddRefs(relevantNode));
if (relevantNode)
resultNode.swap(relevantNode);
nsCOMPtr<nsIContent> content = do_QueryInterface(resultNode);
if (!content || !content->IsNodeOfType(nsINode::eTEXT)) {
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleFor(resultNode, getter_AddRefs(accessible));
GetAccService()->GetAccessibleFor(resultNode, getter_AddRefs(accessible));
if (accessible) {
nsIAccessibleText *textAcc = nsnull;
CallQueryInterface(accessible, &textAcc);
@ -956,8 +947,7 @@ PRBool
nsAccUtils::IsNodeRelevant(nsIDOMNode *aNode)
{
nsCOMPtr<nsIDOMNode> relevantNode;
nsAccessNode::GetAccService()->GetRelevantContentNodeFor(aNode,
getter_AddRefs(relevantNode));
GetAccService()->GetRelevantContentNodeFor(aNode, getter_AddRefs(relevantNode));
return aNode == relevantNode;
}

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

@ -82,12 +82,6 @@ nsAccessNodeHashtable nsAccessNode::gGlobalDocAccessibleCache;
nsApplicationAccessibleWrap *nsAccessNode::gApplicationAccessible = nsnull;
nsIAccessibilityService*
nsAccessNode::GetAccService()
{
return nsAccessibilityService::GetAccessibilityService();
}
/*
* Class nsAccessNode
*/
@ -157,15 +151,12 @@ nsAccessNode::Init()
if (presShell) {
nsCOMPtr<nsIDOMNode> docNode(do_QueryInterface(presShell->GetDocument()));
if (docNode) {
nsIAccessibilityService *accService = GetAccService();
if (accService) {
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleInShell(docNode, presShell,
GetAccService()->GetAccessibleInShell(docNode, presShell,
getter_AddRefs(accessible));
docAccessible = do_QueryInterface(accessible);
}
}
}
NS_ASSERTION(docAccessible, "Cannot cache new nsAccessNode");
if (!docAccessible) {
return NS_ERROR_FAILURE;
@ -473,15 +464,13 @@ nsAccessNode::MakeAccessNode(nsIDOMNode *aNode, nsIAccessNode **aAccessNode)
{
*aAccessNode = nsnull;
nsIAccessibilityService *accService = GetAccService();
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
nsCOMPtr<nsIAccessNode> accessNode;
accService->GetCachedAccessNode(aNode, mWeakShell, getter_AddRefs(accessNode));
GetAccService()->GetCachedAccessNode(aNode, mWeakShell,
getter_AddRefs(accessNode));
if (!accessNode) {
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleInWeakShell(aNode, mWeakShell,
GetAccService()->GetAccessibleInWeakShell(aNode, mWeakShell,
getter_AddRefs(accessible));
accessNode = do_QueryInterface(accessible);

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

@ -56,7 +56,7 @@
#include "nsIStringBundle.h"
#include "nsWeakReference.h"
#include "nsInterfaceHashtable.h"
#include "nsIAccessibilityService.h"
#include "nsAccessibilityService.h"
class nsIPresShell;
class nsPresContext;
@ -145,7 +145,7 @@ class nsAccessNode: public nsIAccessNode
already_AddRefed<nsRootAccessible> GetRootAccessible();
static nsIDOMNode *gLastFocusedNode;
static nsIAccessibilityService* GetAccService();
already_AddRefed<nsIDOMNode> GetCurrentFocus();
/**

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

@ -1173,26 +1173,6 @@ nsAccessibilityService::GetAttachedAccessibleFor(nsIDOMNode *aNode,
return GetAccessibleFor(aNode, aAccessible);
}
NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWindow(nsIDOMNode *aNode,
nsIDOMWindow *aWin,
nsIAccessible **aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
NS_ENSURE_ARG(aNode);
NS_ENSURE_ARG(aWin);
nsCOMPtr<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,
nsIPresShell *aPresShell,
nsIAccessible **aAccessible)
@ -1209,7 +1189,8 @@ NS_IMETHODIMP nsAccessibilityService::GetAccessibleInShell(nsIDOMNode *aNode,
nsnull, &isHiddenUnused, aAccessible);
}
NS_IMETHODIMP nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode,
nsresult
nsAccessibilityService::GetAccessibleInWeakShell(nsIDOMNode *aNode,
nsIWeakReference *aWeakShell,
nsIAccessible **aAccessible)
{
@ -1272,7 +1253,8 @@ static PRBool HasRelatedContent(nsIContent *aContent)
return PR_FALSE;
}
NS_IMETHODIMP nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
nsresult
nsAccessibilityService::GetAccessible(nsIDOMNode *aNode,
nsIPresShell *aPresShell,
nsIWeakReference *aWeakShell,
nsIFrame *aFrameHint,
@ -2054,37 +2036,26 @@ nsAccessibilityService::InvalidateSubtreeFor(nsIPresShell *aShell,
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
/**
* Return accessibility service; creating one if necessary.
*/
nsresult
nsAccessibilityService::GetAccessibilityService(nsIAccessibilityService** aResult)
NS_GetAccessibilityService(nsIAccessibilityService** aResult)
{
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
*aResult = nsnull;
if (!gAccessibilityService) {
gAccessibilityService = new nsAccessibilityService();
NS_ENSURE_TRUE(gAccessibilityService, NS_ERROR_OUT_OF_MEMORY);
if (!nsAccessibilityService::gAccessibilityService) {
nsAccessibilityService::gAccessibilityService = new nsAccessibilityService();
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;
}
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
nsAccessibilityService::GetAccessibleForDeckChildren(nsIDOMNode *aNode, nsIAccessible** aAccessible)
{

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

@ -81,21 +81,35 @@ public:
static nsresult GetShellFromNode(nsIDOMNode *aNode,
nsIWeakReference **weakShell);
/**
* Return accessibility service (static instance of this class).
*/
static nsresult GetAccessibilityService(nsIAccessibilityService** aResult);
/**
* Return cached accessibility service.
*/
static nsIAccessibilityService* GetAccessibilityService();
/**
* Indicates whether accessibility service was shutdown.
*/
static PRBool gIsShutdown;
/**
* Return an accessible for the given DOM node.
*
* @param aNode [in] the given node
* @param aPresShell [in] the pres shell of the node
* @param aWeakShell [in] the weak shell for the pres shell
* @param aFrameHint [in] the frame of the given node
* @param aIsHidden [out] indicates whether the node's frame is hidden
*/
nsresult GetAccessible(nsIDOMNode *aNode, nsIPresShell *aPresShell,
nsIWeakReference *aWeakShell, nsIFrame *aFrameHint,
PRBool *aIsHidden, nsIAccessible **aAccessible);
/**
* Return an accessible for a DOM node in the given pres shell.
*
* @param aNode [in] the given node.
* @param aPresShell [in] the presentation shell of the given node.
* @param aAccessible [out] the nsIAccessible for the given node.
*/
nsresult GetAccessibleInWeakShell(nsIDOMNode *aNode,
nsIWeakReference *aPresShell,
nsIAccessible **aAccessible);
private:
/**
* Return presentation shell, DOM node for the given frame.
@ -170,10 +184,24 @@ private:
*/
void ProcessDocLoadEvent(nsIWebProgress *aWebProgress, PRUint32 aEventType);
friend nsAccessibilityService* GetAccService();
friend nsresult NS_GetAccessibilityService(nsIAccessibilityService** aResult);
NS_DECL_RUNNABLEMETHOD_ARG2(nsAccessibilityService, ProcessDocLoadEvent,
nsCOMPtr<nsIWebProgress>, PRUint32)
};
/**
* Return the accessibility service instance. (Handy global function)
*/
inline nsAccessibilityService*
GetAccService()
{
return nsAccessibilityService::gAccessibilityService;
}
/**
* Map nsIAccessibleRole constants to strings. Used by
* nsIAccessibleRetrieval::getStringRole() method.

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

@ -3096,13 +3096,13 @@ nsAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError)
already_AddRefed<nsIAccessible>
nsAccessible::GetFirstAvailableAccessible(nsIDOMNode *aStartNode)
{
nsIAccessibilityService *accService = GetAccService();
nsCOMPtr<nsIAccessible> accessible;
nsCOMPtr<nsIDOMTreeWalker> walker;
nsCOMPtr<nsIDOMNode> currentNode(aStartNode);
while (currentNode) {
accService->GetAccessibleInWeakShell(currentNode, mWeakShell, getter_AddRefs(accessible)); // AddRef'd
GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell,
getter_AddRefs(accessible));
if (accessible)
return accessible.forget();

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

@ -46,11 +46,11 @@
#include "nsIContent.h"
#include "nsIDOMXULElement.h"
#include "nsIPresShell.h"
#include "nsAccessibilityService.h"
#include "nsWeakReference.h"
nsAccessibleTreeWalker::nsAccessibleTreeWalker(nsIWeakReference* aPresShell, nsIDOMNode* aNode, PRBool aWalkAnonContent):
mWeakShell(aPresShell),
mAccService(do_GetService("@mozilla.org/accessibilityService;1")),
mWalkAnonContent(aWalkAnonContent)
{
mState.domNode = aNode;
@ -294,14 +294,10 @@ nsAccessibleTreeWalker::WalkFrames()
*/
PRBool nsAccessibleTreeWalker::GetAccessible()
{
if (!mAccService) {
return PR_FALSE;
}
mState.accessible = nsnull;
nsCOMPtr<nsIPresShell> presShell(do_QueryReferent(mWeakShell));
mAccService->GetAccessible(mState.domNode, presShell, mWeakShell,
GetAccService()->GetAccessible(mState.domNode, presShell, mWeakShell,
mState.frame.GetFrame(), &mState.isHidden,
getter_AddRefs(mState.accessible));

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

@ -48,7 +48,6 @@
#include "nsIAccessible.h"
#include "nsIDOMNode.h"
#include "nsIDOMNodeList.h"
#include "nsIAccessibilityService.h"
#include "nsIWeakReference.h"
#include "nsIFrame.h"
@ -132,7 +131,6 @@ protected:
void GetNextDOMNode();
nsCOMPtr<nsIWeakReference> mWeakShell;
nsCOMPtr<nsIAccessibilityService> mAccService;
PRBool mWalkAnonContent;
};

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

@ -2113,9 +2113,6 @@ nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
nsCOMPtr<nsIDOMNode> currentNode(aNode), parentNode;
nsCOMPtr<nsIAccessNode> accessNode;
nsIAccessibilityService *accService = GetAccService();
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
do {
currentNode->GetParentNode(getter_AddRefs(parentNode));
currentNode = parentNode;
@ -2126,11 +2123,12 @@ nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
}
nsCOMPtr<nsIDOMNode> relevantNode;
if (NS_SUCCEEDED(accService->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
if (NS_SUCCEEDED(GetAccService()->GetRelevantContentNodeFor(currentNode, getter_AddRefs(relevantNode))) && relevantNode) {
currentNode = relevantNode;
}
if (aCanCreate) {
accService->GetAccessibleInWeakShell(currentNode, mWeakShell, aAccessible);
GetAccService()->GetAccessibleInWeakShell(currentNode, mWeakShell,
aAccessible);
}
else { // Only return cached accessibles, don't create anything
nsCOMPtr<nsIAccessNode> accessNode;

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

@ -89,11 +89,10 @@ nsRelUtils::AddTargetFromContent(PRUint32 aRelationType,
if (!aContent)
return NS_OK_NO_RELATION_TARGET;
nsCOMPtr<nsIAccessibilityService> accService = nsAccessNode::GetAccService();
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleFor(node, getter_AddRefs(accessible));
GetAccService()->GetAccessibleFor(node, getter_AddRefs(accessible));
return AddTarget(aRelationType, aRelation, accessible);
}

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

@ -152,14 +152,14 @@ nsTextEquivUtils::AppendTextEquivFromContent(nsIAccessible *aInitiatorAcc,
nsIFrame *frame = aContent->GetPrimaryFrame();
PRBool isVisible = frame && frame->GetStyleVisibility()->IsVisible();
nsresult rv;
nsresult rv = NS_ERROR_FAILURE;
PRBool goThroughDOMSubtree = PR_TRUE;
if (isVisible) {
nsCOMPtr<nsIAccessible> accessible;
rv = nsAccessNode::GetAccService()->
GetAccessibleInShell(DOMNode, shell, getter_AddRefs(accessible));
if (NS_SUCCEEDED(rv) && accessible) {
GetAccService()->GetAccessibleInShell(DOMNode, shell,
getter_AddRefs(accessible));
if (accessible) {
rv = AppendFromAccessible(accessible, aString);
goThroughDOMSubtree = PR_FALSE;
}

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

@ -110,8 +110,8 @@ void nsHTMLSelectableAccessible::iterator::CalcSelectionCount(PRInt32 *aSelectio
(*aSelectionCount)++;
}
void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibilityService *aAccService,
nsIMutableArray *aSelectedAccessibles,
void
nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles,
nsPresContext *aContext)
{
PRBool isSelected = PR_FALSE;
@ -121,7 +121,8 @@ void nsHTMLSelectableAccessible::iterator::AddAccessibleIfSelected(nsIAccessibil
mOption->GetSelected(&isSelected);
if (isSelected) {
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);
}
PRBool nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex,
nsIAccessibilityService *aAccService,
PRBool
nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIndex,
nsPresContext *aContext,
nsIAccessible **aAccessible)
{
@ -143,7 +144,7 @@ PRBool nsHTMLSelectableAccessible::iterator::GetAccessibleIfSelected(PRInt32 aIn
if (isSelected) {
if (mSelCount == aIndex) {
nsCOMPtr<nsIDOMNode> optionNode(do_QueryInterface(mOption));
aAccService->GetAccessibleInWeakShell(optionNode, mWeakShell, aAccessible);
GetAccService()->GetAccessibleInWeakShell(optionNode, mWeakShell, aAccessible);
return PR_TRUE;
}
mSelCount++;
@ -201,10 +202,6 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectedChildren(nsIArray **_retval
{
*_retval = nsnull;
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
if (!accService)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIMutableArray> selectedAccessibles =
do_CreateInstance(NS_ARRAY_CONTRACTID);
NS_ENSURE_STATE(selectedAccessibles);
@ -215,7 +212,7 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::GetSelectedChildren(nsIArray **_retval
nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
while (iter.Advance())
iter.AddAccessibleIfSelected(accService, selectedAccessibles, context);
iter.AddAccessibleIfSelected(selectedAccessibles, context);
PRUint32 uLength = 0;
selectedAccessibles->GetLength(&uLength);
@ -231,17 +228,13 @@ NS_IMETHODIMP nsHTMLSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccess
{
*_retval = nsnull;
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
if (!accService)
return NS_ERROR_FAILURE;
nsPresContext *context = GetPresContext();
if (!context)
return NS_ERROR_FAILURE;
nsHTMLSelectableAccessible::iterator iter(this, mWeakShell);
while (iter.Advance())
if (iter.GetAccessibleIfSelected(aIndex, accService, context, _retval))
if (iter.GetAccessibleIfSelected(aIndex, context, _retval))
return NS_OK;
// No matched item found
@ -426,7 +419,6 @@ nsHTMLSelectListAccessible::CacheOptSiblings(nsIContent *aParentContent)
nsHTMLSelectOptionAccessible::nsHTMLSelectOptionAccessible(nsIDOMNode* aDOMNode, nsIWeakReference* aShell):
nsHyperTextAccessibleWrap(aDOMNode, aShell)
{
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
nsCOMPtr<nsIDOMNode> parentNode;
aDOMNode->GetParentNode(getter_AddRefs(parentNode));
nsCOMPtr<nsIAccessible> parentAccessible;
@ -436,7 +428,8 @@ nsHyperTextAccessibleWrap(aDOMNode, aShell)
// GetParent would normally return. This is because the
// nsHTMLComboboxListAccessible is inserted into the accessible hierarchy
// where there is no DOM node for it.
accService->GetAccessibleInWeakShell(parentNode, mWeakShell, getter_AddRefs(parentAccessible));
GetAccService()->GetAccessibleInWeakShell(parentNode, mWeakShell,
getter_AddRefs(parentAccessible));
if (parentAccessible) {
if (nsAccUtils::RoleInternal(parentAccessible) ==
nsIAccessibleRole::ROLE_COMBOBOX) {
@ -839,16 +832,13 @@ nsIContent* nsHTMLSelectOptionAccessible::GetSelectState(PRUint32* aState,
nsCOMPtr<nsIDOMNode> selectNode(do_QueryInterface(content));
if (selectNode) {
nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
if (accService) {
nsCOMPtr<nsIAccessible> selAcc;
accService->GetAccessibleFor(selectNode, getter_AddRefs(selAcc));
GetAccService()->GetAccessibleFor(selectNode, getter_AddRefs(selAcc));
if (selAcc) {
selAcc->GetState(aState, aExtraState);
return content;
}
}
}
return nsnull;
}
@ -1026,13 +1016,12 @@ nsHTMLComboboxAccessible::GetFocusedOptionAccessible()
}
nsCOMPtr<nsIDOMNode> focusedOptionNode;
nsHTMLSelectOptionAccessible::GetFocusedOptionNode(mDOMNode, getter_AddRefs(focusedOptionNode));
nsIAccessibilityService *accService = GetAccService();
if (!focusedOptionNode || !accService) {
if (!focusedOptionNode) {
return nsnull;
}
nsIAccessible *optionAccessible;
accService->GetAccessibleInWeakShell(focusedOptionNode, mWeakShell,
GetAccService()->GetAccessibleInWeakShell(focusedOptionNode, mWeakShell,
&optionAccessible);
return optionAccessible;
}

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

@ -45,7 +45,6 @@
#include "nsIDOMHTMLOptionsCollection.h"
#include "nsIDOMHTMLOptionElement.h"
#include "nsIDOMNode.h"
#include "nsIAccessibilityService.h"
#include "nsAccessibleTreeWalker.h"
class nsIMutableArray;
@ -104,10 +103,10 @@ protected:
void CalcSelectionCount(PRInt32 *aSelectionCount);
void Select(PRBool aSelect);
void AddAccessibleIfSelected(nsIAccessibilityService *aAccService,
nsIMutableArray *aSelectedAccessibles,
void AddAccessibleIfSelected(nsIMutableArray *aSelectedAccessibles,
nsPresContext *aContext);
PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsIAccessibilityService *aAccService, nsPresContext *aContext, nsIAccessible **_retval);
PRBool GetAccessibleIfSelected(PRInt32 aIndex, nsPresContext *aContext,
nsIAccessible **aAccessible);
PRBool Advance();
};

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

@ -39,7 +39,6 @@
#include "nsAccessNodeWrap.h"
#include "ISimpleDOMNode_i.c"
#include "nsAccessibilityAtoms.h"
#include "nsIAccessibilityService.h"
#include "nsIAccessible.h"
#include "nsAttrName.h"
#include "nsIDocument.h"
@ -411,13 +410,10 @@ ISimpleDOMNode* nsAccessNodeWrap::MakeAccessNode(nsIDOMNode *node)
if (!doc)
return NULL;
nsCOMPtr<nsIAccessibilityService> accService(do_GetService("@mozilla.org/accessibilityService;1"));
if (!accService)
return NULL;
ISimpleDOMNode *iNode = NULL;
nsCOMPtr<nsIAccessible> nsAcc;
accService->GetAccessibleInWeakShell(node, mWeakShell, getter_AddRefs(nsAcc));
GetAccService()->GetAccessibleInWeakShell(node, mWeakShell,
getter_AddRefs(nsAcc));
if (nsAcc) {
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(nsAcc));
NS_ASSERTION(accessNode, "nsIAccessible impl does not inherit from nsIAccessNode");

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

@ -125,7 +125,6 @@ nsXFormsAccessible::CacheSelectChildren(nsIDOMNode *aContainerNode)
nsCOMPtr<nsIAccessible> accessible;
nsRefPtr<nsAccessible> acc;
PRUint32 childLength = 0;
for (PRUint32 index = 0; index < length; index++) {
nsCOMPtr<nsIDOMNode> child;
children->Item(index, getter_AddRefs(child));

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

@ -120,9 +120,6 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
NS_ENSURE_TRUE(accService, NS_ERROR_FAILURE);
nsCOMPtr<nsIMutableArray> selectedAccessibles =
do_CreateInstance(NS_ARRAY_CONTRACTID);
NS_ENSURE_STATE(selectedAccessibles);
@ -138,7 +135,7 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre
nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
xulMultiSelect->GetSelectedItem(index, getter_AddRefs(selectedItem));
nsCOMPtr<nsIDOMNode> selectedNode(do_QueryInterface(selectedItem));
accService->GetAccessibleInWeakShell(selectedNode, mWeakShell,
GetAccService()->GetAccessibleInWeakShell(selectedNode, mWeakShell,
getter_AddRefs(selectedAccessible));
if (selectedAccessible)
selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE);
@ -149,7 +146,7 @@ NS_IMETHODIMP nsXULSelectableAccessible::GetSelectedChildren(nsIArray **aChildre
mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
nsCOMPtr<nsIDOMNode> selectedNode(do_QueryInterface(selectedItem));
if(selectedNode) {
accService->GetAccessibleInWeakShell(selectedNode, mWeakShell,
GetAccService()->GetAccessibleInWeakShell(selectedNode, mWeakShell,
getter_AddRefs(selectedAccessible));
if (selectedAccessible)
selectedAccessibles->AppendElement(selectedAccessible, PR_FALSE);
@ -183,15 +180,13 @@ NS_IMETHODIMP nsXULSelectableAccessible::RefSelection(PRInt32 aIndex, nsIAccessi
mSelectControl->GetSelectedItem(getter_AddRefs(selectedItem));
if (selectedItem) {
nsCOMPtr<nsIAccessibilityService> accService = GetAccService();
if (accService) {
accService->GetAccessibleInWeakShell(selectedItem, mWeakShell, aAccessible);
GetAccService()->GetAccessibleInWeakShell(selectedItem, mWeakShell,
aAccessible);
if (*aAccessible) {
NS_ADDREF(*aAccessible);
return NS_OK;
}
}
}
return NS_ERROR_FAILURE;
}
@ -354,8 +349,8 @@ nsXULMenuitemAccessible::GetStateInternal(PRUint32 *aState,
grandParentAcc->GetState(&grandParentState, &grandParentExtState);
*aState &= ~(nsIAccessibleStates::STATE_OFFSCREEN |
nsIAccessibleStates::STATE_INVISIBLE);
*aState |= grandParentState & nsIAccessibleStates::STATE_OFFSCREEN |
grandParentState & nsIAccessibleStates::STATE_INVISIBLE;
*aState |= (grandParentState & nsIAccessibleStates::STATE_OFFSCREEN) |
(grandParentState & nsIAccessibleStates::STATE_INVISIBLE);
if (aExtraState) {
*aExtraState |=
grandParentExtState & nsIAccessibleStates::EXT_STATE_OPAQUE;

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

@ -40,6 +40,10 @@
display: none;
}
tabpanels {
background-color: white;
}
%ifdef MOZ_WIDGET_GTK2
/* Favicons override the "images-in-menus" metric in xul.css */
.alltabs-item > .menu-iconic-left {

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

@ -1335,6 +1335,14 @@ SessionStoreService.prototype = {
catch (ex) { debug(ex); }
}
if (aEntry.docIdentifier) {
entry.docIdentifier = aEntry.docIdentifier;
}
if (aEntry.stateData) {
entry.stateData = aEntry.stateData;
}
if (!(aEntry instanceof Ci.nsISHContainer)) {
return entry;
}
@ -2038,9 +2046,11 @@ SessionStoreService.prototype = {
delete this._windows[aWindow.__SSi]._restoring;
}
// helper hash for ensuring unique frame IDs
// helper hashes for ensuring unique frame IDs and unique document
// identifiers.
var idMap = { used: {} };
this.restoreHistory(aWindow, aTabs, aTabData, idMap);
var docIdentMap = {};
this.restoreHistory(aWindow, aTabs, aTabData, idMap, docIdentMap);
},
/**
@ -2054,7 +2064,8 @@ SessionStoreService.prototype = {
* @param aIdMap
* Hash for ensuring unique frame IDs
*/
restoreHistory: function sss_restoreHistory(aWindow, aTabs, aTabData, aIdMap) {
restoreHistory:
function sss_restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap) {
var _this = this;
while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) {
aTabs.shift(); // this tab got removed before being completely restored
@ -2090,7 +2101,8 @@ SessionStoreService.prototype = {
//XXXzpao Wallpaper patch for bug 514751
if (!tabData.entries[i].url)
continue;
history.addEntry(this._deserializeHistoryEntry(tabData.entries[i], aIdMap), true);
history.addEntry(this._deserializeHistoryEntry(tabData.entries[i],
aIdMap, aDocIdentMap), true);
}
// make sure to reset the capabilities and attributes, in case this tab gets reused
@ -2152,7 +2164,9 @@ SessionStoreService.prototype = {
browser.loadURI(tabData.userTypedValue, null, null, true);
}
aWindow.setTimeout(function(){ _this.restoreHistory(aWindow, aTabs, aTabData, aIdMap); }, 0);
aWindow.setTimeout(function(){
_this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap);
}, 0);
},
/**
@ -2163,7 +2177,9 @@ SessionStoreService.prototype = {
* Hash for ensuring unique frame IDs
* @returns nsISHEntry
*/
_deserializeHistoryEntry: function sss_deserializeHistoryEntry(aEntry, aIdMap) {
_deserializeHistoryEntry:
function sss_deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) {
var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].
createInstance(Ci.nsISHEntry);
@ -2196,6 +2212,10 @@ SessionStoreService.prototype = {
shEntry.ID = id;
}
if (aEntry.stateData) {
shEntry.stateData = aEntry.stateData;
}
if (aEntry.scroll) {
var scrollPos = (aEntry.scroll || "0,0").split(",");
scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
@ -2216,6 +2236,28 @@ SessionStoreService.prototype = {
shEntry.postData = stream;
}
if (aEntry.docIdentifier) {
// Get a new document identifier for this entry to ensure that history
// entries after a session restore are considered to have different
// documents from the history entries before the session restore.
// Document identifiers are 64-bit ints, so JS will loose precision and
// start assigning all entries the same doc identifier if these ever get
// large enough.
//
// It's a potential security issue if document identifiers aren't
// globally unique, but shEntry.setUniqueDocIdentifier() below guarantees
// that we won't re-use a doc identifier within a given instance of the
// application.
let ident = aDocIdentMap[aEntry.docIdentifier];
if (!ident) {
shEntry.setUniqueDocIdentifier();
aDocIdentMap[aEntry.docIdentifier] = shEntry.docIdentifier;
}
else {
shEntry.docIdentifier = ident;
}
}
if (aEntry.owner_b64) { // Firefox 3
var ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(Ci.nsIStringInputStream);
@ -2237,7 +2279,8 @@ SessionStoreService.prototype = {
//XXXzpao Wallpaper patch for bug 514751
if (!aEntry.children[i].url)
continue;
shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap), i);
shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap,
aDocIdentMap), i);
}
}

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

@ -108,6 +108,7 @@ _BROWSER_TEST_FILES = \
browser_491577.js \
browser_493467.js \
browser_495495.js \
browser_500328.js \
browser_506482.js \
browser_514751.js \
browser_522545.js \

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

@ -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");
}
tabpanels {
-moz-appearance: none;
}
/* Tabs */
.tabbrowser-tab {
border: none !important;

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

@ -399,7 +399,6 @@ menubutton:not([disabled="true"]):hover:active {
-moz-image-region: rect(23px, 36px, 46px, 0px);
}
#back-button:hover:active:not([disabled]),
#back-button[buttondown="true"]:not([disabled]),
#back-button[open="true"] {
-moz-image-region: rect(46px, 36px, 69px, 0px);
}
@ -414,7 +413,6 @@ menubutton:not([disabled="true"]):hover:active {
-moz-image-region: rect(23px, 72px, 46px, 36px);
}
#forward-button:hover:active:not([disabled]),
#forward-button[buttondown="true"]:not([disabled]),
#forward-button[open="true"] {
-moz-image-region: rect(46px, 72px, 69px, 36px);
}
@ -1591,10 +1589,6 @@ tabbrowser > tabbox {
display: none;
}
tabbrowser > tabbox > tabpanels {
-moz-appearance: none !important;
}
/**
* Tab Drag and Drop
*/
@ -1782,10 +1776,6 @@ tabbrowser > tabbox > tabpanels {
list-style-image: url("chrome://global/skin/icons/closetab-active.png");
}
tabpanels.plain {
background-color: #fff !important;
}
/* Bookmarks toolbar */
.toolbar-drop-indicator {
list-style-image: url(chrome://browser/skin/places/toolbarDropMarker.png);

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

@ -1177,10 +1177,6 @@ statusbarpanel#statusbar-display {
border-bottom: 1px solid threedshadow;
}
tabpanels {
-moz-appearance: none;
}
/* tabbrowser-tab focus ring */
.tabbrowser-tab > .tab-text {
border: 1px dotted transparent;

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

@ -41,7 +41,7 @@
interface nsIURI;
interface nsIChannel;
[scriptable, uuid(c0dbfd5e-b7ae-4c18-8674-82492f35d715)]
[scriptable, uuid(50eda256-4dd2-4c7c-baed-96983910af9f)]
interface nsIScriptSecurityManager : nsIXPCSecurityManager
{
///////////////// Security Checks //////////////////
@ -54,14 +54,6 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
in JSVal aProperty,
in PRUint32 aAction);
/**
* Checks whether the running script is allowed to connect to aTargetURI
*/
[noscript] void checkConnect(in JSContextPtr aJSContext,
in nsIURI aTargetURI,
in string aClassName,
in string aProperty);
/**
* Check that the script currently running in context "cx" can load "uri".
*

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

@ -410,8 +410,7 @@ public:
static nsresult
CheckSameOriginPrincipal(nsIPrincipal* aSubject,
nsIPrincipal* aObject,
PRBool aIsCheckConnect);
nsIPrincipal* aObject);
static PRUint32
HashPrincipalByOrigin(nsIPrincipal* aPrincipal);
@ -458,8 +457,7 @@ private:
nsresult
CheckSameOriginDOMProp(nsIPrincipal* aSubject,
nsIPrincipal* aObject,
PRUint32 aAction,
PRBool aIsCheckConnect);
PRUint32 aAction);
nsresult
LookupPolicy(nsIPrincipal* principal,

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

@ -363,8 +363,7 @@ nsPrincipal::Equals(nsIPrincipal *aOther, PRBool *aResult)
// Codebases are equal if they have the same origin.
*aResult =
NS_SUCCEEDED(nsScriptSecurityManager::CheckSameOriginPrincipal(this,
aOther,
PR_FALSE));
aOther));
return NS_OK;
}

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

@ -563,34 +563,6 @@ nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx,
aClassName, aProperty, nsnull);
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckConnect(JSContext* cx,
nsIURI* aTargetURI,
const char* aClassName,
const char* aPropertyName)
{
// Get a context if necessary
if (!cx)
{
cx = GetCurrentJSContext();
if (!cx)
return NS_OK; // No JS context, so allow the load
}
nsresult rv = CheckLoadURIFromScript(cx, aTargetURI);
if (NS_FAILED(rv)) return rv;
JSAutoRequest ar(cx);
JSString* propertyName = ::JS_InternString(cx, aPropertyName);
if (!propertyName)
return NS_ERROR_OUT_OF_MEMORY;
return CheckPropertyAccessImpl(nsIXPCSecurityManager::ACCESS_CALL_METHOD, nsnull,
cx, nsnull, nsnull, aTargetURI,
nsnull, aClassName, STRING_TO_JSVAL(propertyName), nsnull);
}
NS_IMETHODIMP
nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
nsIURI* aTargetURI)
@ -750,7 +722,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
}
if(NS_SUCCEEDED(rv))
rv = CheckSameOriginDOMProp(subjectPrincipal, objectPrincipal,
aAction, aTargetURI != nsnull);
aAction);
break;
}
default:
@ -943,8 +915,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction,
/* static */
nsresult
nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
nsIPrincipal* aObject,
PRBool aIsCheckConnect)
nsIPrincipal* aObject)
{
/*
** Get origin of subject and object and compare.
@ -952,23 +923,13 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
if (aSubject == aObject)
return NS_OK;
// These booleans are only used when !aIsCheckConnect. Default
// them to false, and change if that turns out wrong.
// Default to false, and change if that turns out wrong.
PRBool subjectSetDomain = PR_FALSE;
PRBool objectSetDomain = PR_FALSE;
nsCOMPtr<nsIURI> subjectURI;
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));
if (!subjectURI) {
aSubject->GetURI(getter_AddRefs(subjectURI));
@ -982,7 +943,6 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
} else {
objectSetDomain = PR_TRUE;
}
}
if (SecurityCompareURIs(subjectURI, objectURI))
{ // 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
// DNS spoofing based on document.domain (154930)
// But this restriction does not apply to CheckConnect calls, since
// that's called for data-only load checks like XMLHTTPRequest where
// we ignore domain (bug 290100).
if (aIsCheckConnect)
return NS_OK;
// If both or neither explicitly set their domain, allow the access
if (subjectSetDomain == objectSetDomain)
return NS_OK;
@ -1009,7 +963,7 @@ nsScriptSecurityManager::CheckSameOriginPrincipal(nsIPrincipal* aSubject,
// It's important that
//
// CheckSameOriginPrincipal(A, B, PR_FALSE) == NS_OK
// CheckSameOriginPrincipal(A, B) == NS_OK
//
// imply
//
@ -1032,22 +986,14 @@ nsScriptSecurityManager::HashPrincipalByOrigin(nsIPrincipal* aPrincipal)
nsresult
nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject,
nsIPrincipal* aObject,
PRUint32 aAction,
PRBool aIsCheckConnect)
PRUint32 aAction)
{
nsresult rv;
if (aIsCheckConnect) {
// Don't do equality compares, just do a same-origin compare,
// since the object principal isn't a real principal, just a
// GetCodebasePrincipal() on whatever URI we started with.
rv = CheckSameOriginPrincipal(aSubject, aObject, aIsCheckConnect);
} else {
PRBool subsumes;
rv = aSubject->Subsumes(aObject, &subsumes);
if (NS_SUCCEEDED(rv) && !subsumes) {
rv = NS_ERROR_DOM_PROP_ACCESS_DENIED;
}
}
if (NS_SUCCEEDED(rv))
return NS_OK;

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

@ -39,7 +39,7 @@
interface nsIDOMFileError;
[scriptable, uuid(0845E8AE-56BD-4F0E-962A-3B3E92638A0B)]
[scriptable, uuid(16753172-6890-4e6a-8c10-a7ff30c5ef22)]
interface nsIDOMFile : nsISupports
{
//fileName and fileSize are now deprecated attributes
@ -47,6 +47,7 @@ interface nsIDOMFile : nsISupports
readonly attribute unsigned long long fileSize;
readonly attribute DOMString name;
readonly attribute DOMString mozFullPath;
readonly attribute unsigned long long size;
readonly attribute DOMString type;

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

@ -106,8 +106,8 @@ class nsIBoxObject;
// IID for the nsIDocument interface
#define NS_IDOCUMENT_IID \
{ 0xb04d9176, 0xf087, 0x4d3c, \
{ 0x87, 0x11, 0x13, 0x9d, 0x19, 0x95, 0x43, 0x55 } }
{ 0x6b2f1996, 0x95d4, 0x48db, \
{0xaf, 0xd1, 0xfd, 0xaa, 0x75, 0x4c, 0x79, 0x92 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -1225,6 +1225,28 @@ public:
Doc_Theme_Bright
};
/**
* Returns the document's pending state object (serialized to JSON), or the
* empty string if one doesn't exist.
*
* This field serves as a waiting place for the history entry's state object:
* We set the field's value to the history entry's state object early on in
* the load, then after we fire onload we deserialize the field's value and
* fire a popstate event containing the resulting object.
*/
nsAString& GetPendingStateObject()
{
return mPendingStateObject;
}
/**
* Set the document's pending state object (as serialized to JSON).
*/
void SetPendingStateObject(nsAString &obj)
{
mPendingStateObject.Assign(obj);
}
/**
* Returns Doc_Theme_None if there is no lightweight theme specified,
* Doc_Theme_Dark for a dark theme, Doc_Theme_Bright for a light theme, and
@ -1388,6 +1410,8 @@ protected:
nsCOMPtr<nsIDocument> mDisplayDocument;
PRUint32 mEventsSuppressed;
nsString mPendingStateObject;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)

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

@ -407,6 +407,7 @@ nsContentUtils::InitializeEventTable() {
{ &nsGkAtoms::onchange, { NS_FORM_CHANGE, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onselect, { NS_FORM_SELECTED, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onload, { NS_LOAD, EventNameType_All }},
{ &nsGkAtoms::onpopstate, { NS_POPSTATE, EventNameType_HTMLXUL }},
{ &nsGkAtoms::onunload, { NS_PAGE_UNLOAD,
(EventNameType_HTMLXUL | EventNameType_SVGSVG) }},
{ &nsGkAtoms::onhashchange, { NS_HASHCHANGE, EventNameType_HTMLXUL }},

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

@ -108,6 +108,16 @@ nsDOMFile::GetName(nsAString &aFileName)
return mFile->GetLeafName(aFileName);
}
NS_IMETHODIMP
nsDOMFile::GetMozFullPath(nsAString &aFileName)
{
if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) {
return mFile->GetPath(aFileName);
}
aFileName.Truncate();
return NS_OK;
}
NS_IMETHODIMP
nsDOMFile::GetSize(PRUint64 *aFileSize)
{

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

@ -46,6 +46,11 @@
* Base class for all our document implementations.
*/
#ifdef MOZ_LOGGING
// so we can get logging even in release builds
#define FORCE_PR_LOG 1
#endif
#include "prlog.h"
#include "plstr.h"
#include "prprf.h"
@ -184,13 +189,6 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
// FOR CSP (autogenerated by xpidl)
#include "nsIContentSecurityPolicy.h"
#ifdef MOZ_LOGGING
// so we can get logging even in release builds
#define FORCE_PR_LOG 1
#endif
#include "prlog.h"
/* Keeps track of whether or not CSP is enabled */
static PRBool gCSPEnabled = PR_TRUE;

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

@ -650,6 +650,7 @@ GK_ATOM(onkeypress, "onkeypress")
GK_ATOM(onkeyup, "onkeyup")
GK_ATOM(onLoad, "onLoad")
GK_ATOM(onload, "onload")
GK_ATOM(onpopstate, "onpopstate")
GK_ATOM(only, "only") // this one is not an event
GK_ATOM(onmousedown, "onmousedown")
GK_ATOM(onmousemove, "onmousemove")

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

@ -2402,9 +2402,13 @@ WebGLContext::ValidateGL()
//fprintf(stderr, "GL_MAX_VERTEX_ATTRIBS: %d\n", val);
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_UNITS, &val);
// Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
// even though the hardware supports much more. The
// GL_MAX_{COMBINED_}TEXTURE_IMAGE_UNITS value is the accurate
// value. For GLES2, GL_MAX_TEXTURE_UNITS is still correc.t
gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &val);
if (val == 0) {
LogMessage("GL_MAX_TEXTURE_UNITS is 0!");
LogMessage("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is 0!");
return PR_FALSE;
}

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

@ -82,6 +82,7 @@ CPPSRCS = \
nsDOMEventTargetHelper.cpp \
nsDOMScrollAreaEvent.cpp \
nsDOMTransitionEvent.cpp \
nsDOMPopStateEvent.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a static lib.

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

@ -59,12 +59,13 @@
#include "nsIURI.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScriptError.h"
#include "nsDOMPopStateEvent.h"
static const char* const sEventNames[] = {
"mousedown", "mouseup", "click", "dblclick", "mouseover",
"mouseout", "mousemove", "contextmenu", "keydown", "keyup", "keypress",
"focus", "blur", "load", "beforeunload", "unload", "hashchange", "abort", "error",
"submit", "reset", "change", "select", "input" ,"text",
"focus", "blur", "load", "popstate", "beforeunload", "unload", "hashchange",
"abort", "error", "submit", "reset", "change", "select", "input", "text",
"compositionstart", "compositionend", "popupshowing", "popupshown",
"popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate",
"dragenter", "dragover", "dragexit", "dragdrop", "draggesture",
@ -1328,6 +1329,8 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType)
return sEventNames[eDOMEvents_close];
case NS_LOAD:
return sEventNames[eDOMEvents_load];
case NS_POPSTATE:
return sEventNames[eDOMEvents_popstate];
case NS_BEFORE_PAGE_UNLOAD:
return sEventNames[eDOMEvents_beforeunload];
case NS_PAGE_UNLOAD:

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

@ -58,7 +58,7 @@ class nsDOMEvent : public nsIDOMEvent,
{
public:
// Note: this enum must be kept in sync with mEventNames in nsDOMEvent.cpp
// Note: this enum must be kept in sync with sEventNames in nsDOMEvent.cpp
enum nsDOMEvents {
eDOMEvents_mousedown=0,
eDOMEvents_mouseup,
@ -74,6 +74,7 @@ public:
eDOMEvents_focus,
eDOMEvents_blur,
eDOMEvents_load,
eDOMEvents_popstate,
eDOMEvents_beforeunload,
eDOMEvents_unload,
eDOMEvents_hashchange,

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

@ -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 "nsINode.h"
#include "nsPIDOMWindow.h"
#include "nsDOMPopStateEvent.h"
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
@ -796,6 +797,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
// is probably wrong!
if (aEventType.LowerCaseEqualsLiteral("transitionevent"))
return NS_NewDOMTransitionEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("popstateevent"))
return NS_NewDOMPopStateEvent(aDOMEvent, aPresContext, nsnull);
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}

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

@ -692,9 +692,30 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
loadAsHtml5 = PR_FALSE;
}
if (!(contentType.EqualsLiteral("text/html") && aCommand && !nsCRT::strcmp(aCommand, "view"))) {
if (loadAsHtml5 &&
!(contentType.EqualsLiteral("text/html") &&
aCommand &&
!nsCRT::strcmp(aCommand, "view"))) {
loadAsHtml5 = PR_FALSE;
}
// TODO: Proper about:blank treatment is bug 543435
if (loadAsHtml5) {
// mDocumentURI hasn't been set, yet, so get the URI from the channel
nsCOMPtr<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
else {
NS_ASSERTION(mIsRegularHTML,

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

@ -44,6 +44,12 @@ namespace mozilla {
class SMILBoolType : public nsISMILType
{
public:
// Singleton for nsSMILValue objects to hold onto.
static SMILBoolType sSingleton;
protected:
// nsISMILType Methods
// -------------------
virtual nsresult Init(nsSMILValue& aValue) const;
virtual void Destroy(nsSMILValue&) const;
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
@ -57,10 +63,11 @@ public:
double aUnitDistance,
nsSMILValue& aResult) const;
static SMILBoolType sSingleton;
private:
// Private constructor & destructor: prevent instances beyond my singleton,
// and prevent others from deleting my singleton.
SMILBoolType() {}
~SMILBoolType() {}
};
} // namespace mozilla

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

@ -44,6 +44,12 @@ namespace mozilla {
class SMILEnumType : public nsISMILType
{
public:
// Singleton for nsSMILValue objects to hold onto.
static SMILEnumType sSingleton;
protected:
// nsISMILType Methods
// -------------------
virtual nsresult Init(nsSMILValue& aValue) const;
virtual void Destroy(nsSMILValue&) const;
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
@ -57,10 +63,11 @@ public:
double aUnitDistance,
nsSMILValue& aResult) const;
static SMILEnumType sSingleton;
private:
// Private constructor & destructor: prevent instances beyond my singleton,
// and prevent others from deleting my singleton.
SMILEnumType() {}
~SMILEnumType() {}
};
} // namespace mozilla

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

@ -75,7 +75,12 @@ class nsSMILValue;
class nsISMILType
{
public:
/**
* Only give the nsSMILValue class access to this interface.
*/
friend class nsSMILValue;
protected:
/**
* Initialises aValue and sets it to some identity value such that adding
* aValue to another value of the same type has no effect.
@ -211,11 +216,12 @@ public:
double aUnitDistance,
nsSMILValue& aResult) const = 0;
/*
* Virtual destructor: Nothing to do here, but subclasses
* may need it.
/**
* Protected destructor, to ensure that no one accidentally deletes an
* instance of this class.
* (The only instances in existence should be singletons - one per subclass.)
*/
virtual ~nsISMILType() {};
~nsISMILType() {}
};
#endif // NS_ISMILTYPE_H_

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

@ -46,13 +46,16 @@
#include "nsIContent.h"
#include "nsIDOMElement.h"
// Helper function
static PRBool
GetCSSComputedValue(nsIContent* aElem,
nsCSSProperty aPropID,
nsAString& aResult)
{
NS_ENSURE_TRUE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID),
PR_FALSE);
NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aPropID),
"Can't look up computed value of shorthand property");
NS_ABORT_IF_FALSE(nsSMILCSSProperty::IsPropertyAnimatable(aPropID),
"Shouldn't get here for non-animatable properties");
nsIDocument* doc = aElem->GetCurrentDoc();
if (!doc) {
@ -73,8 +76,7 @@ GetCSSComputedValue(nsIContent* aElem,
nsresult rv = NS_NewComputedDOMStyle(domElement, EmptyString(), shell,
getter_AddRefs(computedStyle));
if (NS_SUCCEEDED(rv) && computedStyle) {
// NOTE: This will produce an empty string for shorthand values
if (NS_SUCCEEDED(rv)) {
computedStyle->GetPropertyValue(aPropID, aResult);
return PR_TRUE;
}
@ -94,6 +96,20 @@ nsSMILCSSProperty::nsSMILCSSProperty(nsCSSProperty aPropID,
nsSMILValue
nsSMILCSSProperty::GetBaseValue() const
{
// SPECIAL CASE: Shorthands
if (nsCSSProps::IsShorthand(mPropID)) {
// We can't look up the base (computed-style) value of shorthand
// properties, because they aren't guaranteed to have a consistent computed
// value. However, that's not a problem, because it turns out the caller
// isn't going to end up using the value we return anyway. Base values only
// get used when there's interpolation or addition, and the shorthand
// properties we know about don't support those operations. So, we can just
// return a dummy value (initialized with the right type, so as not to
// indicate failure).
return nsSMILValue(&nsSMILCSSValueType::sSingleton);
}
// GENERAL CASE: Non-Shorthands
// (1) Put empty string in override style for property mPropID
// (saving old override style value, so we can set it again when we're done)
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
@ -118,18 +134,11 @@ nsSMILCSSProperty::GetBaseValue() const
overrideDecl->SetPropertyValue(mPropID, cachedOverrideStyleVal);
}
// (4) Create a nsSMILValue from the computed style
nsSMILValue baseValue;
if (didGetComputedVal) {
// (4) Create the nsSMILValue from the computed style value
nsSMILCSSValueType::sSingleton.Init(baseValue);
if (!nsCSSProps::IsShorthand(mPropID) &&
!nsSMILCSSValueType::sSingleton.ValueFromString(mPropID, mElement,
computedStyleVal,
baseValue)) {
nsSMILCSSValueType::sSingleton.Destroy(baseValue);
NS_ABORT_IF_FALSE(baseValue.IsNull(),
"Destroy should leave us with null-typed value");
}
nsSMILCSSValueType::ValueFromString(mPropID, mElement,
computedStyleVal, baseValue);
}
return baseValue;
}
@ -140,14 +149,9 @@ nsSMILCSSProperty::ValueFromString(const nsAString& aStr,
nsSMILValue& aValue) const
{
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
nsSMILCSSValueType::sSingleton.Init(aValue);
PRBool success =
nsSMILCSSValueType::sSingleton.ValueFromString(mPropID, mElement,
aStr, aValue);
if (!success) {
nsSMILCSSValueType::sSingleton.Destroy(aValue);
}
return success ? NS_OK : NS_ERROR_FAILURE;
nsSMILCSSValueType::ValueFromString(mPropID, mElement, aStr, aValue);
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
nsresult
@ -155,32 +159,29 @@ nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue)
{
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
nsresult rv = NS_OK;
// Convert nsSMILValue to string
nsAutoString valStr;
if (!nsSMILCSSValueType::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)) {
// Apply the style to the target element
// Use string value to style the target element
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
NS_ABORT_IF_FALSE(overrideStyle, "Need a non-null overrideStyle");
nsCOMPtr<nsICSSDeclaration> overrideDecl =
do_QueryInterface(overrideStyle);
nsCOMPtr<nsICSSDeclaration> overrideDecl = do_QueryInterface(overrideStyle);
if (overrideDecl) {
overrideDecl->SetPropertyValue(mPropID, valStr);
}
} else {
NS_WARNING("Failed to convert nsSMILValue for CSS property into a string");
rv = NS_ERROR_FAILURE;
}
return rv;
return NS_OK;
}
void
nsSMILCSSProperty::ClearAnimValue()
{
// Put empty string in override style for property propID
// Put empty string in override style for our property
nsCOMPtr<nsIDOMCSSStyleDeclaration> overrideStyle;
mElement->GetSMILOverrideStyle(getter_AddRefs(overrideStyle));
nsCOMPtr<nsICSSDeclaration> overrideDecl = do_QueryInterface(overrideStyle);

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

@ -303,59 +303,79 @@ GetPresContextForElement(nsIContent* aElem)
return shell ? shell->GetPresContext() : nsnull;
}
PRBool
nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
// Helper function to parse a string into a nsStyleAnimation::Value
static PRBool
ValueFromStringHelper(nsCSSProperty aPropID,
nsIContent* aTargetElement,
nsPresContext* aPresContext,
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
// barf, and then manually make the parsed value negative. (This is a partial
// solution to let us accept some otherwise out-of-bounds CSS values -- bug
// 501188 will provide a more complete fix.)
// barf, and then manually make the parsed value negative.
// (This is a partial solution to let us accept some otherwise out-of-bounds
// CSS values. Bug 501188 will provide a more complete fix.)
PRBool isNegative = PR_FALSE;
PRUint32 subStringBegin = 0;
PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
if (absValuePos > 0) {
subStringBegin = (PRUint32)absValuePos;
isNegative = PR_TRUE;
subStringBegin = (PRUint32)absValuePos; // Start parsing after '-' sign
}
nsDependentSubstring subString(aString, subStringBegin);
nsStyleAnimation::Value parsedValue;
if (nsStyleAnimation::ComputeValue(aPropID, aTargetElement,
subString, parsedValue)) {
if (isNegative) {
InvertSign(parsedValue);
}
if (aPropID == eCSSProperty_font_size) {
// Divide out text-zoom, since SVG is supposed to ignore it
NS_ABORT_IF_FALSE(parsedValue.GetUnit() == nsStyleAnimation::eUnit_Coord,
"'font-size' value with unexpected style unit");
parsedValue.SetCoordValue(parsedValue.GetCoordValue() /
presContext->TextZoom());
}
aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
return aValue.mU.mPtr != nsnull;
}
if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement,
subString, aStyleAnimValue)) {
return PR_FALSE;
}
if (isNegative) {
InvertSign(aStyleAnimValue);
}
if (aPropID == eCSSProperty_font_size) {
// Divide out text-zoom, since SVG is supposed to ignore it
NS_ABORT_IF_FALSE(aStyleAnimValue.GetUnit() ==
nsStyleAnimation::eUnit_Coord,
"'font-size' value with unexpected style unit");
aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
aPresContext->TextZoom());
}
return PR_TRUE;
}
// static
void
nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
nsIContent* aTargetElement,
const nsAString& aString,
nsSMILValue& aValue)
{
NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
nsPresContext* presContext = GetPresContextForElement(aTargetElement);
if (!presContext) {
NS_WARNING("Not parsing animation value; unable to get PresContext");
return;
}
nsStyleAnimation::Value parsedValue;
if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
aString, parsedValue)) {
sSingleton.Init(aValue);
aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
if (!aValue.mU.mPtr) {
// Out of memory! Destroy outparam, to leave it as nsSMILNullType,
// which indicates to our caller that we failed.
sSingleton.Destroy(aValue);
}
}
}
// static
PRBool
nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
nsAString& aString) const
nsAString& aString)
{
NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton,
"Passed-in value is wrong type");
"Unexpected SMIL value type");
const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
return !wrapper ||
nsStyleAnimation::UncomputeValue(wrapper->mPropID, wrapper->mPresContext,

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

@ -54,8 +54,12 @@ class nsAString;
class nsSMILCSSValueType : public nsISMILType
{
public:
// nsISMILValueType Methods
// ------------------------
// Singleton for nsSMILValue objects to hold onto.
static nsSMILCSSValueType sSingleton;
protected:
// nsISMILType Methods
// -------------------
NS_OVERRIDE virtual nsresult Init(nsSMILValue& aValue) const;
NS_OVERRIDE virtual void Destroy(nsSMILValue&) const;
NS_OVERRIDE virtual nsresult Assign(nsSMILValue& aDest,
@ -71,24 +75,29 @@ public:
double aUnitDistance,
nsSMILValue& aResult) const;
public:
// Helper Methods
// --------------
/**
* Sets up the given nsSMILValue to represent the given string value. The
* string is interpreted as a value for the given property on the given
* element.
*
* Note: aValue is expected to be freshly initialized (i.e. it should already
* have been passed into nsSMILCSSValueType::Init(), and it should not have
* been set up further via e.g. Assign() or another ValueFromString() call.)
* On failure, this method leaves aValue.mType == nsSMILNullType::sSingleton.
* Otherwise, this method leaves aValue.mType == this class's singleton.
*
* @param aPropID The property for which we're parsing a value.
* @param aTargetElement The target element to whom the property/value
* setting applies.
* @param aString The string to be parsed as a CSS value.
* @param [out] aValue The nsSMILValue to be populated.
* @return PR_TRUE on success, PR_FALSE on failure.
* @param [out] aValue The nsSMILValue to be populated. Should
* initially be null-typed.
* @pre aValue.IsNull()
* @post aValue.IsNull() || aValue.mType == nsSMILCSSValueType::sSingleton
*/
PRBool ValueFromString(nsCSSProperty aPropID, nsIContent* aTargetElement,
const nsAString& aString, nsSMILValue& aValue) const;
static void ValueFromString(nsCSSProperty aPropID,
nsIContent* aTargetElement,
const nsAString& aString, nsSMILValue& aValue);
/**
* Creates a string representation of the given nsSMILValue.
@ -102,13 +111,13 @@ public:
* @param [out] aString The string to be populated with the given value.
* @return PR_TRUE on success, PR_FALSE on failure.
*/
PRBool ValueToString(const nsSMILValue& aValue, nsAString& aString) const;
// Singleton for nsSMILValue objects to hold onto.
static nsSMILCSSValueType sSingleton;
static PRBool ValueToString(const nsSMILValue& aValue, nsAString& aString);
private:
// Private constructor & destructor: prevent instances beyond my singleton,
// and prevent others from deleting my singleton.
nsSMILCSSValueType() {}
~nsSMILCSSValueType() {}
};
#endif // NS_SMILCSSVALUETYPE_H_

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

@ -44,6 +44,12 @@
class nsSMILFloatType : public nsISMILType
{
public:
// Singleton for nsSMILValue objects to hold onto.
static nsSMILFloatType sSingleton;
protected:
// nsISMILType Methods
// -------------------
virtual nsresult Init(nsSMILValue& aValue) const;
virtual void Destroy(nsSMILValue&) const;
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
@ -57,10 +63,11 @@ public:
double aUnitDistance,
nsSMILValue& aResult) const;
static nsSMILFloatType sSingleton;
private:
// Private constructor & destructor: prevent instances beyond my singleton,
// and prevent others from deleting my singleton.
nsSMILFloatType() {}
~nsSMILFloatType() {}
};
#endif // NS_SMILFLOATTYPE_H_

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

@ -44,6 +44,12 @@
class nsSMILNullType : public nsISMILType
{
public:
// Singleton for nsSMILValue objects to hold onto.
static nsSMILNullType sSingleton;
protected:
// nsISMILType Methods
// -------------------
virtual nsresult Init(nsSMILValue& aValue) const { return NS_OK; }
virtual void Destroy(nsSMILValue& aValue) const {}
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
@ -60,7 +66,11 @@ public:
double aUnitDistance,
nsSMILValue& aResult) const;
static nsSMILNullType sSingleton;
private:
// Private constructor & destructor: prevent instances beyond my singleton,
// and prevent others from deleting my singleton.
nsSMILNullType() {}
~nsSMILNullType() {}
};
#endif // NS_SMILNULLTYPE_H_

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

@ -50,12 +50,6 @@
#include "nsISVGValue.h"
#include "prdtoa.h"
nsISMILType*
nsSVGTransformSMILAttr::GetSMILType() const
{
return &nsSVGTransformSMILType::sSingleton;
}
nsresult
nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* aSrcElement,
@ -65,32 +59,21 @@ nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
NS_ASSERTION(aValue.IsNull(),
"aValue should have been cleared before calling ValueFromString");
nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
if (val.IsNull())
return NS_ERROR_FAILURE;
const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
const nsIAtom* transformType = typeAttr
? typeAttr->GetAtomValue()
: nsGkAtoms::translate;
nsresult rv = ParseValue(aStr, transformType, val);
if (NS_FAILED(rv))
return rv;
aValue = val;
return NS_OK;
ParseValue(aStr, transformType, aValue);
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
nsSMILValue
nsSVGTransformSMILAttr::GetBaseValue() const
{
nsSVGTransformSMILType *type = &nsSVGTransformSMILType::sSingleton;
nsSMILValue val(type);
nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
if (val.IsNull())
return val;
return val; // Initialization failed
nsIDOMSVGTransformList *list = mVal->mBaseVal.get();
@ -149,19 +132,12 @@ nsSVGTransformSMILAttr::SetAnimValue(const nsSMILValue& aValue)
//----------------------------------------------------------------------
// Implementation helpers
nsresult
void
nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult) const
nsSMILValue& aResult)
{
nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton;
NS_ASSERTION(
type == static_cast<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);
NS_ASSERTION(aResult.IsNull(), "Unexpected type for SMIL value");
float params[3] = { 0.f };
PRInt32 numParsed = ParseParameterList(aSpec, params, 3);
@ -170,12 +146,12 @@ nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
if (aTransformType == nsGkAtoms::translate) {
// tx [ty=0]
if (numParsed != 1 && numParsed != 2)
return NS_ERROR_FAILURE;
return;
transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE;
} else if (aTransformType == nsGkAtoms::scale) {
// sx [sy=sx]
if (numParsed != 1 && numParsed != 2)
return NS_ERROR_FAILURE;
return;
if (numParsed == 1) {
params[1] = params[0];
}
@ -183,35 +159,41 @@ nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
} else if (aTransformType == nsGkAtoms::rotate) {
// r [cx=0 cy=0]
if (numParsed != 1 && numParsed != 3)
return NS_ERROR_FAILURE;
return;
transformType = nsSVGSMILTransform::TRANSFORM_ROTATE;
} else if (aTransformType == nsGkAtoms::skewX) {
// x-angle
if (numParsed != 1)
return NS_ERROR_FAILURE;
return;
transformType = nsSVGSMILTransform::TRANSFORM_SKEWX;
} else if (aTransformType == nsGkAtoms::skewY) {
// y-angle
if (numParsed != 1)
return NS_ERROR_FAILURE;
return;
transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
} else {
return NS_ERROR_FAILURE;
return;
}
return type->AppendTransform(nsSVGSMILTransform(transformType, params),
aResult);
nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
nsSVGSMILTransform transform(transformType, params);
if (NS_FAILED(nsSVGTransformSMILType::AppendTransform(transform, val))) {
return;
}
// Success! Initialize our outparam with parsed value.
aResult = val;
}
inline PRBool
nsSVGTransformSMILAttr::IsSpace(const char c) const
IsSpace(const char c)
{
return (c == 0x9 || c == 0xA || c == 0xD || c == 0x20);
}
inline void
nsSVGTransformSMILAttr::SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd) const
SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd)
{
while (aIter != aIterEnd && IsSpace(*aIter))
++aIter;
@ -220,7 +202,7 @@ nsSVGTransformSMILAttr::SkipWsp(nsACString::const_iterator& aIter,
PRInt32
nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec,
float* aVars,
PRInt32 aNVars) const
PRInt32 aNVars)
{
NS_ConvertUTF16toUTF8 spec(aSpec);
@ -258,9 +240,10 @@ nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec,
nsresult
nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue(
nsIDOMSVGTransform* aTransform, nsSMILValue& aValue) const
nsIDOMSVGTransform* aTransform, nsSMILValue& aValue)
{
nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton;
NS_ASSERTION(aValue.mType == &nsSVGTransformSMILType::sSingleton,
"Unexpected type for SMIL value");
PRUint16 svgTransformType = nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX;
aTransform->GetType(&svgTransformType);
@ -328,10 +311,9 @@ nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue(
matrix->GetD(&mx[3]);
matrix->GetE(&mx[4]);
matrix->GetF(&mx[5]);
rv = type->AppendTransform(nsSVGSMILTransform(mx), aValue);
transformType = nsSVGSMILTransform::TRANSFORM_MATRIX;
return nsSVGTransformSMILType::AppendTransform(nsSVGSMILTransform(mx),
aValue);
}
break;
case nsIDOMSVGTransform::SVG_TRANSFORM_UNKNOWN:
// If it's 'unknown', it's probably not initialised, so just skip it.
@ -342,12 +324,11 @@ nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue(
return NS_ERROR_FAILURE;
}
if (transformType != nsSVGSMILTransform::TRANSFORM_MATRIX) {
rv =
type->AppendTransform(nsSVGSMILTransform(transformType, params), aValue);
}
NS_ABORT_IF_FALSE(transformType != nsSVGSMILTransform::TRANSFORM_MATRIX,
"generalized matrix case should have returned above");
return rv;
return nsSVGTransformSMILType::
AppendTransform(nsSVGSMILTransform(transformType, params), aValue);
}
nsresult
@ -396,40 +377,34 @@ nsSVGTransformSMILAttr::UpdateFromSMILValue(
nsresult
nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue(
const nsSVGSMILTransform& aSMILTransform,
nsIDOMSVGTransform* aSVGTransform) const
nsIDOMSVGTransform* aSVGTransform)
{
nsresult rv = NS_ERROR_FAILURE;
switch (aSMILTransform.mTransformType)
{
case nsSVGSMILTransform::TRANSFORM_TRANSLATE:
rv = aSVGTransform->SetTranslate(aSMILTransform.mParams[0],
return aSVGTransform->SetTranslate(aSMILTransform.mParams[0],
aSMILTransform.mParams[1]);
break;
case nsSVGSMILTransform::TRANSFORM_SCALE:
rv = aSVGTransform->SetScale(aSMILTransform.mParams[0],
return aSVGTransform->SetScale(aSMILTransform.mParams[0],
aSMILTransform.mParams[1]);
break;
case nsSVGSMILTransform::TRANSFORM_ROTATE:
rv = aSVGTransform->SetRotate(aSMILTransform.mParams[0],
return aSVGTransform->SetRotate(aSMILTransform.mParams[0],
aSMILTransform.mParams[1],
aSMILTransform.mParams[2]);
break;
case nsSVGSMILTransform::TRANSFORM_SKEWX:
rv = aSVGTransform->SetSkewX(aSMILTransform.mParams[0]);
break;
return aSVGTransform->SetSkewX(aSMILTransform.mParams[0]);
case nsSVGSMILTransform::TRANSFORM_SKEWY:
rv = aSVGTransform->SetSkewY(aSMILTransform.mParams[0]);
break;
return aSVGTransform->SetSkewY(aSMILTransform.mParams[0]);
case nsSVGSMILTransform::TRANSFORM_MATRIX:
{
nsCOMPtr<nsIDOMSVGMatrix> svgMatrix;
rv = NS_NewSVGMatrix(getter_AddRefs(svgMatrix),
nsresult rv =
NS_NewSVGMatrix(getter_AddRefs(svgMatrix),
aSMILTransform.mParams[0],
aSMILTransform.mParams[1],
aSMILTransform.mParams[2],
@ -437,11 +412,13 @@ nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue(
aSMILTransform.mParams[4],
aSMILTransform.mParams[5]);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(svgMatrix,NS_ERROR_FAILURE);
rv = aSVGTransform->SetMatrix(svgMatrix);
NS_ABORT_IF_FALSE(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:
nsSVGTransformSMILAttr(nsSVGAnimatedTransformList* aTransform,
nsSVGElement* aSVGElement)
: mVal(aTransform),
mSVGElement(aSVGElement) {}
: mVal(aTransform) {}
// nsISMILAttr methods
virtual nsISMILType* GetSMILType() const;
virtual nsresult ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* aSrcElement,
nsSMILValue& aValue) const;
@ -67,30 +65,24 @@ public:
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
protected:
nsresult ParseValue(const nsAString& aSpec,
static void ParseValue(const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult) const;
PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars,
PRInt32 aNVars) const;
PRBool IsSpace(const char c) const;
void SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd) const;
nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform,
nsSMILValue& aValue) const;
nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList,
nsSMILValue& aResult);
static PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars,
PRInt32 aNVars);
static nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform,
nsSMILValue& aValue);
static nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList,
const nsSMILValue& aValue);
nsresult GetSVGTransformFromSMILValue(
static nsresult GetSVGTransformFromSMILValue(
const nsSVGSMILTransform& aSMILTransform,
nsIDOMSVGTransform* aSVGTransform) const;
already_AddRefed<nsIDOMSVGTransform> GetSVGTransformFromSMILValue(
const nsSMILValue& aValue) const;
nsIDOMSVGTransform* aSVGTransform);
private:
// Raw pointers are OK here because this nsSVGTransformSMILAttr is both
// created & destroyed during a SMIL sample-step, during which time the DOM
// isn't modified.
nsSVGAnimatedTransformList* mVal;
nsSVGElement* mSVGElement;
};
#endif // NS_SVGTRANSFORMSMILATTR_H_

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

@ -42,28 +42,20 @@
/*static*/ nsSVGTransformSMILType nsSVGTransformSMILType::sSingleton;
typedef nsTArray<nsSVGSMILTransform> TransformArray;
//----------------------------------------------------------------------
// nsISMILType implementation
nsresult
nsSVGTransformSMILType::Init(nsSMILValue &aValue) const
{
NS_PRECONDITION(aValue.mType == this || aValue.IsNull(),
"Unexpected value type");
NS_ASSERTION(aValue.mType != this || aValue.mU.mPtr,
"Invalid nsSMILValue of SVG transform type: NULL data member");
NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");
if (aValue.mType != this || !aValue.mU.mPtr) {
// Different type, or no data member: allocate memory and set type
TransformArray* transforms = new TransformArray(1);
NS_ENSURE_TRUE(transforms, NS_ERROR_OUT_OF_MEMORY);
aValue.mU.mPtr = transforms;
aValue.mType = this;
} else {
// Same type, just set clear
TransformArray* transforms = static_cast<TransformArray*>(aValue.mU.mPtr);
transforms->Clear();
}
return NS_OK;
}
@ -313,10 +305,11 @@ nsSVGTransformSMILType::Interpolate(const nsSMILValue& aStartVal,
//----------------------------------------------------------------------
// Transform array accessors
// static
PRUint32
nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue) const
nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue)
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value");
NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
const TransformArray& transforms =
*static_cast<const TransformArray*>(aValue.mU.mPtr);
@ -324,11 +317,12 @@ nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue) const
return transforms.Length();
}
// static
const nsSVGSMILTransform*
nsSVGTransformSMILType::GetTransformAt(PRUint32 aIndex,
const nsSMILValue& aValue) const
const nsSMILValue& aValue)
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value");
NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
const TransformArray& transforms =
*static_cast<const TransformArray*>(aValue.mU.mPtr);
@ -341,16 +335,14 @@ nsSVGTransformSMILType::GetTransformAt(PRUint32 aIndex,
return &transforms[aIndex];
}
// static
nsresult
nsSVGTransformSMILType::AppendTransform(const nsSVGSMILTransform& aTransform,
nsSMILValue& aValue) const
nsSMILValue& aValue)
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value");
NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr);
nsSVGSMILTransform* transform = transforms.AppendElement(aTransform);
NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
return transforms.AppendElement(aTransform) ?
NS_OK : NS_ERROR_OUT_OF_MEMORY;
}

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

@ -106,7 +106,12 @@ class nsSMILValue;
class nsSVGTransformSMILType : public nsISMILType
{
public:
// nsISMILType
// Singleton for nsSMILValue objects to hold onto.
static nsSVGTransformSMILType sSingleton;
protected:
// nsISMILType Methods
// -------------------
virtual nsresult Init(nsSMILValue& aValue) const;
virtual void Destroy(nsSMILValue& aValue) const;
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
@ -122,20 +127,22 @@ public:
const nsSMILValue& aEndVal,
double aUnitDistance,
nsSMILValue& aResult) const;
public:
// Transform array accessors
PRUint32 GetNumTransforms(const nsSMILValue& aValue) const;
const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex,
const nsSMILValue& aValue) const;
nsresult AppendTransform(const nsSVGSMILTransform& aTransform,
nsSMILValue& aValue) const;
// -------------------------
static PRUint32 GetNumTransforms(const nsSMILValue& aValue);
static const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex,
const nsSMILValue& aValue);
static nsresult AppendTransform(const nsSVGSMILTransform& aTransform,
nsSMILValue& aValue);
static nsSVGTransformSMILType sSingleton;
protected:
typedef nsTArray<nsSVGSMILTransform> TransformArray;
private:
// Private constructor & destructor: prevent instances beyond my singleton,
// and prevent others from deleting my singleton.
nsSVGTransformSMILType() {}
~nsSVGTransformSMILType() {}
};
#endif // NS_SVGTRANSFORMSMILTYPE_H_

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

@ -52,6 +52,7 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const debug = false;
var expectedConsoleMessages = [];
var expectLoggedMessages = null;
try {
const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].
@ -88,6 +89,9 @@ function test_template()
if (needsOpen)
root.open = true;
if (expectLoggedMessages)
expectLoggedMessages();
checkResults(root, 0);
if (changes.length) {

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

@ -7,7 +7,7 @@
-->
<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">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
@ -37,7 +37,7 @@ var expectedOutput =
Components.classes["@mozilla.org/consoleservice;1"].
getService(Components.interfaces.nsIConsoleService).reset();
function expectLoggedMessages()
expectLoggedMessages = function()
{
// check log to ensure that two rows have been added
var initialNumber = Number(document.getElementById("root").firstChild.nextSibling.id.substring(3));

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

@ -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-2.html
load 436900-1.html
load 500328-1.html

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

@ -109,6 +109,7 @@
#include "nsIURIClassifier.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsCPrefetchService.h"
#include "nsJSON.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@ -655,6 +656,8 @@ DispatchPings(nsIContent *content, nsIURI *referrer)
ForEachPing(content, SendPing, &info);
}
static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
//*****************************************************************************
//*** nsDocShell: Object Management
//*****************************************************************************
@ -863,6 +866,14 @@ NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
return *aSink ? NS_OK : NS_NOINTERFACE;
}
else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
NS_SUCCEEDED(EnsureContentViewer())) {
nsCOMPtr<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))) {
*aSink = nsnull;
@ -1196,7 +1207,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
// The parent was loaded normally. In this case, this *brand new* child really shouldn't
// have a SHEntry. If it does, it could be because the parent is replacing an
// existing frame with a new frame, in the onLoadHandler. We don't want this
// url to get into session history. Clear off shEntry, and set laod type to
// url to get into session history. Clear off shEntry, and set load type to
// LOAD_BYPASS_HISTORY.
PRBool inOnLoadHandler=PR_FALSE;
parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
@ -3226,11 +3237,11 @@ nsDocShell::GetChildSHEntry(PRInt32 aChildOffset, nsISHEntry ** aResult)
NS_IMETHODIMP
nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
PRInt32 aChildOffset)
PRInt32 aChildOffset, PRUint32 loadType)
{
nsresult rv;
if (mLSHE) {
if (mLSHE && loadType != LOAD_PUSHSTATE) {
/* You get here if you are currently building a
* hierarchy ie.,you just visited a frameset page
*/
@ -3285,7 +3296,8 @@ nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
nsCOMPtr<nsIDocShellHistory> parent =
do_QueryInterface(GetAsSupports(mParent), &rv);
if (parent) {
rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset);
rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
loadType);
}
}
return rv;
@ -3313,7 +3325,7 @@ nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, PRInt32 aChildOffset)
nsCOMPtr<nsIDocShellHistory> parent =
do_QueryInterface(GetAsSupports(mParent), &rv);
if (parent) {
rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset);
rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType);
}
@ -3457,7 +3469,6 @@ NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex)
}
NS_IMETHODIMP
nsDocShell::LoadURI(const PRUnichar * aURI,
PRUint32 aLoadFlags,
@ -3846,6 +3857,13 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
mFailedURI = aURI;
mFailedLoadType = mLoadType;
if (mLSHE) {
// If we don't give mLSHE a new doc identifier here, when we go back or
// forward to another SHEntry with the same doc identifier, the error
// page will persist.
mLSHE->SetUniqueDocIdentifier();
}
nsCAutoString url;
nsCAutoString charset;
if (aURI)
@ -5714,13 +5732,13 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
// We're done with the URI classifier for this channel
mClassifier = nsnull;
//
// Notify the ContentViewer that the Document has finished loading...
//
// This will cause any OnLoad(...) handlers to fire, if it is a HTML
// document...
//
// Notify the ContentViewer that the Document has finished loading. This
// will cause any OnLoad(...) and PopState(...) handlers to fire.
if (!mEODForCurrentDocument && mContentViewer) {
// Set the pending state object which will be returned to the page in
// the popstate event.
SetDocPendingStateObj(mLSHE);
mIsExecutingOnLoadHandler = PR_TRUE;
mContentViewer->LoadComplete(aStatus);
mIsExecutingOnLoadHandler = PR_FALSE;
@ -7368,6 +7386,26 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
return NS_OK;
}
nsresult
nsDocShell::SetDocPendingStateObj(nsISHEntry *shEntry)
{
nsresult rv;
nsCOMPtr<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
nsDocShell::CheckLoadingPermissions()
@ -7845,19 +7883,42 @@ nsDocShell::InternalLoad(nsIURI * aURI,
#endif
}
if ((aLoadType == LOAD_NORMAL ||
if (aLoadType == LOAD_NORMAL ||
aLoadType == LOAD_STOP_CONTENT ||
LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
aLoadType == LOAD_HISTORY ||
aLoadType == LOAD_LINK) && allowScroll) {
aLoadType == LOAD_LINK) {
PRBool wasAnchor = PR_FALSE;
PRBool doHashchange = PR_FALSE;
nscoord cx, cy;
NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx, &cy,
&doHashchange),
NS_ERROR_FAILURE);
if (wasAnchor) {
if (allowScroll) {
NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx,
&cy, &doHashchange),
NS_ERROR_FAILURE);
}
// If this is a history load, aSHEntry will have document identifier X
// if it was created as a result of a History.pushState() from a
// SHEntry with doc ident X, or if it was created by changing the hash
// of the URI corresponding to a SHEntry with doc ident X.
PRBool sameDocIdent = PR_FALSE;
if (mOSHE && aSHEntry) {
PRUint64 ourDocIdent, otherDocIdent;
mOSHE->GetDocIdentifier(&ourDocIdent);
aSHEntry->GetDocIdentifier(&otherDocIdent);
sameDocIdent = (ourDocIdent == otherDocIdent);
}
// Do a short-circuited load if the new URI differs from the current
// URI only in the hash, or if the two entries belong to the same
// document and don't point to the same object.
//
// (If we didn't check that the SHEntries are different objects,
// history.go(0) would short-circuit instead of triggering a true
// load, and we wouldn't dispatch an onload event to the page.)
if (wasAnchor || (sameDocIdent && (mOSHE != aSHEntry))) {
mLoadType = aLoadType;
mURIResultedInDocument = PR_TRUE;
@ -7877,6 +7938,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
mOSHE->GetOwner(getter_AddRefs(owner));
}
OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE);
nsCOMPtr<nsIInputStream> postData;
PRUint32 pageIdent = PR_UINT32_MAX;
nsCOMPtr<nsISupports> cacheKey;
@ -7895,6 +7957,17 @@ nsDocShell::InternalLoad(nsIURI * aURI,
mOSHE->GetPageIdentifier(&pageIdent);
mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
}
if (mLSHE && wasAnchor) {
// If it's an anchor load, set mLSHE's doc identifier to
// mOSHE's doc identifier -- These are the same documents,
// as far as HTML5 is concerned.
PRUint64 docIdent;
rv = mOSHE->GetDocIdentifier(&docIdent);
if (NS_SUCCEEDED(rv)) {
mLSHE->SetDocIdentifier(docIdent);
}
}
}
/* Assign mOSHE to mLSHE. This will either be a new entry created
@ -7949,11 +8022,26 @@ nsDocShell::InternalLoad(nsIURI * aURI,
shEntry->SetTitle(mTitle);
}
if (doHashchange) {
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(mScriptGlobal);
if (sameDocIdent) {
// Set the doc's URI according to the new history entry's URI
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();
}
@ -8837,6 +8925,14 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
if (uploadChannel) {
uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
}
// If the response status indicates an error, unlink this session
// history entry from any entries sharing its doc ident.
PRUint32 responseStatus;
nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
mLSHE->SetUniqueDocIdentifier();
}
}
}
/* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in
@ -8895,7 +8991,6 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
SetHistoryEntry(&mLSHE, mOSHE);
}
/* If the user pressed shift-reload, cache will create a new cache key
* for the page. Save the new cacheKey in Session History.
* see bug 90098
@ -8986,6 +9081,282 @@ nsDocShell::SetReferrerURI(nsIURI * aURI)
//*****************************************************************************
// nsDocShell: Session History
//*****************************************************************************
nsresult
nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult)
{
nsresult rv;
aResult.Truncate();
// First, try to extract a jsval from the variant |aData|. This works only
// if the variant implements GetAsJSVal.
jsval jsData;
rv = aData->GetAsJSVal(&jsData);
NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
// Now get the JSContext associated with the current document.
// First get the current document.
nsCOMPtr<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
nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
{
@ -9428,7 +9799,6 @@ nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry,
return rv;
}
void
nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
{
@ -9679,9 +10049,6 @@ nsresult
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIChannel * aChannel)
{
if (mItemType != typeContent || !mGlobalHistory)
return NS_OK;
// If this is a POST request, we do not want to include this in global
// history, so return early.
nsCOMPtr<nsIHttpChannel> hchan(do_QueryInterface(aChannel));
@ -9692,16 +10059,26 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
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;
nsresult rv = mGlobalHistory->IsVisited(aURI, &visited);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIURI> referrer;
if (aChannel)
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), referrer);
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), aReferrer);
if (NS_FAILED(rv))
return rv;
@ -9714,6 +10091,7 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
}
return NS_OK;
}
//*****************************************************************************

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

@ -364,6 +364,10 @@ protected:
PRUint32 aLoadType, nscoord *cx, nscoord *cy,
PRBool * aDoHashchange);
// Tries to stringify a given variant by converting it to JSON. This only
// works if the variant is backed by a JSVal.
nsresult StringifyJSValVariant(nsIVariant *aData, nsAString &aResult);
// Returns PR_TRUE if would have called FireOnLocationChange,
// but did not because aFireOnLocationChange was false on entry.
// In this case it is the caller's responsibility to ensure
@ -465,8 +469,11 @@ protected:
PRUint32 aStateFlags);
// Global History
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIChannel * aChannel);
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIURI * aReferrer);
// Helper Routines
nsresult ConfirmRepost(PRBool * aRepost);
@ -515,6 +522,11 @@ protected:
nsIChannel * aChannel,
nsresult aResult);
// Sets the current document's pending state object to the given SHEntry's
// state object. The pending state object is eventually given to the page
// in the PopState event.
nsresult SetDocPendingStateObj(nsISHEntry *shEntry);
nsresult CheckLoadingPermissions();
// Security checks to prevent frameset spoofing. See comments at

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

@ -92,6 +92,7 @@ enum LoadType {
LOAD_BYPASS_HISTORY = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_BYPASS_HISTORY),
LOAD_STOP_CONTENT = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT),
LOAD_STOP_CONTENT_AND_REPLACE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL, nsIWebNavigation::LOAD_FLAGS_STOP_CONTENT | nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY),
LOAD_PUSHSTATE = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_PUSHSTATE, nsIWebNavigation::LOAD_FLAGS_NONE),
/**
* Load type for an error page. These loads are never triggered by users of
* Docshell. Instead, Docshell triggers the load itself when a
@ -122,6 +123,7 @@ static inline PRBool IsValidLoadType(PRUint32 aLoadType)
case LOAD_BYPASS_HISTORY:
case LOAD_STOP_CONTENT:
case LOAD_STOP_CONTENT_AND_REPLACE:
case LOAD_PUSHSTATE:
case LOAD_ERROR_PAGE:
return PR_TRUE;
}

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

@ -69,8 +69,9 @@ interface nsISecureBrowserUI;
interface nsIDOMStorage;
interface nsIPrincipal;
interface nsIWebBrowserPrint;
interface nsIVariant;
[scriptable, uuid(c95eaff1-14e6-4db1-a806-46be97d5a9b6)]
[scriptable, uuid(3adde256-05a9-43a7-a190-f8fe75eecfd6)]
interface nsIDocShell : nsISupports
{
/**
@ -169,6 +170,13 @@ interface nsIDocShell : nsISupports
out nsIDocShell aDocShell,
out nsIRequest aRequest);
/**
* Do either a history.pushState() or history.replaceState() operation,
* depending on the value of aReplace.
*/
void addState(in nsIVariant aData, in DOMString aTitle,
in DOMString aURL, in boolean aReplace);
/**
* Creates a DocShellLoadInfo object that you can manipulate and then pass
* to loadURI.
@ -342,6 +350,7 @@ interface nsIDocShell : nsISupports
const unsigned long LOAD_CMD_NORMAL = 0x1; // Normal load
const unsigned long LOAD_CMD_RELOAD = 0x2; // Reload
const unsigned long LOAD_CMD_HISTORY = 0x4; // Load from history
const unsigned long LOAD_CMD_PUSHSTATE = 0x8; // History.pushState()
readonly attribute unsigned long busyFlags;

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

@ -39,7 +39,7 @@
#include "nsISupports.idl"
interface nsISHEntry;
[scriptable, uuid(89caa9f0-8b1c-47fb-b0d3-f0aef0bff749)]
[scriptable, uuid(a89b80a8-3c44-4a25-9d2c-2fb42358b46e)]
interface nsIDocShellHistory : nsISupports
{
/**
@ -48,11 +48,12 @@ interface nsIDocShellHistory : nsISupports
nsISHEntry getChildSHEntry(in long aChildOffset);
/**
* Add a Child SHEntry for a frameset page
* Add a Child SHEntry for a frameset page, given the child's loadtype.
*/
void addChildSHEntry(in nsISHEntry aCloneReference,
in nsISHEntry aHistoryEntry,
in long aChildOffset);
in long aChildOffset,
in unsigned long aLoadType);
/*
* Whether this docshell should save entries in global history.

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

@ -58,7 +58,7 @@ class nsDocShellEditorData;
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
[scriptable, uuid(09fecea6-5453-43ba-bf91-3ff32618f037)]
[scriptable, uuid(62b0603f-57ca-439e-a0fb-6f6978500755)]
interface nsISHEntry : nsIHistoryEntry
{
/** URI for the document */
@ -149,6 +149,21 @@ interface nsISHEntry : nsIHistoryEntry
*/
attribute unsigned long pageIdentifier;
/**
* docIdentifier is an integer that should be the same for two entries
* attached to the same docshell if and only if the two entries are entries
* for the same document. In practice, two entries A and B will have the
* same docIdentifier if they have the same pageIdentifier or if B was
* created by A calling history.pushState().
*/
attribute unsigned long long docIdentifier;
/**
* Changes this entry's doc identifier to a new value which is unique
* among those of all other entries.
*/
void setUniqueDocIdentifier();
/** attribute to set and get the cache key for the entry */
attribute nsISupports cacheKey;
@ -192,6 +207,12 @@ interface nsISHEntry : nsIHistoryEntry
*/
attribute nsISupports owner;
/**
* Get/set data associated with this history state via a pushState() call,
* encoded as JSON.
**/
attribute AString stateData;
/**
* Gets the owning pointer to the editor data assosicated with
* this shistory entry. This forgets its pointer, so free it when

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

@ -75,6 +75,7 @@ protected:
static HistoryTracker *gHistoryTracker = nsnull;
static PRUint32 gEntryID = 0;
static PRUint64 gEntryDocIdentifier = 0;
nsresult nsSHEntry::Startup()
{
@ -104,6 +105,7 @@ nsSHEntry::nsSHEntry()
: mLoadType(0)
, mID(gEntryID++)
, mPageIdentifier(mID)
, mDocIdentifier(gEntryDocIdentifier++)
, mScrollPositionX(0)
, mScrollPositionY(0)
, mIsFrameNavigation(PR_FALSE)
@ -125,6 +127,7 @@ nsSHEntry::nsSHEntry(const nsSHEntry &other)
, mLoadType(0) // XXX why not copy?
, mID(other.mID)
, mPageIdentifier(other.mPageIdentifier)
, mDocIdentifier(other.mDocIdentifier)
, mScrollPositionX(0) // XXX why not copy?
, mScrollPositionY(0) // XXX why not copy?
, mIsFrameNavigation(other.mIsFrameNavigation)
@ -393,6 +396,30 @@ NS_IMETHODIMP nsSHEntry::SetPageIdentifier(PRUint32 aPageIdentifier)
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::GetDocIdentifier(PRUint64 * aResult)
{
*aResult = mDocIdentifier;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::SetDocIdentifier(PRUint64 aDocIdentifier)
{
// This ensures that after a session restore, gEntryDocIdentifier is greater
// than all SHEntries' docIdentifiers, which ensures that we'll never repeat
// a doc identifier.
if (aDocIdentifier >= gEntryDocIdentifier)
gEntryDocIdentifier = aDocIdentifier + 1;
mDocIdentifier = aDocIdentifier;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::SetUniqueDocIdentifier()
{
mDocIdentifier = gEntryDocIdentifier++;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::GetIsSubFrame(PRBool * aFlag)
{
*aFlag = mIsFrameNavigation;
@ -866,3 +893,17 @@ nsSHEntry::HasDetachedEditor()
return mEditorData != nsnull;
}
NS_IMETHODIMP
nsSHEntry::GetStateData(nsAString &aStateData)
{
aStateData.Assign(mStateData);
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SetStateData(const nsAString &aDataStr)
{
mStateData.Assign(aDataStr);
return NS_OK;
}

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

@ -99,6 +99,7 @@ private:
PRUint32 mLoadType;
PRUint32 mID;
PRUint32 mPageIdentifier;
PRInt64 mDocIdentifier;
PRInt32 mScrollPositionX;
PRInt32 mScrollPositionY;
PRPackedBool mIsFrameNavigation;
@ -115,6 +116,7 @@ private:
nsCOMPtr<nsISupports> mOwner;
nsExpirationState mExpirationState;
nsAutoPtr<nsDocShellEditorData> mEditorData;
nsString mStateData;
};
#endif /* nsSHEntry_h */

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

@ -492,9 +492,10 @@ nsSHistory::PrintHistory()
uri->GetSpec(url);
printf("**** SH Transaction #%d, Entry = %x\n", index, entry.get());
printf("\t\t URL = %s\n", url);
printf("\t\t URL = %s\n", url.get());
printf("\t\t Title = %s\n", NS_LossyConvertUTF16toASCII(title).get());
printf("\t\t layout History Data = %x\n", layoutHistoryState);
printf("\t\t layout History Data = %x\n", layoutHistoryState.get());
#endif
nsCOMPtr<nsISHTransaction> next;
@ -1223,7 +1224,6 @@ nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd)
docShell = mRootDocShell;
}
if (!docShell) {
// we did not successfully go to the proper index.
// return error.
@ -1235,8 +1235,6 @@ nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd)
return InitiateLoad(nextEntry, docShell, aLoadType);
}
nsresult
nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound)
{

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

@ -82,6 +82,7 @@
#include "nsIDOMNSEvent.h"
#include "nsIDOMKeyEvent.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMPopStateEvent.h"
#include "nsContentUtils.h"
#include "nsDOMWindowUtils.h"
@ -1330,13 +1331,15 @@ static nsDOMClassInfoData sClassInfoData[] = {
NS_DEFINE_CLASSINFO_DATA(ScrollAreaEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(PopStateEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(TransitionEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
};
// Objects that shuld be constructable through |new Name();|
// Objects that should be constructable through |new Name();|
struct nsContractIDMapData
{
PRInt32 mDOMClassInfoID;
@ -1420,6 +1423,7 @@ jsval nsDOMClassInfo::sOnreset_id = JSVAL_VOID;
jsval nsDOMClassInfo::sOnchange_id = JSVAL_VOID;
jsval nsDOMClassInfo::sOnselect_id = JSVAL_VOID;
jsval nsDOMClassInfo::sOnload_id = JSVAL_VOID;
jsval nsDOMClassInfo::sOnpopstate_id = JSVAL_VOID;
jsval nsDOMClassInfo::sOnbeforeunload_id = JSVAL_VOID;
jsval nsDOMClassInfo::sOnunload_id = JSVAL_VOID;
jsval nsDOMClassInfo::sOnhashchange_id = JSVAL_VOID;
@ -1614,6 +1618,7 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
SET_JSVAL_TO_STRING(sOnchange_id, cx, "onchange");
SET_JSVAL_TO_STRING(sOnselect_id, cx, "onselect");
SET_JSVAL_TO_STRING(sOnload_id, cx, "onload");
SET_JSVAL_TO_STRING(sOnpopstate_id, cx, "onpopstate");
SET_JSVAL_TO_STRING(sOnbeforeunload_id, cx, "onbeforeunload");
SET_JSVAL_TO_STRING(sOnunload_id, cx, "onunload");
SET_JSVAL_TO_STRING(sOnhashchange_id, cx, "onhashchange");
@ -2232,6 +2237,11 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(PopStateEvent, nsIDOMPopStateEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMPopStateEvent)
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLDocument)
@ -7327,7 +7337,8 @@ nsEventReceiverSH::ReallyIsEventName(jsval id, jschar aFirstChar)
return (id == sOnpaint_id ||
id == sOnpageshow_id ||
id == sOnpagehide_id ||
id == sOnpaste_id);
id == sOnpaste_id ||
id == sOnpopstate_id);
case 'k' :
return (id == sOnkeydown_id ||
id == sOnkeypress_id ||

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

@ -327,6 +327,7 @@ protected:
static jsval sOnchange_id;
static jsval sOnselect_id;
static jsval sOnload_id;
static jsval sOnpopstate_id;
static jsval sOnbeforeunload_id;
static jsval sOnunload_id;
static jsval sOnhashchange_id;

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

@ -473,6 +473,7 @@ enum nsDOMClassInfoID {
eDOMClassInfo_PaintRequestList_id,
eDOMClassInfo_ScrollAreaEvent_id,
eDOMClassInfo_PopStateEvent_id,
eDOMClassInfo_EventListenerInfo_id,

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

@ -79,6 +79,7 @@
#include "nsCycleCollector.h"
#include "nsCCUncollectableMarker.h"
#include "nsDOMThreadService.h"
#include "nsAutoJSValHolder.h"
// Interfaces Needed
#include "nsIFrame.h"
@ -112,6 +113,7 @@
#include "nsIDOMKeyEvent.h"
#include "nsIDOMMessageEvent.h"
#include "nsIDOMPopupBlockedEvent.h"
#include "nsIDOMPopStateEvent.h"
#include "nsIDOMOfflineResourceList.h"
#include "nsIDOMGeoGeolocation.h"
#include "nsPIDOMStorage.h"
@ -169,6 +171,7 @@
#include "nsIXULAppInfo.h"
#include "nsNetUtil.h"
#include "nsFocusManager.h"
#include "nsIJSON.h"
#ifdef MOZ_XUL
#include "nsXULPopupManager.h"
#include "nsIDOMXULControlElement.h"
@ -361,6 +364,8 @@ static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
static const char kCryptoContractID[] = NS_CRYPTO_CONTRACTID;
static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
static const char sPopStatePrefStr[] = "browser.history.allowPopState";
static PRBool
IsAboutBlank(nsIURI* aURI)
{
@ -655,9 +660,9 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
mTimeoutPublicIdCounter(1),
mTimeoutFiringDepth(0),
mJSObject(nsnull),
mPendingStorageEventsObsolete(nsnull),
mTimeoutsSuspendDepth(0),
mFocusMethod(0),
mPendingStorageEventsObsolete(nsnull)
mFocusMethod(0)
#ifdef DEBUG
, mSetOpenerWindowCalled(PR_FALSE)
#endif
@ -6987,7 +6992,119 @@ nsGlobalWindow::DispatchSyncHashchange()
PR_FALSE, PR_FALSE);
}
// Find an nsCanvasFrame under aFrame. Only search the principal
nsresult
nsGlobalWindow::DispatchSyncPopState()
{
FORWARD_TO_INNER(DispatchSyncPopState, (), NS_OK);
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"Must be safe to run script here.");
// Check that PopState hasn't been pref'ed off.
if (!nsContentUtils::GetBoolPref(sPopStatePrefStr, PR_FALSE))
return NS_OK;
nsresult rv = NS_OK;
// Bail if the window is frozen.
if (IsFrozen()) {
return NS_OK;
}
// Bail if there's no document or the document's readystate isn't "complete".
if (!mDoc) {
return NS_OK;
}
nsIDocument::ReadyState readyState = mDoc->GetReadyStateEnum();
if (readyState != nsIDocument::READYSTATE_COMPLETE) {
return NS_OK;
}
// Get the document's pending state object -- it contains the data we're
// going to send along with the popstate event. The object is serialized as
// JSON.
nsAString& stateObjJSON = mDoc->GetPendingStateObject();
nsCOMPtr<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.
static nsCanvasFrame* FindCanvasFrame(nsIFrame* aFrame)
{

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

@ -448,6 +448,8 @@ public:
virtual void SetReadyForFocus();
virtual void PageHidden();
virtual nsresult DispatchSyncHashchange();
virtual nsresult DispatchSyncPopState();
virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin);
static PRBool DOMWindowDumpEnabled();

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

@ -57,6 +57,13 @@
#include "nsReadableUtils.h"
#include "nsDOMClassInfo.h"
#include "nsContentUtils.h"
#include "nsIDOMNSDocument.h"
#include "nsISHistoryInternal.h"
static const char* sAllowPushStatePrefStr =
"browser.history.allowPushState";
static const char* sAllowReplaceStatePrefStr =
"browser.history.allowReplaceState";
//
// History class implementation
@ -272,6 +279,47 @@ nsHistory::Go(PRInt32 aDelta)
return NS_OK;
}
NS_IMETHODIMP
nsHistory::PushState(nsIVariant *aData, const nsAString& aTitle,
const nsAString& aURL)
{
// Check that PushState hasn't been pref'ed off.
if (!nsContentUtils::GetBoolPref(sAllowPushStatePrefStr, PR_FALSE))
return NS_OK;
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
// AddState might run scripts, so we need to hold a strong reference to the
// docShell here to keep it from going away.
nsCOMPtr<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
nsHistory::Item(PRUint32 aIndex, nsAString& aReturn)
{

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

@ -194,7 +194,6 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISupports> owner;
nsCOMPtr<nsIURI> sourceURI;
if (cx) {
// No cx means that there's no JS running, or at least no JS that
@ -222,7 +221,6 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
!principal)
return NS_ERROR_FAILURE;
owner = do_QueryInterface(principal);
principal->GetURI(getter_AddRefs(sourceURI));
}
// Create load info
@ -232,10 +230,12 @@ nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
loadInfo->SetOwner(owner);
// now set the referrer on the loadinfo
if (sourceURI) {
// Now set the referrer on the loadinfo. We need to do this in order to get
// the correct referrer URI from a document which was pushStated.
nsCOMPtr<nsIURI> sourceURI;
result = GetURI(getter_AddRefs(sourceURI));
if (NS_SUCCEEDED(result))
loadInfo->SetReferrer(sourceURI);
}
loadInfo.swap(*aLoadInfo);

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

@ -461,6 +461,10 @@ public:
*/
virtual nsresult DispatchSyncHashchange() = 0;
/**
* Instructs this window to synchronously dispatch a popState event.
*/
virtual nsresult DispatchSyncPopState() = 0;
/**
* Tell this window that there is an observer for orientation changes

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

@ -39,7 +39,9 @@
#include "domstubs.idl"
[scriptable, uuid(896d1d20-b4c4-11d2-bd93-00805f8ae3f4)]
interface nsIVariant;
[scriptable, uuid(208f2af7-9f2e-497c-8a53-9e7803280898)]
interface nsIDOMHistory : nsISupports
{
readonly attribute long length;
@ -52,4 +54,10 @@ interface nsIDOMHistory : nsISupports
void go([optional] in long aDelta);
DOMString item(in unsigned long index);
void pushState(in nsIVariant aData,
in DOMString aTitle,
[optional] in DOMString aURL);
void replaceState(in nsIVariant aData,
in DOMString aTitle,
[optional] in DOMString aURL);
};

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

@ -83,6 +83,7 @@ XPIDLSRCS = \
nsIDOMOrientationEvent.idl \
nsIDOMScrollAreaEvent.idl \
nsIDOMTransitionEvent.idl \
nsIDOMPopStateEvent.idl \
$(NULL)
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 nsIScriptGlobalObject;
%{ C++
#include "jspubtd.h"
%}
native JSVal(jsval);
[ptr] native JSValPtr(jsval);
[ptr] native JSContext(JSContext);
/**
* Encode and decode JSON text.
*/
[scriptable, uuid(45464c36-efde-4cb5-8e00-07480533ff35)]
[scriptable, uuid(6fcf09ee-87d0-42ec-a72a-8d60114e974f)]
interface nsIJSON : nsISupports
{
AString encode(/* in JSObject value */);
@ -59,4 +67,9 @@ interface nsIJSON : nsISupports
void /* JSObject */ decodeFromStream(in nsIInputStream stream,
in long contentLength);
[noscript] AString encodeFromJSVal(in JSValPtr value, in JSContext cx);
// Make sure you GCroot the result of this function before using it.
[noscript] JSVal decodeToJSVal(in AString str, in JSContext cx);
};

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

@ -12,6 +12,5 @@ version_label=Version:
mimetype_label=MIME Type
description_label=Description
suffixes_label=Suffixes
enabled_label=Enabled
yes_label=Yes
no_label=No

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

@ -235,6 +235,10 @@ PluginModuleChild::InitGraphics()
{
// FIXME/cjones: is this the place for this?
#if defined(MOZ_WIDGET_GTK2)
// Work around plugins that don't interact well with GDK
// client-side windows.
PR_SetEnv("GDK_NATIVE_WINDOWS=1");
gtk_init(0, 0);
// GtkPlug is a static class so will leak anyway but this ref makes sure.

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

@ -149,6 +149,8 @@ PluginModuleParent::WriteExtraDataForMinidump(nsIFile* dumpFile)
pluginFile.substr(filePos).c_str());
//TODO: add plugin name and version: bug 539841
// (as PluginName, PluginVersion)
WriteExtraDataEntry(stream, "PluginName", "");
WriteExtraDataEntry(stream, "PluginVersion", "");
stream->Close();
}

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

@ -51,6 +51,9 @@ CPPSRCS = \
nsJSON.cpp \
$(NULL)
EXPORTS = nsJSON.h \
$(NULL)
FORCE_STATIC_LIB = 1
LOCAL_INCLUDES = \

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

@ -195,6 +195,27 @@ WriteCallback(const jschar *buf, uint32 len, void *data)
return JS_TRUE;
}
NS_IMETHODIMP
nsJSON::EncodeFromJSVal(jsval *value, JSContext *cx, nsAString &result)
{
result.Truncate();
// Begin a new request
JSAutoRequest ar(cx);
nsJSONWriter writer;
JSBool ok = JS_Stringify(cx, value, NULL, JSVAL_NULL,
WriteCallback, &writer);
if (!ok) {
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED);
writer.FlushBuffer();
result.Assign(writer.mOutputString);
return NS_OK;
}
nsresult
nsJSON::EncodeInternal(nsJSONWriter *writer)
{
@ -382,6 +403,30 @@ nsJSON::DecodeFromStream(nsIInputStream *aStream, PRInt32 aContentLength)
return DecodeInternal(aStream, aContentLength, PR_TRUE);
}
NS_IMETHODIMP
nsJSON::DecodeToJSVal(const nsAString &str, JSContext *cx, jsval *result)
{
JSAutoRequest ar(cx);
JSONParser *parser = JS_BeginJSONParse(cx, result);
NS_ENSURE_TRUE(parser, NS_ERROR_UNEXPECTED);
JSBool ok = JS_ConsumeJSONText(cx, parser,
(jschar*)PromiseFlatString(str).get(),
(uint32)str.Length());
// Since we've called JS_BeginJSONParse, we have to call JS_FinishJSONParse,
// even if JS_ConsumeJSONText fails. But if either fails, we'll report an
// error.
ok = ok && JS_FinishJSONParse(cx, parser, JSVAL_NULL);
if (!ok) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
nsresult
nsJSON::DecodeInternal(nsIInputStream *aStream,
PRInt32 aContentLength,

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

@ -550,8 +550,8 @@ NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult)
nsDOMStorage::nsDOMStorage()
: mUseDB(PR_FALSE)
, mSessionOnly(PR_TRUE)
, mItemsCached(PR_FALSE)
, mStorageType(nsPIDOMStorage::Unknown)
, mItemsCached(PR_FALSE)
, mEventBroadcaster(nsnull)
{
mSecurityChecker = this;
@ -562,10 +562,10 @@ nsDOMStorage::nsDOMStorage()
nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
: mUseDB(PR_FALSE) // Any clone is not using the database
, mSessionOnly(PR_TRUE)
, mItemsCached(PR_FALSE)
, mDomain(aThat.mDomain)
, mSessionOnly(PR_TRUE)
, mStorageType(aThat.mStorageType)
, mItemsCached(PR_FALSE)
#ifdef MOZ_STORAGE
, mScopeDBKey(aThat.mScopeDBKey)
#endif

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

@ -77,6 +77,9 @@ _TEST_FILES = \
postMessage.jar \
postMessage.jar^headers^ \
test_bug477323.html \
test_bug500328.html \
file_bug500328_1.html \
file_bug500328_2.html \
$(NULL)
_CHROME_FILES = \

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

@ -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;
}
// set the default string, in case for API/conversion errors
CopyASCIItoUTF16(nsDependentCString(asctime(tmTime)), stringOut);
NS_ASSERTION(tmTime->tm_mon >= 0, "tm is not set correctly");
NS_ASSERTION(tmTime->tm_mday >= 1, "tm is not set correctly");
NS_ASSERTION(tmTime->tm_hour >= 0, "tm is not set correctly");

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

@ -57,7 +57,6 @@
native COMVARIANT(VARIANT);
[ptr] native COMVARIANTPtr(VARIANT);
native JSVal(jsval);
[ptr] native JSContextPtr(JSContext);
interface IDispatch;

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

@ -59,11 +59,12 @@
/***************************************************************************/
// NB: JSVal is declared in nsIVariant.idl
[ptr] native JSContextPtr(JSContext);
[ptr] native JSClassPtr(JSClass);
[ptr] native JSObjectPtr(JSObject);
[ptr] native JSValPtr(jsval);
native JSVal(jsval);
native JSEqualityOp(JSEqualityOp);
native JSID(jsid);
[ptr] native voidPtrPtr(void*);
@ -530,6 +531,12 @@ interface nsIXPConnect : nsISupports
in nsIIDRef aIID,
[iid_is(aIID),retval] out nsQIResult result);
/**
* Wraps the given JSVal in a nsIVariant and returns the new variant.
*/
nsIVariant
jSValToVariant(in JSContextPtr cx, in JSValPtr aJSVal);
/**
* This only succeeds if the JSObject is a nsIXPConnectWrappedNative.
* A new wrapper is *never* constructed.

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

@ -1358,14 +1358,6 @@ FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext,
return NS_OK;
}
/* [noscript] void checkConnect (in JSContextPtr aJSContext, in nsIURI aTargetURI, in string aClassName, in string aProperty); */
NS_IMETHODIMP
FullTrustSecMan::CheckConnect(JSContext * aJSContext, nsIURI *aTargetURI,
const char *aClassName, const char *aProperty)
{
return NS_OK;
}
/* [noscript] void checkLoadURIFromScript (in JSContextPtr cx, in nsIURI uri); */
NS_IMETHODIMP
FullTrustSecMan::CheckLoadURIFromScript(JSContext * cx, nsIURI *uri)

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

@ -1051,7 +1051,7 @@ InitWebGLTypes(JSContext *aJSContext, JSObject *aGlobalJSObj)
// Alias WebGLArrayBuffer -> ArrayBuffer
if(!JS_GetProperty(aJSContext, aGlobalJSObj, "ArrayBuffer", &v) ||
!JS_DefineProperty(aJSContext, aGlobalJSObj, "WebGLArrayBuffer", v,
NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE))
NULL, NULL, JSPROP_PERMANENT))
return PR_FALSE;
const int webglTypes[] = {
@ -1080,7 +1080,7 @@ InitWebGLTypes(JSContext *aJSContext, JSObject *aGlobalJSObj)
{
if(!JS_GetProperty(aJSContext, aGlobalJSObj, js::TypedArray::slowClasses[webglTypes[i]].name, &v) ||
!JS_DefineProperty(aJSContext, aGlobalJSObj, webglNames[i], v,
NULL, NULL, JSPROP_PERMANENT | JSPROP_ENUMERATE))
NULL, NULL, JSPROP_PERMANENT))
return PR_FALSE;
}
@ -1370,6 +1370,25 @@ nsXPConnect::WrapJS(JSContext * aJSContext,
return NS_OK;
}
NS_IMETHODIMP
nsXPConnect::JSValToVariant(JSContext *cx,
jsval *aJSVal,
nsIVariant ** aResult)
{
NS_PRECONDITION(aJSVal, "bad param");
NS_PRECONDITION(aResult, "bad param");
*aResult = nsnull;
XPCCallContext ccx(NATIVE_CALLER, cx);
if(!ccx.IsValid())
return NS_ERROR_FAILURE;
*aResult = XPCVariant::newVariant(ccx, *aJSVal);
NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
/* void wrapJSAggregatedToNative (in nsISupports aOuter, in JSContextPtr aJSContext, in JSObjectPtr aJSObj, in nsIIDRef aIID, [iid_is (aIID), retval] out nsQIResult result); */
NS_IMETHODIMP
nsXPConnect::WrapJSAggregatedToNative(nsISupports *aOuter,

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

@ -4198,6 +4198,10 @@ public:
static XPCVariant* newVariant(XPCCallContext& ccx, jsval aJSVal);
/**
* nsIVariant exposes a GetAsJSVal() method, which also returns mJSVal.
* But if you can, you should call this one, since it can be inlined.
*/
jsval GetJSVal() const {return mJSVal;}
XPCVariant(XPCCallContext& ccx, jsval aJSVal);

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

@ -390,6 +390,14 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx)
NS_SUCCEEDED(nsVariant::SetFromInterface(&mData, iid, wrapper));
}
NS_IMETHODIMP
XPCVariant::GetAsJSVal(jsval* result)
{
NS_PRECONDITION(result, "null result arg.");
*result = GetJSVal();
return NS_OK;
}
// static
JSBool
XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
@ -402,30 +410,29 @@ XPCVariant::VariantDataToJS(XPCLazyCallContext& lccx,
if (NS_FAILED(variant->GetDataType(&type)))
return JS_FALSE;
nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
if(xpcvariant)
{
jsval realVal = xpcvariant->GetJSVal();
if(JSVAL_IS_PRIMITIVE(realVal) ||
jsval realVal;
nsresult rv = variant->GetAsJSVal(&realVal);
if(NS_SUCCEEDED(rv) &&
(JSVAL_IS_PRIMITIVE(realVal) ||
type == nsIDataType::VTYPE_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
// an nsID),.
// So, just pass through the underlying data.
// It's not a JSObject (or it's a JSArray or a JSObject representing an
// nsID). Just pass through the underlying data.
*pJSVal = realVal;
return JS_TRUE;
}
if(xpcvariant->mReturnRawObject)
nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
if(xpcvariant && xpcvariant->mReturnRawObject)
{
NS_ASSERTION(type == nsIDataType::VTYPE_INTERFACE ||
type == nsIDataType::VTYPE_INTERFACE_IS,
"Weird variant");
*pJSVal = realVal;
return JS_TRUE;
}
// else, it's an object and we really need to double wrap it if we've
// already decided that its 'natural' type is as some sort of interface.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше