[JAEGER] Merge from tracemonkey.

This commit is contained in:
David Anderson 2010-07-19 20:49:26 -07:00
commit dd9c55abdd
809 changed files with 31983 additions and 17670 deletions

View File

@ -45,7 +45,7 @@
interface nsIAccessible; interface nsIAccessible;
interface nsIArray; interface nsIArray;
[scriptable, uuid(035c0c0e-41e3-4985-8ad9-d9f14cdc667a)] [scriptable, uuid(cb0bf7b9-117e-40e2-9e46-189c3d43ce4a)]
interface nsIAccessibleTable : nsISupports interface nsIAccessibleTable : nsISupports
{ {
/** /**
@ -104,6 +104,17 @@ interface nsIAccessibleTable : nsISupports
*/ */
long getRowIndexAt(in long cellIndex); long getRowIndexAt(in long cellIndex);
/**
* Translate the given cell index into the corresponding row and column
* indices.
*
* @param cellIndex [in] cell index to return row and column indices for
* @param rowIndex [out] row index at the given cell index
* @param columnIndex [out] column index at the given cell index
*/
void getRowAndColumnIndicesAt(in long cellIndex,
out long rowIndex, out long columnIndex);
/** /**
* Return the number of columns occupied by the accessible cell at * Return the number of columns occupied by the accessible cell at
* the specified row and column in the table. The result differs from 1 if * the specified row and column in the table. The result differs from 1 if

View File

@ -0,0 +1,169 @@
/* ***** 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
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
*
* 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 ***** */
#include "AccGroupInfo.h"
AccGroupInfo::AccGroupInfo(nsAccessible* aItem, PRUint32 aRole) :
mPosInSet(0), mSetSize(0), mParent(nsnull)
{
nsAccessible* parent = aItem->GetParent();
if (!parent)
return;
PRInt32 indexInParent = aItem->GetIndexInParent();
PRInt32 level = nsAccUtils::GetARIAOrDefaultLevel(aItem);
// Compute position in set.
mPosInSet = 1;
for (PRInt32 idx = indexInParent - 1; idx >=0 ; idx--) {
nsAccessible* sibling = parent->GetChildAt(idx);
PRUint32 siblingRole = nsAccUtils::Role(sibling);
// If the sibling is separator then the group is ended.
if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR)
break;
// If sibling is not visible and hasn't the same base role.
if (BaseRole(siblingRole) != aRole ||
nsAccUtils::State(sibling) & nsIAccessibleStates::STATE_INVISIBLE)
continue;
// Check if it's hierarchical flatten structure, i.e. if the sibling
// level is lesser than this one then group is ended, if the sibling level
// is greater than this one then the group is split by some child elements
// (group will be continued).
PRInt32 siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
if (siblingLevel < level) {
mParent = sibling;
break;
}
// Skip subset.
if (siblingLevel > level)
continue;
// If the previous item in the group has calculated group information then
// build group information for this item based on found one.
if (sibling->mGroupInfo) {
mPosInSet += sibling->mGroupInfo->mPosInSet;
mParent = sibling->mGroupInfo->mParent;
mSetSize = sibling->mGroupInfo->mSetSize;
return;
}
mPosInSet++;
}
// Compute set size.
mSetSize = mPosInSet;
PRInt32 siblingCount = parent->GetChildCount();
for (PRInt32 idx = indexInParent + 1; idx < siblingCount; idx++) {
nsAccessible* sibling = parent->GetChildAt(idx);
PRUint32 siblingRole = nsAccUtils::Role(sibling);
// If the sibling is separator then the group is ended.
if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR)
break;
// If sibling is visible and has the same base role
if (BaseRole(siblingRole) != aRole ||
nsAccUtils::State(sibling) & nsIAccessibleStates::STATE_INVISIBLE)
continue;
// and check if it's hierarchical flatten structure.
PRInt32 siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
if (siblingLevel < level)
break;
// Skip subset.
if (siblingLevel > level)
continue;
// If the next item in the group has calculated group information then
// build group information for this item based on found one.
if (sibling->mGroupInfo) {
mParent = sibling->mGroupInfo->mParent;
mSetSize = sibling->mGroupInfo->mSetSize;
return;
}
mSetSize++;
}
if (mParent)
return;
// Compute parent.
PRUint32 parentRole = nsAccUtils::Role(parent);
// In the case of ARIA row in treegrid, return treegrid since ARIA
// groups aren't used to organize levels in ARIA treegrids.
if (aRole == nsIAccessibleRole::ROLE_ROW &&
parentRole == nsIAccessibleRole::ROLE_TREE_TABLE) {
mParent = parent;
return;
}
// In the case of ARIA tree, a tree can be arranged by using ARIA groups
// to organize levels. In this case the parent of the tree item will be
// a group and the previous treeitem of that should be the tree item
// parent. Or, if the parent is something other than a tree we will
// return that.
if (parentRole != nsIAccessibleRole::ROLE_GROUPING) {
mParent = parent;
return;
}
nsAccessible* parentPrevSibling = parent->GetSiblingAtOffset(-1);
PRUint32 parentPrevSiblingRole = nsAccUtils::Role(parentPrevSibling);
if (parentPrevSiblingRole == nsIAccessibleRole::ROLE_TEXT_LEAF) {
// XXX Sometimes an empty text accessible is in the hierarchy here,
// although the text does not appear to be rendered, GetRenderedText()
// says that it is so we need to skip past it to find the true
// previous sibling.
parentPrevSibling = parentPrevSibling->GetSiblingAtOffset(-1);
parentPrevSiblingRole = nsAccUtils::Role(parentPrevSibling);
}
// Previous sibling of parent group is a tree item, this is the
// conceptual tree item parent.
if (parentPrevSiblingRole == nsIAccessibleRole::ROLE_OUTLINEITEM)
mParent = parentPrevSibling;
}

View File

@ -0,0 +1,96 @@
/* ***** 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
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Alexander Surkov <surkov.alexander@gmail.com> (original author)
*
* 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 ***** */
#ifndef AccGroupInfo_h_
#define AccGroupInfo_h_
#include "nsAccessible.h"
#include "nsAccUtils.h"
/**
* Calculate and store group information.
*/
class AccGroupInfo
{
public:
AccGroupInfo(nsAccessible* aItem, PRUint32 aRole);
~AccGroupInfo() { }
PRInt32 PosInSet() const { return mPosInSet; }
PRUint32 SetSize() const { return mSetSize; }
nsAccessible* GetConceptualParent() const { return mParent; }
/**
* Create group info.
*/
static AccGroupInfo* CreateGroupInfo(nsAccessible* aAccessible)
{
PRUint32 role = nsAccUtils::Role(aAccessible);
if (role != nsIAccessibleRole::ROLE_ROW &&
role != nsIAccessibleRole::ROLE_GRID_CELL &&
role != nsIAccessibleRole::ROLE_OUTLINEITEM &&
role != nsIAccessibleRole::ROLE_OPTION &&
role != nsIAccessibleRole::ROLE_LISTITEM &&
role != nsIAccessibleRole::ROLE_MENUITEM &&
role != nsIAccessibleRole::ROLE_CHECK_MENU_ITEM &&
role != nsIAccessibleRole::ROLE_RADIO_MENU_ITEM &&
role != nsIAccessibleRole::ROLE_RADIOBUTTON &&
role != nsIAccessibleRole::ROLE_PAGETAB)
return nsnull;
AccGroupInfo* info = new AccGroupInfo(aAccessible, BaseRole(role));
return info;
}
private:
AccGroupInfo(const AccGroupInfo&);
AccGroupInfo& operator =(const AccGroupInfo&);
static PRUint32 BaseRole(PRUint32 aRole)
{
if (aRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
aRole == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
return nsIAccessibleRole::ROLE_MENUITEM;
return aRole;
}
PRUint32 mPosInSet;
PRUint32 mSetSize;
nsAccessible* mParent;
};
#endif

View File

@ -49,6 +49,7 @@ LIBXUL_LIBRARY = 1
CPPSRCS = \ CPPSRCS = \
AccCollector.cpp \ AccCollector.cpp \
AccGroupInfo.cpp \
AccIterator.cpp \ AccIterator.cpp \
filters.cpp \ filters.cpp \
nsAccDocManager.cpp \ nsAccDocManager.cpp \

View File

@ -221,6 +221,34 @@ nsARIAGridAccessible::GetRowIndexAt(PRInt32 aCellIndex, PRInt32 *aRowIndex)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsARIAGridAccessible::GetRowAndColumnIndicesAt(PRInt32 aCellIndex,
PRInt32* aRowIndex,
PRInt32* aColumnIndex)
{
NS_ENSURE_ARG_POINTER(aRowIndex);
*aRowIndex = -1;
NS_ENSURE_ARG_POINTER(aColumnIndex);
*aColumnIndex = -1;
if (IsDefunct())
return NS_ERROR_FAILURE;
NS_ENSURE_ARG(aCellIndex >= 0);
PRInt32 rowCount = 0;
GetRowCount(&rowCount);
PRInt32 colsCount = 0;
GetColumnCount(&colsCount);
NS_ENSURE_ARG(aCellIndex < rowCount * colsCount);
*aColumnIndex = aCellIndex % colsCount;
*aRowIndex = aCellIndex / colsCount;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsARIAGridAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn, nsARIAGridAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn,
PRInt32 *aExtentCount) PRInt32 *aExtentCount)

View File

@ -39,11 +39,10 @@
#ifndef _nsAccCache_H_ #ifndef _nsAccCache_H_
#define _nsAccCache_H_ #define _nsAccCache_H_
#include "nsIAccessible.h"
#include "nsRefPtrHashtable.h" #include "nsRefPtrHashtable.h"
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
class nsIAccessible;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Accessible cache utils // Accessible cache utils
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -367,106 +367,6 @@ nsAccUtils::GetAncestorWithRole(nsAccessible *aDescendant, PRUint32 aRole)
return nsnull; return nsnull;
} }
void
nsAccUtils::GetARIATreeItemParent(nsIAccessible *aStartTreeItem,
nsIContent *aStartContent,
nsIAccessible **aTreeItemParentResult)
{
*aTreeItemParentResult = nsnull;
nsCOMPtr<nsIAccessible> parentAccessible;
aStartTreeItem->GetParent(getter_AddRefs(parentAccessible));
if (!parentAccessible)
return;
PRUint32 startTreeItemRole = nsAccUtils::Role(aStartTreeItem);
// Calculate tree grid row parent only if the row inside of ARIA treegrid.
if (startTreeItemRole == nsIAccessibleRole::ROLE_ROW) {
PRUint32 role = nsAccUtils::Role(parentAccessible);
if (role != nsIAccessibleRole::ROLE_TREE_TABLE)
return;
}
// This is a tree or treegrid that uses aria-level to define levels, so find
// the first previous sibling accessible where level is defined to be less
// than the current level.
nsAutoString levelStr;
if (nsAccUtils::HasDefinedARIAToken(aStartContent, nsAccessibilityAtoms::aria_level) &&
aStartContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::aria_level, levelStr)) {
PRInt32 success;
PRInt32 level = levelStr.ToInteger(&success);
if (level > 1 && NS_SUCCEEDED(success)) {
nsCOMPtr<nsIAccessible> currentAccessible = aStartTreeItem, prevAccessible;
while (PR_TRUE) {
currentAccessible->GetPreviousSibling(getter_AddRefs(prevAccessible));
currentAccessible.swap(prevAccessible);
nsCOMPtr<nsIAccessNode> accessNode = do_QueryInterface(currentAccessible);
if (!accessNode) {
break; // Reached top of tree, no higher level found
}
PRUint32 role = nsAccUtils::Role(currentAccessible);
if (role != startTreeItemRole)
continue;
nsCOMPtr<nsIDOMNode> treeItemNode;
accessNode->GetDOMNode(getter_AddRefs(treeItemNode));
nsCOMPtr<nsIContent> treeItemContent = do_QueryInterface(treeItemNode);
if (treeItemContent &&
nsAccUtils::HasDefinedARIAToken(treeItemContent,
nsAccessibilityAtoms::aria_level) &&
treeItemContent->GetAttr(kNameSpaceID_None,
nsAccessibilityAtoms::aria_level, levelStr)) {
if (levelStr.ToInteger(&success) < level && NS_SUCCEEDED(success)) {
NS_ADDREF(*aTreeItemParentResult = currentAccessible);
return;
}
}
}
}
}
// In the case of ARIA treegrid, return its parent since ARIA group isn't
// used to organize levels in ARIA treegrids.
if (startTreeItemRole == nsIAccessibleRole::ROLE_ROW) {
NS_ADDREF(*aTreeItemParentResult = parentAccessible);
return; // The container for the tree grid rows
}
// In the case of ARIA tree, a tree can be arranged by using role="group" to
// organize levels. In this case the parent of the tree item will be a group
// and the previous sibling of that should be the tree item parent. Or, if
// the parent is something other than a tree we will return that.
PRUint32 role = nsAccUtils::Role(parentAccessible);
if (role != nsIAccessibleRole::ROLE_GROUPING) {
NS_ADDREF(*aTreeItemParentResult = parentAccessible);
return; // The container for the tree items
}
nsCOMPtr<nsIAccessible> prevAccessible;
parentAccessible->GetPreviousSibling(getter_AddRefs(prevAccessible));
if (!prevAccessible)
return;
role = nsAccUtils::Role(prevAccessible);
if (role == nsIAccessibleRole::ROLE_TEXT_LEAF) {
// XXX Sometimes an empty text accessible is in the hierarchy here,
// although the text does not appear to be rendered, GetRenderedText() says that it is
// so we need to skip past it to find the true previous sibling
nsCOMPtr<nsIAccessible> tempAccessible = prevAccessible;
tempAccessible->GetPreviousSibling(getter_AddRefs(prevAccessible));
if (!prevAccessible)
return;
role = nsAccUtils::Role(prevAccessible);
}
if (role == nsIAccessibleRole::ROLE_OUTLINEITEM) {
// Previous sibling of parent group is a tree item -- this is the conceptual tree item parent
NS_ADDREF(*aTreeItemParentResult = prevAccessible);
}
}
nsAccessible * nsAccessible *
nsAccUtils::GetSelectableContainer(nsAccessible *aAccessible, PRUint32 aState) nsAccUtils::GetSelectableContainer(nsAccessible *aAccessible, PRUint32 aState)
{ {

View File

@ -198,19 +198,6 @@ public:
static nsAccessible * GetAncestorWithRole(nsAccessible *aDescendant, static nsAccessible * GetAncestorWithRole(nsAccessible *aDescendant,
PRUint32 aRole); PRUint32 aRole);
/**
* For an ARIA tree item , get the accessible that represents its conceptual parent.
* This method will use the correct method for the given way the tree is constructed.
* The conceptual parent is what the user sees as the parent, not the DOM or accessible parent.
* @param aStartTreeItem The tree item to get the parent for
* @param aStartTreeItemContent The content node for the tree item
* @param The tree item's parent, or null if none
*/
static void
GetARIATreeItemParent(nsIAccessible *aStartTreeItem,
nsIContent *aStartTreeItemContent,
nsIAccessible **aTreeItemParent);
/** /**
* Return single or multi selectable container for the given item. * Return single or multi selectable container for the given item.
* *

View File

@ -131,7 +131,7 @@ void nsAccessNode::LastRelease()
NS_ASSERTION(!mWeakShell, "A Shutdown() impl forgot to call its parent's Shutdown?"); NS_ASSERTION(!mWeakShell, "A Shutdown() impl forgot to call its parent's Shutdown?");
} }
// ... then die. // ... then die.
NS_DELETEXPCOM(this); delete this;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -41,6 +41,7 @@
#include "nsIXBLAccessible.h" #include "nsIXBLAccessible.h"
#include "AccGroupInfo.h"
#include "AccIterator.h" #include "AccIterator.h"
#include "nsAccUtils.h" #include "nsAccUtils.h"
#include "nsARIAMap.h" #include "nsARIAMap.h"
@ -2125,11 +2126,12 @@ nsAccessible::GetRelationByType(PRUint32 aRelationType,
(mRoleMapEntry->role == nsIAccessibleRole::ROLE_OUTLINEITEM || (mRoleMapEntry->role == nsIAccessibleRole::ROLE_OUTLINEITEM ||
mRoleMapEntry->role == nsIAccessibleRole::ROLE_ROW)) { mRoleMapEntry->role == nsIAccessibleRole::ROLE_ROW)) {
nsCOMPtr<nsIAccessible> accTarget; AccGroupInfo* groupInfo = GetGroupInfo();
nsAccUtils::GetARIATreeItemParent(this, mContent, if (!groupInfo)
getter_AddRefs(accTarget)); return NS_OK_NO_RELATION_TARGET;
return nsRelUtils::AddTarget(aRelationType, aRelation, accTarget); return nsRelUtils::AddTarget(aRelationType, aRelation,
groupInfo->GetConceptualParent());
} }
// If accessible is in its own Window, or is the root of a document, // If accessible is in its own Window, or is the root of a document,
@ -3091,98 +3093,24 @@ nsAccessible::GetActionRule(PRUint32 aStates)
return eNoAction; return eNoAction;
} }
AccGroupInfo*
nsAccessible::GetGroupInfo()
{
if (mGroupInfo)
return mGroupInfo;
mGroupInfo = AccGroupInfo::CreateGroupInfo(this);
return mGroupInfo;
}
void void
nsAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet, PRInt32 *aSetSize) nsAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet, PRInt32 *aSetSize)
{ {
PRUint32 role = nsAccUtils::Role(this); AccGroupInfo* groupInfo = GetGroupInfo();
if (role != nsIAccessibleRole::ROLE_LISTITEM && if (groupInfo) {
role != nsIAccessibleRole::ROLE_MENUITEM && *aPosInSet = groupInfo->PosInSet();
role != nsIAccessibleRole::ROLE_CHECK_MENU_ITEM && *aSetSize = groupInfo->SetSize();
role != nsIAccessibleRole::ROLE_RADIO_MENU_ITEM &&
role != nsIAccessibleRole::ROLE_RADIOBUTTON &&
role != nsIAccessibleRole::ROLE_PAGETAB &&
role != nsIAccessibleRole::ROLE_OPTION &&
role != nsIAccessibleRole::ROLE_OUTLINEITEM &&
role != nsIAccessibleRole::ROLE_ROW &&
role != nsIAccessibleRole::ROLE_GRID_CELL)
return;
PRUint32 baseRole = role;
if (role == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
role == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
baseRole = nsIAccessibleRole::ROLE_MENUITEM;
nsAccessible* parent = GetParent();
NS_ENSURE_TRUE(parent,);
PRInt32 level = nsAccUtils::GetARIAOrDefaultLevel(this);
// Compute 'posinset'.
PRInt32 positionInGroup = 1;
for (PRInt32 idx = mIndexInParent - 1; idx >= 0; idx--) {
nsAccessible* sibling = parent->GetChildAt(idx);
PRUint32 siblingRole = nsAccUtils::Role(sibling);
// If the sibling is separator then the group is ended.
if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR)
break;
PRUint32 siblingBaseRole = siblingRole;
if (siblingRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
siblingRole == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
siblingBaseRole = nsIAccessibleRole::ROLE_MENUITEM;
// If sibling is visible and has the same base role
if (siblingBaseRole == baseRole &&
!(nsAccUtils::State(sibling) & nsIAccessibleStates::STATE_INVISIBLE)) {
// and check if it's hierarchical flatten structure, i.e. if the sibling
// level is lesser than this one then group is ended, if the sibling level
// is greater than this one then the group is splited by some child
// elements (group will be continued).
PRInt32 siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
if (siblingLevel < level)
break;
else if (level == siblingLevel)
++ positionInGroup;
}
} }
// Compute 'setsize'.
PRInt32 setSize = positionInGroup;
PRInt32 siblingCount = parent->GetChildCount();
for (PRInt32 idx = mIndexInParent + 1; idx < siblingCount; idx++) {
nsAccessible* sibling = parent->GetChildAt(idx);
NS_ENSURE_TRUE(sibling,);
PRUint32 siblingRole = nsAccUtils::Role(sibling);
// If the sibling is separator then the group is ended.
if (siblingRole == nsIAccessibleRole::ROLE_SEPARATOR)
break;
PRUint32 siblingBaseRole = siblingRole;
if (siblingRole == nsIAccessibleRole::ROLE_CHECK_MENU_ITEM ||
siblingRole == nsIAccessibleRole::ROLE_RADIO_MENU_ITEM)
siblingBaseRole = nsIAccessibleRole::ROLE_MENUITEM;
// If sibling is visible and has the same base role
if (siblingBaseRole == baseRole &&
!(nsAccUtils::State(sibling) & nsIAccessibleStates::STATE_INVISIBLE)) {
// and check if it's hierarchical flatten structure.
PRInt32 siblingLevel = nsAccUtils::GetARIAOrDefaultLevel(sibling);
if (siblingLevel < level)
break;
else if (level == siblingLevel)
++ setSize;
}
}
*aPosInSet = positionInGroup;
*aSetSize = setSize;
} }
PRInt32 PRInt32

View File

@ -52,6 +52,7 @@
#include "nsTArray.h" #include "nsTArray.h"
#include "nsRefPtrHashtable.h" #include "nsRefPtrHashtable.h"
class AccGroupInfo;
class nsAccessible; class nsAccessible;
class nsAccEvent; class nsAccEvent;
struct nsRoleMapEntry; struct nsRoleMapEntry;
@ -324,7 +325,12 @@ protected:
* Set accessible parent and index in parent. * Set accessible parent and index in parent.
*/ */
void BindToParent(nsAccessible* aParent, PRUint32 aIndexInParent); void BindToParent(nsAccessible* aParent, PRUint32 aIndexInParent);
void UnbindFromParent() { mParent = nsnull; mIndexInParent = -1; } void UnbindFromParent()
{
mParent = nsnull;
mIndexInParent = -1;
mGroupInfo = nsnull;
}
/** /**
* Return sibling accessible at the given offset. * Return sibling accessible at the given offset.
@ -424,6 +430,11 @@ protected:
*/ */
PRUint32 GetActionRule(PRUint32 aStates); PRUint32 GetActionRule(PRUint32 aStates);
/**
* Return group info.
*/
AccGroupInfo* GetGroupInfo();
/** /**
* Fires platform accessible event. It's notification method only. It does * Fires platform accessible event. It's notification method only. It does
* change nothing on Gecko side. Don't use it until you're sure what you do * change nothing on Gecko side. Don't use it until you're sure what you do
@ -440,6 +451,9 @@ protected:
PRBool mAreChildrenInitialized; PRBool mAreChildrenInitialized;
PRInt32 mIndexInParent; PRInt32 mIndexInParent;
nsAutoPtr<AccGroupInfo> mGroupInfo;
friend class AccGroupInfo;
nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
}; };

View File

@ -953,6 +953,26 @@ nsHTMLTableAccessible::GetRowIndexAt(PRInt32 aIndex, PRInt32 *aRow)
return (*aRow == -1 || column == -1) ? NS_ERROR_INVALID_ARG : NS_OK; return (*aRow == -1 || column == -1) ? NS_ERROR_INVALID_ARG : NS_OK;
} }
NS_IMETHODIMP
nsHTMLTableAccessible::GetRowAndColumnIndicesAt(PRInt32 aIndex,
PRInt32* aRowIdx,
PRInt32* aColumnIdx)
{
NS_ENSURE_ARG_POINTER(aRowIdx);
*aRowIdx = -1;
NS_ENSURE_ARG_POINTER(aColumnIdx);
*aColumnIdx = -1;
if (IsDefunct())
return NS_ERROR_FAILURE;
nsITableLayout* tableLayout = GetTableLayout();
if (tableLayout)
tableLayout->GetRowAndColumnByIndex(aIndex, aRowIdx, aColumnIdx);
return (*aRowIdx == -1 || *aColumnIdx == -1) ? NS_ERROR_INVALID_ARG : NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsHTMLTableAccessible::GetColumnExtentAt(PRInt32 aRowIndex, nsHTMLTableAccessible::GetColumnExtentAt(PRInt32 aRowIndex,
PRInt32 aColumnIndex, PRInt32 aColumnIndex,

View File

@ -666,33 +666,28 @@ __try {
if (!tableAcc) if (!tableAcc)
return E_FAIL; return E_FAIL;
PRInt32 row = -1; PRInt32 rowIdx = -1, columnIdx = -1;
nsresult rv = tableAcc->GetRowIndexAt(aIndex, &row); nsresult rv = tableAcc->GetRowAndColumnIndicesAt(aIndex, &rowIdx, &columnIdx);
if (NS_FAILED(rv))
return GetHRESULT(rv);
PRInt32 column = -1;
rv = tableAcc->GetColumnIndexAt(aIndex, &column);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return GetHRESULT(rv); return GetHRESULT(rv);
PRInt32 rowExtents = 0; PRInt32 rowExtents = 0;
rv = tableAcc->GetRowExtentAt(row, column, &rowExtents); rv = tableAcc->GetRowExtentAt(rowIdx, columnIdx, &rowExtents);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return GetHRESULT(rv); return GetHRESULT(rv);
PRInt32 columnExtents = 0; PRInt32 columnExtents = 0;
rv = tableAcc->GetColumnExtentAt(row, column, &columnExtents); rv = tableAcc->GetColumnExtentAt(rowIdx, columnIdx, &columnExtents);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return GetHRESULT(rv); return GetHRESULT(rv);
PRBool isSelected = PR_FALSE; PRBool isSelected = PR_FALSE;
rv = tableAcc->IsCellSelected(row, column, &isSelected); rv = tableAcc->IsCellSelected(rowIdx, columnIdx, &isSelected);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return GetHRESULT(rv); return GetHRESULT(rv);
*aRow = row; *aRow = rowIdx;
*aColumn = column; *aColumn = columnIdx;
*aRowExtents = rowExtents; *aRowExtents = rowExtents;
*aColumnExtents = columnExtents; *aColumnExtents = columnExtents;
*aIsSelected = isSelected; *aIsSelected = isSelected;

View File

@ -412,6 +412,28 @@ nsXULListboxAccessible::GetRowIndexAt(PRInt32 aIndex, PRInt32 *aRow)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsXULListboxAccessible::GetRowAndColumnIndicesAt(PRInt32 aCellIndex,
PRInt32* aRowIndex,
PRInt32* aColumnIndex)
{
NS_ENSURE_ARG_POINTER(aRowIndex);
*aRowIndex = -1;
NS_ENSURE_ARG_POINTER(aColumnIndex);
*aColumnIndex = -1;
if (IsDefunct())
return NS_ERROR_FAILURE;
PRInt32 columnCount = 0;
nsresult rv = GetColumnCount(&columnCount);
NS_ENSURE_SUCCESS(rv, rv);
*aColumnIndex = aCellIndex % columnCount;
*aRowIndex = aCellIndex / columnCount;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsXULListboxAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn, nsXULListboxAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn,
PRInt32 *aCellSpans) PRInt32 *aCellSpans)

View File

@ -411,6 +411,28 @@ nsXULTreeGridAccessible::GetRowIndexAt(PRInt32 aCellIndex, PRInt32 *aRowIndex)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsXULTreeGridAccessible::GetRowAndColumnIndicesAt(PRInt32 aCellIndex,
PRInt32* aRowIndex,
PRInt32* aColumnIndex)
{
NS_ENSURE_ARG_POINTER(aRowIndex);
*aRowIndex = -1;
NS_ENSURE_ARG_POINTER(aColumnIndex);
*aColumnIndex = -1;
if (IsDefunct())
return NS_ERROR_FAILURE;
PRInt32 columnCount = 0;
nsresult rv = GetColumnCount(&columnCount);
NS_ENSURE_SUCCESS(rv, rv);
*aColumnIndex = aCellIndex % columnCount;
*aRowIndex = aCellIndex / columnCount;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsXULTreeGridAccessible::GetColumnExtentAt(PRInt32 aRowIndex, nsXULTreeGridAccessible::GetColumnExtentAt(PRInt32 aRowIndex,
PRInt32 aColumnIndex, PRInt32 aColumnIndex,

View File

@ -224,7 +224,7 @@ function testTableIndexes(aIdentifier, aIdxes)
if (idx != - 1) { if (idx != - 1) {
// getRowAtIndex // getRowIndexAt
var origRowIdx = rowIdx; var origRowIdx = rowIdx;
while (origRowIdx > 0 && while (origRowIdx > 0 &&
aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx]) aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx])
@ -237,9 +237,9 @@ function testTableIndexes(aIdentifier, aIdxes)
} }
is(obtainedRowIdx, origRowIdx, is(obtainedRowIdx, origRowIdx,
id + ": row for index " + idx +" is not correct"); id + ": row for index " + idx + " is not correct (getRowIndexAt)");
// getColumnAtIndex // getColumnIndexAt
var origColIdx = colIdx; var origColIdx = colIdx;
while (origColIdx > 0 && while (origColIdx > 0 &&
aIdxes[rowIdx][colIdx] == aIdxes[rowIdx][origColIdx - 1]) aIdxes[rowIdx][colIdx] == aIdxes[rowIdx][origColIdx - 1])
@ -252,7 +252,21 @@ function testTableIndexes(aIdentifier, aIdxes)
} }
is(obtainedColIdx, origColIdx, is(obtainedColIdx, origColIdx,
id + ": column for index " + idx +" is not correct"); id + ": column for index " + idx + " is not correct (getColumnIndexAt)");
// getRowAndColumnIndicesAt
var obtainedRowIdxObj = { }, obtainedColIdxObj = { };
try {
tableAcc.getRowAndColumnIndicesAt(idx, obtainedRowIdxObj,
obtainedColIdxObj);
} catch (e) {
ok(false, id + ": can't get row and column indices for cell index " + idx + "," + e);
}
is(obtainedRowIdxObj.value, origRowIdx,
id + ": row for index " + idx + " is not correct (getRowAndColumnIndicesAt)");
is(obtainedColIdxObj.value, origColIdx,
id + ": column for index " + idx + " is not correct (getRowAndColumnIndicesAt)");
if (cellAcc) { if (cellAcc) {

View File

@ -134,5 +134,7 @@
<true/> <true/>
<key>CGDisableCoalescedUpdates</key> <key>CGDisableCoalescedUpdates</key>
<true/> <true/>
<key>LSMinimumSystemVersion</key>
<string>10.5</string>
</dict> </dict>
</plist> </plist>

View File

@ -320,8 +320,6 @@ pref("browser.tabs.loadInBackground", true);
pref("browser.tabs.opentabfor.middleclick", true); pref("browser.tabs.opentabfor.middleclick", true);
pref("browser.tabs.loadDivertedInBackground", false); pref("browser.tabs.loadDivertedInBackground", false);
pref("browser.tabs.loadBookmarksInBackground", false); pref("browser.tabs.loadBookmarksInBackground", false);
pref("browser.tabs.tabMinWidth", 100);
pref("browser.tabs.tabMaxWidth", 250);
pref("browser.tabs.tabClipWidth", 140); pref("browser.tabs.tabClipWidth", 140);
// Where to show tab close buttons: // Where to show tab close buttons:

View File

@ -130,7 +130,7 @@ var FullZoom = {
this._siteSpecificPref = this._siteSpecificPref =
gPrefService.getBoolPref("browser.zoom.siteSpecific"); gPrefService.getBoolPref("browser.zoom.siteSpecific");
this.updateBackgroundTabs = this.updateBackgroundTabs =
gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs"); gPrefService.getBoolPref("browser.zoom.updateBackgroundTabs");
// Listen for changes to the browser.zoom branch so we can enable/disable // Listen for changes to the browser.zoom branch so we can enable/disable
// updating background tabs and per-site saving and restoring of zoom levels. // updating background tabs and per-site saving and restoring of zoom levels.

View File

@ -22,12 +22,18 @@ tabbrowser {
.tabbrowser-tab { .tabbrowser-tab {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab"); -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
}
.tabbrowser-tab:not([pinned]) {
-moz-box-flex: 100; -moz-box-flex: 100;
max-width: 250px;
min-width: 100px;
width: 0;
} }
.tabbrowser-tab:not([fadein]) { .tabbrowser-tab:not([fadein]) {
max-width: 1px !important; max-width: 1px;
min-width: 1px !important; min-width: 1px;
} }
.tabbrowser-tab[fadein]:not([pinned]) { .tabbrowser-tab[fadein]:not([pinned]) {
@ -48,9 +54,6 @@ tabbrowser {
.tabbrowser-tab[pinned] { .tabbrowser-tab[pinned] {
position: fixed; position: fixed;
-moz-box-flex: 0;
min-width: 0 !important;
max-width: none !important;
} }
.tabbrowser-tab[pinned] > .tab-text { .tabbrowser-tab[pinned] > .tab-text {
@ -81,6 +84,12 @@ toolbar[printpreview="true"] {
-moz-box-ordinal-group: 10; -moz-box-ordinal-group: 10;
} }
%ifdef MENUBAR_CAN_AUTOHIDE
#main-window[inFullscreen] > #appmenu-button-container {
display: none;
}
%endif
toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] { toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] {
display: none; display: none;
} }

View File

@ -4014,7 +4014,7 @@ var XULBrowserWindow = {
} }
}, },
onLinkIconAvailable: function (aBrowser, aIconURL) { onLinkIconAvailable: function (aIconURL) {
if (gProxyFavIcon && gBrowser.userTypedValue === null) if (gProxyFavIcon && gBrowser.userTypedValue === null)
PageProxySetIcon(aIconURL); // update the favicon in the URL bar PageProxySetIcon(aIconURL); // update the favicon in the URL bar
}, },
@ -4490,21 +4490,16 @@ var CombinedStopReload = {
}; };
var TabsProgressListener = { var TabsProgressListener = {
onProgressChange: function (aBrowser, aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
},
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
#ifdef MOZ_CRASHREPORTER #ifdef MOZ_CRASHREPORTER
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
if (aRequest instanceof Ci.nsIChannel && if (aRequest instanceof Ci.nsIChannel &&
aStateFlags & Ci.nsIWebProgressListener.STATE_START && aStateFlags & Ci.nsIWebProgressListener.STATE_START &&
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT && aStateFlags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT &&
gCrashReporter.enabled) { gCrashReporter.enabled) {
gCrashReporter.annotateCrashReport("URL", aRequest.URI.spec); gCrashReporter.annotateCrashReport("URL", aRequest.URI.spec);
} }
#endif
}, },
#endif
onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) { onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI) {
// Filter out any sub-frame loads // Filter out any sub-frame loads
@ -4512,9 +4507,6 @@ var TabsProgressListener = {
FullZoom.onLocationChange(aLocationURI, false, aBrowser); FullZoom.onLocationChange(aLocationURI, false, aBrowser);
}, },
onStatusChange: function (aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
},
onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) { onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) {
if (gPrefService.getBoolPref("accessibility.blockautorefresh")) { if (gPrefService.getBoolPref("accessibility.blockautorefresh")) {
let brandBundle = document.getElementById("bundle_brand"); let brandBundle = document.getElementById("bundle_brand");
@ -4561,9 +4553,6 @@ var TabsProgressListener = {
return false; return false;
} }
return true; return true;
},
onSecurityChange: function (aBrowser, aWebProgress, aRequest, aState) {
} }
} }
@ -4727,12 +4716,12 @@ var TabsOnTop = {
#ifdef MENUBAR_CAN_AUTOHIDE #ifdef MENUBAR_CAN_AUTOHIDE
function updateAppButtonDisplay() { function updateAppButtonDisplay() {
var menubarHidden = var displayAppButton = window.menubar.visible &&
document.getElementById("toolbar-menubar").getAttribute("autohide") == "true"; document.getElementById("toolbar-menubar").getAttribute("autohide") == "true";
document.getElementById("appmenu-button-container").hidden = !menubarHidden; document.getElementById("appmenu-button-container").hidden = !displayAppButton;
if (menubarHidden) if (displayAppButton)
document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1"); document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1");
else else
document.documentElement.removeAttribute("chromemargin"); document.documentElement.removeAttribute("chromemargin");
@ -7772,6 +7761,10 @@ var TabContextMenu = {
Cc["@mozilla.org/browser/sessionstore;1"]. Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore). getService(Ci.nsISessionStore).
getClosedTabCount(window) == 0; getClosedTabCount(window) == 0;
// Only one of pin/unpin should be visible
document.getElementById("context_pinTab").hidden = this.contextTab.pinned;
document.getElementById("context_unpinTab").hidden = !this.contextTab.pinned;
} }
}; };

View File

@ -126,6 +126,12 @@
accesskey="&openTabInNewWindow.accesskey;" accesskey="&openTabInNewWindow.accesskey;"
tbattr="tabbrowser-multiple" tbattr="tabbrowser-multiple"
oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/> oncommand="gBrowser.replaceTabWithWindow(TabContextMenu.contextTab);"/>
<menuitem id="context_pinTab" label="&pinTab.label;"
accesskey="&pinTab.accesskey;"
oncommand="gBrowser.pinTab(TabContextMenu.contextTab);"/>
<menuitem id="context_unpinTab" label="&unpinTab.label;" hidden="true"
accesskey="&unpinTab.accesskey;"
oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
<menuseparator/> <menuseparator/>
<menuitem id="context_bookmarkTab" <menuitem id="context_bookmarkTab"
label="&bookmarkThisTab.label;" label="&bookmarkThisTab.label;"

View File

@ -122,6 +122,12 @@ Sanitizer.prototype = {
// facility for timespan-based eviction. Wipe it. // facility for timespan-based eviction. Wipe it.
cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE); cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
} catch(er) {} } catch(er) {}
var imageCache = Cc["@mozilla.org/image/cache;1"].
getService(Ci.imgICache);
try {
imageCache.clearCache(false); // true=chrome, false=content
} catch(er) {}
}, },
get canClear() get canClear()

View File

@ -263,6 +263,53 @@
</body> </body>
</method> </method>
<method name="_callProgressListeners">
<parameter name="aBrowser"/>
<parameter name="aMethod"/>
<parameter name="aArguments"/>
<parameter name="aCallGlobalListeners"/>
<parameter name="aCallTabsListeners"/>
<body><![CDATA[
var rv = true;
if (!aBrowser)
aBrowser = this.mCurrentBrowser;
if (aCallGlobalListeners != false &&
aBrowser == this.mCurrentBrowser) {
this.mProgressListeners.forEach(function (p) {
if (aMethod in p) {
try {
if (!p[aMethod].apply(p, aArguments))
rv = false;
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
});
}
if (aCallTabsListeners != false) {
aArguments.unshift(aBrowser);
this.mTabsProgressListeners.forEach(function (p) {
if (aMethod in p) {
try {
if (!p[aMethod].apply(p, aArguments))
rv = false;
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
});
}
return rv;
]]></body>
</method>
<!-- A web progress listener object definition for a given tab. --> <!-- A web progress listener object definition for a given tab. -->
<method name="mTabProgressListener"> <method name="mTabProgressListener">
<parameter name="aTab"/> <parameter name="aTab"/>
@ -293,10 +340,14 @@
delete this.mTabBrowser; delete this.mTabBrowser;
}, },
onProgressChange : function (aWebProgress, aRequest, _callProgressListeners: function () {
aCurSelfProgress, aMaxSelfProgress, Array.unshift(arguments, this.mBrowser);
aCurTotalProgress, aMaxTotalProgress) return this.mTabBrowser._callProgressListeners.apply(this.mTabBrowser, arguments);
{ },
onProgressChange: function (aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0; this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0;
if (this.mBlank) if (this.mBlank)
@ -312,46 +363,21 @@
} }
} }
if (this.mTabBrowser.mCurrentTab == this.mTab) { this._callProgressListeners("onProgressChange",
for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { [aWebProgress, aRequest,
let p = this.mTabBrowser.mProgressListeners[i]; aCurSelfProgress, aMaxSelfProgress,
if (p) aCurTotalProgress, aMaxTotalProgress]);
try {
p.onProgressChange(aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}
for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
let p = this.mTabBrowser.mTabsProgressListeners[i];
if (p)
try {
p.onProgressChange(this.mBrowser, aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}, },
onProgressChange64 : function (aWebProgress, aRequest, onProgressChange64: function (aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress, aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) aCurTotalProgress, aMaxTotalProgress) {
{
return this.onProgressChange(aWebProgress, aRequest, return this.onProgressChange(aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress,
aMaxTotalProgress); aMaxTotalProgress);
}, },
onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus) onStateChange: function (aWebProgress, aRequest, aStateFlags, aStatus) {
{
if (!aRequest) if (!aRequest)
return; return;
@ -436,33 +462,19 @@
this.mTabBrowser.mIsBusy = false; this.mTabBrowser.mIsBusy = false;
} }
if (this.mTabBrowser.mCurrentTab == this.mTab) { if (oldBlank) {
for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { this._callProgressListeners("onUpdateCurrentBrowser",
let p = this.mTabBrowser.mProgressListeners[i]; [aStateFlags, aStatus, "", 0],
if (p) true, false);
try { } else {
if (!oldBlank) this._callProgressListeners("onStateChange",
p.onStateChange(aWebProgress, aRequest, aStateFlags, aStatus); [aWebProgress, aRequest, aStateFlags, aStatus],
// make sure that the visible status of new blank tabs is correctly set true, false);
else if ("onUpdateCurrentBrowser" in p)
p.onUpdateCurrentBrowser(aStateFlags, aStatus, "", 0);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
} }
for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) { this._callProgressListeners("onStateChange",
let p = this.mTabBrowser.mTabsProgressListeners[i]; [aWebProgress, aRequest, aStateFlags, aStatus],
if (p) false);
try {
p.onStateChange(this.mBrowser, aWebProgress, aRequest, aStateFlags, aStatus);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
if (aStateFlags & (nsIWebProgressListener.STATE_START | if (aStateFlags & (nsIWebProgressListener.STATE_START |
nsIWebProgressListener.STATE_STOP)) { nsIWebProgressListener.STATE_STOP)) {
@ -474,8 +486,7 @@
this.mStatus = aStatus; this.mStatus = aStatus;
}, },
onLocationChange : function(aWebProgress, aRequest, aLocation) onLocationChange: function (aWebProgress, aRequest, aLocation) {
{
// The document loaded correctly, clear the value if we should // The document loaded correctly, clear the value if we should
if (this.mBrowser.userTypedClear > 0) if (this.mBrowser.userTypedClear > 0)
this.mBrowser.userTypedValue = null; this.mBrowser.userTypedValue = null;
@ -497,129 +508,35 @@
browserHistory.registerOpenPage(aLocation); browserHistory.registerOpenPage(aLocation);
if (!this.mBlank) { if (!this.mBlank) {
if (this.mTabBrowser.mCurrentTab == this.mTab) { this._callProgressListeners("onLocationChange",
for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { [aWebProgress, aRequest, aLocation]);
let p = this.mTabBrowser.mProgressListeners[i];
if (p)
try {
p.onLocationChange(aWebProgress, aRequest, aLocation);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}
for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
let p = this.mTabBrowser.mTabsProgressListeners[i];
if (p)
try {
p.onLocationChange(this.mBrowser, aWebProgress, aRequest, aLocation);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
} }
this.mBrowser.lastURI = aLocation; this.mBrowser.lastURI = aLocation;
}, },
onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
{
if (this.mBlank) if (this.mBlank)
return; return;
if (this.mTabBrowser.mCurrentTab == this.mTab) { this._callProgressListeners("onStatusChange",
for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) { [aWebProgress, aRequest, aStatus, aMessage]);
let p = this.mTabBrowser.mProgressListeners[i];
if (p)
try {
p.onStatusChange(aWebProgress, aRequest, aStatus, aMessage);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}
for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
let p = this.mTabBrowser.mTabsProgressListeners[i];
if (p)
try {
p.onStatusChange(this.mBrowser, aWebProgress, aRequest, aStatus, aMessage);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
this.mMessage = aMessage; this.mMessage = aMessage;
}, },
onSecurityChange : function(aWebProgress, aRequest, aState) onSecurityChange: function (aWebProgress, aRequest, aState) {
{ this._callProgressListeners("onSecurityChange",
if (this.mTabBrowser.mCurrentTab == this.mTab) { [aWebProgress, aRequest, aState]);
for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
let p = this.mTabBrowser.mProgressListeners[i];
if (p)
try {
p.onSecurityChange(aWebProgress, aRequest, aState);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}
for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
let p = this.mTabBrowser.mTabsProgressListeners[i];
if (p)
try {
p.onSecurityChange(this.mBrowser, aWebProgress, aRequest, aState);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}, },
onRefreshAttempted : function(aWebProgress, aURI, aDelay, aSameURI) onRefreshAttempted: function (aWebProgress, aURI, aDelay, aSameURI) {
{ return this._callProgressListeners("onRefreshAttempted",
var allowRefresh = true; [aWebProgress, aURI, aDelay, aSameURI]);
if (this.mTabBrowser.mCurrentTab == this.mTab) {
for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
let p = this.mTabBrowser.mProgressListeners[i];
if (p && "onRefreshAttempted" in p) {
try {
if (!p.onRefreshAttempted(aWebProgress, aURI, aDelay, aSameURI))
allowRefresh = false;
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}
}
for (let i = 0; i < this.mTabBrowser.mTabsProgressListeners.length; i++) {
let p = this.mTabBrowser.mTabsProgressListeners[i];
if (p && "onRefreshAttempted" in p) {
try {
if (!p.onRefreshAttempted(this.mBrowser, aWebProgress, aURI, aDelay, aSameURI))
allowRefresh = false;
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}
return allowRefresh;
}, },
QueryInterface : function(aIID) QueryInterface: function (aIID) {
{
if (aIID.equals(Components.interfaces.nsIWebProgressListener) || if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
aIID.equals(Components.interfaces.nsIWebProgressListener2) || aIID.equals(Components.interfaces.nsIWebProgressListener2) ||
aIID.equals(Components.interfaces.nsISupportsWeakReference) || aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
@ -663,29 +580,7 @@
this.updateIcon(aTab); this.updateIcon(aTab);
if (browser == this.mCurrentBrowser) { this._callProgressListeners(browser, "onLinkIconAvailable", [browser.mIconURL]);
for (let i = 0; i < this.mProgressListeners.length; i++) {
let p = this.mProgressListeners[i];
if ('onLinkIconAvailable' in p)
try {
p.onLinkIconAvailable(browser, browser.mIconURL);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
}
for (let i = 0; i < this.mTabsProgressListeners.length; i++) {
let p = this.mTabsProgressListeners[i];
if ('onLinkIconAvailable' in p)
try {
p.onLinkIconAvailable(browser, browser.mIconURL);
} catch (e) {
// don't inhibit other listeners
Components.utils.reportError(e);
}
}
]]> ]]>
</body> </body>
</method> </method>
@ -864,26 +759,20 @@
var webProgress = this.mCurrentBrowser.webProgress; var webProgress = this.mCurrentBrowser.webProgress;
var securityUI = this.mCurrentBrowser.securityUI; var securityUI = this.mCurrentBrowser.securityUI;
var i, p; this._callProgressListeners(null, "onLocationChange",
for (i = 0; i < this.mProgressListeners.length; i++) { [webProgress, null, loc], true, false);
p = this.mProgressListeners[i];
if (p)
try {
p.onLocationChange(webProgress, null, loc);
if (securityUI)
p.onSecurityChange(webProgress, null, securityUI.state);
// make sure that all status indicators are properly updated if (securityUI) {
if ("onUpdateCurrentBrowser" in p) { this._callProgressListeners(null, "onSecurityChange",
let listener = this.mTabListeners[this.tabContainer.selectedIndex] || null; [webProgress, null, securityUI.state], true, false);
if (listener && listener.mStateFlags) }
p.onUpdateCurrentBrowser(listener.mStateFlags, listener.mStatus,
listener.mMessage, listener.mTotalProgress); var listener = this.mTabListeners[this.tabContainer.selectedIndex] || null;
} if (listener && listener.mStateFlags) {
} catch (e) { this._callProgressListeners(null, "onUpdateCurrentBrowser",
// don't inhibit other listeners or following code [listener.mStateFlags, listener.mStatus,
Components.utils.reportError(e); listener.mMessage, listener.mTotalProgress],
} true, false);
} }
// Don't switch the fast find or update the titlebar (bug 540248) - this tab switch is temporary // Don't switch the fast find or update the titlebar (bug 540248) - this tab switch is temporary
@ -898,32 +787,22 @@
const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener; const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
if (this.mCurrentTab.hasAttribute("busy") && !this.mIsBusy) { if (this.mCurrentTab.hasAttribute("busy") && !this.mIsBusy) {
this.mIsBusy = true; this.mIsBusy = true;
for (i = 0; i < this.mProgressListeners.length; i++) { this._callProgressListeners(null, "onStateChange",
p = this.mProgressListeners[i]; [webProgress, null,
if (p) nsIWebProgressListener.STATE_START |
try { nsIWebProgressListener.STATE_IS_NETWORK, 0],
p.onStateChange(webProgress, null, nsIWebProgressListener.STATE_START | nsIWebProgressListener.STATE_IS_NETWORK, 0); true, false);
} catch (e) {
// don't inhibit other listeners or following code
Components.utils.reportError(e);
}
}
} }
// If the new tab is not busy, and our current state is busy, then // If the new tab is not busy, and our current state is busy, then
// we need to fire a stop to all progress listeners. // we need to fire a stop to all progress listeners.
if (!this.mCurrentTab.hasAttribute("busy") && this.mIsBusy) { if (!this.mCurrentTab.hasAttribute("busy") && this.mIsBusy) {
this.mIsBusy = false; this.mIsBusy = false;
for (i = 0; i < this.mProgressListeners.length; i++) { this._callProgressListeners(null, "onStateChange",
p = this.mProgressListeners[i]; [webProgress, null,
if (p) nsIWebProgressListener.STATE_STOP |
try { nsIWebProgressListener.STATE_IS_NETWORK, 0],
p.onStateChange(webProgress, null, nsIWebProgressListener.STATE_STOP | nsIWebProgressListener.STATE_IS_NETWORK, 0); true, false);
} catch (e) {
// don't inhibit other listeners or following code
Components.utils.reportError(e);
}
}
} }
// TabSelect events are suppressed during preview mode to avoid confusing extensions and other bits of code // TabSelect events are suppressed during preview mode to avoid confusing extensions and other bits of code
@ -1054,11 +933,7 @@
} }
// Remove all our progress listeners from the active browser's filter. // Remove all our progress listeners from the active browser's filter.
for (var i = 0; i < this.mProgressListeners.length; i++) { this.mProgressListeners.forEach(filter.removeProgressListener, filter);
var p = this.mProgressListeners[i];
if (p)
filter.removeProgressListener(p);
}
// Wire up a progress listener to our filter. // Wire up a progress listener to our filter.
const listener = this.mTabProgressListener(this.mCurrentTab, const listener = this.mTabProgressListener(this.mCurrentTab,
@ -1210,9 +1085,6 @@
t.setAttribute("label", aURI); t.setAttribute("label", aURI);
t.setAttribute("crop", "end"); t.setAttribute("crop", "end");
t.style.maxWidth = this.tabContainer.mTabMaxWidth + "px";
t.style.minWidth = this.tabContainer.mTabMinWidth + "px";
t.width = 0;
t.setAttribute("validate", "never"); t.setAttribute("validate", "never");
t.setAttribute("onerror", "this.removeAttribute('image');"); t.setAttribute("onerror", "this.removeAttribute('image');");
t.className = "tabbrowser-tab"; t.className = "tabbrowser-tab";
@ -1766,12 +1638,8 @@
<parameter name="aListener"/> <parameter name="aListener"/>
<body> <body>
<![CDATA[ <![CDATA[
for (var i = 0; i < this.mProgressListeners.length; i++) { this.mProgressListeners =
if (this.mProgressListeners[i] == aListener) { this.mProgressListeners.filter(function (l) l != aListener);
this.mProgressListeners.splice(i, 1);
break;
}
}
if (!this.mTabbedMode) if (!this.mTabbedMode)
// Don't forget to remove it from the filter we hooked it up to // Don't forget to remove it from the filter we hooked it up to
@ -1792,9 +1660,8 @@
<parameter name="aListener"/> <parameter name="aListener"/>
<body> <body>
<![CDATA[ <![CDATA[
var pos = this.mTabsProgressListeners.indexOf(aListener); this.mTabsProgressListeners =
if (pos >= 0) this.mTabsProgressListeners.filter(function (l) l != aListener);
this.mTabsProgressListeners.splice(pos, 1);
]]> ]]>
</body> </body>
</method> </method>
@ -2505,8 +2372,6 @@
<implementation implements="nsIDOMEventListener"> <implementation implements="nsIDOMEventListener">
<constructor> <constructor>
<![CDATA[ <![CDATA[
this.mTabMinWidth = Services.prefs.getIntPref("browser.tabs.tabMinWidth");
this.mTabMaxWidth = Services.prefs.getIntPref("browser.tabs.tabMaxWidth");
this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth"); this.mTabClipWidth = Services.prefs.getIntPref("browser.tabs.tabClipWidth");
this.mCloseButtons = Services.prefs.getIntPref("browser.tabs.closeButtons"); this.mCloseButtons = Services.prefs.getIntPref("browser.tabs.closeButtons");
this._closeWindowWithLastTab = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab"); this._closeWindowWithLastTab = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab");
@ -2514,9 +2379,6 @@
var tab = this.firstChild; var tab = this.firstChild;
tab.setAttribute("label", tab.setAttribute("label",
this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle")); this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle"));
tab.style.minWidth = this.mTabMinWidth + "px";
tab.style.maxWidth = this.mTabMaxWidth + "px";
tab.width = 0;
tab.setAttribute("crop", "end"); tab.setAttribute("crop", "end");
tab.setAttribute("validate", "never"); tab.setAttribute("validate", "never");
tab.setAttribute("onerror", "this.removeAttribute('image');"); tab.setAttribute("onerror", "this.removeAttribute('image');");

View File

@ -125,6 +125,7 @@ _BROWSER_FILES = \
browser_bug491431.js \ browser_bug491431.js \
browser_bug495058.js \ browser_bug495058.js \
browser_bug517902.js \ browser_bug517902.js \
browser_bug519216.js \
browser_bug520538.js \ browser_bug520538.js \
browser_bug521216.js \ browser_bug521216.js \
browser_bug537474.js \ browser_bug537474.js \

View File

@ -38,11 +38,6 @@ var gFrontProgressListener = {
} }
var gAllProgressListener = { var gAllProgressListener = {
onProgressChange: function (aBrowser, aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
},
onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
var state = "onStateChange"; var state = "onStateChange";
info("AllProgress: " + state + " 0x" + aStateFlags.toString(16)); info("AllProgress: " + state + " 0x" + aStateFlags.toString(16));

View File

@ -57,12 +57,7 @@ var gProgressListener = {
ok(gBrowser.tabs.length == kURIs.length, "Correctly opened all expected tabs"); ok(gBrowser.tabs.length == kURIs.length, "Correctly opened all expected tabs");
finishTest(); finishTest();
} }
}, }
onProgressChange: function () {},
onLocationChange: function () {},
onStatusChange: function () {},
onSecurityChange: function () {}
} }
function test() { function test() {

View File

@ -0,0 +1,48 @@
function test() {
waitForExplicitFinish();
gBrowser.stop();
gBrowser.addProgressListener(progressListener1);
gBrowser.addProgressListener(progressListener2);
gBrowser.addProgressListener(progressListener3);
gBrowser.loadURI("data:text/plain,bug519216");
}
var calledListener1 = false;
var progressListener1 = {
onLocationChange: function onLocationChange() {
calledListener1 = true;
gBrowser.removeProgressListener(this);
}
};
var calledListener2 = false;
var progressListener2 = {
onLocationChange: function onLocationChange() {
ok(calledListener1, "called progressListener1 before progressListener2");
calledListener2 = true;
gBrowser.removeProgressListener(this);
}
};
var progressListener3 = {
onLocationChange: function onLocationChange() {
ok(calledListener2, "called progressListener2 before progressListener3");
gBrowser.removeProgressListener(this);
gBrowser.addProgressListener(progressListener4);
executeSoon(function () {
expectListener4 = true;
gBrowser.reload();
});
}
};
var expectListener4 = false;
var progressListener4 = {
onLocationChange: function onLocationChange() {
ok(expectListener4, "didn't call progressListener4 for the first location change");
gBrowser.removeProgressListener(this);
gBrowser.addTab();
gBrowser.removeCurrentTab();
finish();
}
};

View File

@ -35,13 +35,10 @@ var progressListener = {
if (aBrowser == tab.linkedBrowser) if (aBrowser == tab.linkedBrowser)
record(arguments.callee.name); record(arguments.callee.name);
}, },
onProgressChange: function () {},
onSecurityChange: function () {},
onStateChange: function onStateChange(aBrowser) { onStateChange: function onStateChange(aBrowser) {
if (aBrowser == tab.linkedBrowser) if (aBrowser == tab.linkedBrowser)
record(arguments.callee.name); record(arguments.callee.name);
}, },
onStatusChange: function () {},
onLinkIconAvailable: function onLinkIconAvailable(aBrowser) { onLinkIconAvailable: function onLinkIconAvailable(aBrowser) {
if (aBrowser == tab.linkedBrowser) if (aBrowser == tab.linkedBrowser)
record(arguments.callee.name); record(arguments.callee.name);

View File

@ -25,7 +25,7 @@ function test() {
function doTest() { function doTest() {
tabstrip.smoothScroll = false; tabstrip.smoothScroll = false;
var tabMinWidth = gPrefService.getIntPref("browser.tabs.tabMinWidth"); var tabMinWidth = parseInt(getComputedStyle(gBrowser.selectedTab, null).minWidth);
var tabCountForOverflow = Math.ceil(width(tabstrip) / tabMinWidth * 3); var tabCountForOverflow = Math.ceil(width(tabstrip) / tabMinWidth * 3);
while (tabContainer.childNodes.length < tabCountForOverflow) while (tabContainer.childNodes.length < tabCountForOverflow)
gBrowser.addTab("about:blank", {skipAnimation: true}); gBrowser.addTab("about:blank", {skipAnimation: true});

View File

@ -55,7 +55,7 @@ var SubscribeHandler = {
this._feedWriter.close(); this._feedWriter.close();
}, },
subscribe: function FH_subscribe() { subscribe: function SH_subscribe() {
this._feedWriter.subscribe(); this._feedWriter.subscribe();
} }
}; };

View File

@ -95,21 +95,6 @@ var gTabsListener = {
// Test finished. This will move to the next one. // Test finished. This will move to the next one.
waitForFocus(gCurrentTest.finish, gBrowser.ownerDocument.defaultView); waitForFocus(gCurrentTest.finish, gBrowser.ownerDocument.defaultView);
} }
},
onProgressChange: function(aBrowser, aWebProgress, aRequest,
aCurSelfProgress, aMaxSelfProgress,
aCurTotalProgress, aMaxTotalProgress) {
},
onStateChange: function(aBrowser, aWebProgress, aRequest,
aStateFlags, aStatus) {
},
onStatusChange: function(aBrowser, aWebProgress, aRequest,
aStatus, aMessage) {
},
onSecurityChange: function(aBrowser, aWebProgress, aRequest, aState) {
},
noLinkIconAvailable: function(aBrowser) {
} }
} }

View File

@ -141,6 +141,6 @@
label="&button.close.label;" accesskey="&button.close.accesskey;"/> label="&button.close.label;" accesskey="&button.close.accesskey;"/>
#endif #endif
</hbox> </hbox>
<resizer dir="bottomend"/> <resizer type="window" dir="bottomend"/>
</hbox> </hbox>
</window> </window>

View File

@ -111,6 +111,6 @@
label="&button.close.label;" accesskey="&button.close.accesskey;"/> label="&button.close.label;" accesskey="&button.close.accesskey;"/>
#endif #endif
</hbox> </hbox>
<resizer dir="bottomend"/> <resizer type="window" dir="bottomend"/>
</hbox> </hbox>
</window> </window>

View File

@ -571,6 +571,17 @@ PrivateBrowsingService.prototype = {
} }
} }
// Image Cache
let (imageCache = Cc["@mozilla.org/image/cache;1"].
getService(Ci.imgICache)) {
try {
imageCache.clearCache(false); // true=chrome, false=content
} catch (ex) {
Cu.reportError("Exception thrown while clearing the image cache: " +
ex.toString());
}
}
// Cookies // Cookies
let (cm = Cc["@mozilla.org/cookiemanager;1"]. let (cm = Cc["@mozilla.org/cookiemanager;1"].
getService(Ci.nsICookieManager2)) { getService(Ci.nsICookieManager2)) {

View File

@ -92,11 +92,6 @@ function test() {
Services.ww.registerNotification(observer); Services.ww.registerNotification(observer);
gBrowser.addTabsProgressListener({ gBrowser.addTabsProgressListener({
onLocationChange: function() {},
onProgressChange: function() {},
onSecurityChange: function() {},
onStatusChange: function() {},
onRefreshAttempted: function() {},
onStateChange: function(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { onStateChange: function(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
if (aStateFlags & (Ci.nsIWebProgressListener.STATE_STOP | if (aStateFlags & (Ci.nsIWebProgressListener.STATE_STOP |
Ci.nsIWebProgressListener.STATE_IS_WINDOW)) { Ci.nsIWebProgressListener.STATE_IS_WINDOW)) {

View File

@ -83,8 +83,7 @@ function test() {
let numTests = 4; let numTests = 4;
let completedTests = 0; let completedTests = 0;
// access the pref service just once let tabMinWidth = parseInt(getComputedStyle(gBrowser.selectedTab, null).minWidth);
let tabMinWidth = gPrefService.getIntPref("browser.tabs.tabMinWidth");
function runTest(testNum, totalTabs, selectedTab, shownTabs, order) { function runTest(testNum, totalTabs, selectedTab, shownTabs, order) {
let test = { let test = {

View File

@ -62,11 +62,7 @@ function test() {
gBrowser.removeTabsProgressListener(this); gBrowser.removeTabsProgressListener(this);
executeSoon(aSetStateCallback); executeSoon(aSetStateCallback);
} }
}, }
onProgressChange: function () {},
onSecurityChange: function () {},
onStateChange: function () {},
onStatusChange: function () {}
}); });
ss.setBrowserState(JSON.stringify(aState)); ss.setBrowserState(JSON.stringify(aState));
} }
@ -211,11 +207,7 @@ function test() {
gBrowser.removeTabsProgressListener(this); gBrowser.removeTabsProgressListener(this);
firstLocationChange(); firstLocationChange();
} }
}, }
onProgressChange: function () {},
onSecurityChange: function () {},
onStateChange: function () {},
onStatusChange: function () {}
}); });
function firstLocationChange() { function firstLocationChange() {

View File

@ -530,16 +530,6 @@ TabWindow.prototype = {
}, },
//// Browser progress listener //// Browser progress listener
onLocationChange: function () {
},
onProgressChange: function () {
},
onSecurityChange: function () {
},
onStateChange: function () {
},
onStatusChange: function () {
},
onLinkIconAvailable: function (aBrowser, aIconURL) { onLinkIconAvailable: function (aBrowser, aIconURL) {
let self = this; let self = this;
getFaviconAsImage(aIconURL, function (img) { getFaviconAsImage(aIconURL, function (img) {

View File

@ -22,6 +22,10 @@
<!ENTITY closeOtherTabs.accesskey "o"> <!ENTITY closeOtherTabs.accesskey "o">
<!ENTITY openTabInNewWindow.label "Open in a New Window"> <!ENTITY openTabInNewWindow.label "Open in a New Window">
<!ENTITY openTabInNewWindow.accesskey "W"> <!ENTITY openTabInNewWindow.accesskey "W">
<!ENTITY pinTab.label "Make into App Tab">
<!ENTITY pinTab.accesskey "p">
<!ENTITY unpinTab.label "Make into Normal Tab">
<!ENTITY unpinTab.accesskey "k">
<!ENTITY bookmarkThisTab.label "Bookmark This Tab"> <!ENTITY bookmarkThisTab.label "Bookmark This Tab">
<!ENTITY bookmarkThisTab.accesskey "B"> <!ENTITY bookmarkThisTab.accesskey "B">
<!ENTITY bookmarkAllTabs.label "Bookmark All Tabs…"> <!ENTITY bookmarkAllTabs.label "Bookmark All Tabs…">

View File

@ -52,7 +52,7 @@ addonInstallManage.accesskey=O
addonError-1=The add-on could not be downloaded because of a connection failure on #2. addonError-1=The add-on could not be downloaded because of a connection failure on #2.
addonError-2=The add-on from #2 could not be installed because it does not match the add-on #3 expected. addonError-2=The add-on from #2 could not be installed because it does not match the add-on #3 expected.
addonError-3=The add-on downloaded from #2 could not be installed because it appears to be corrupt. addonError-3=The add-on downloaded from #2 could not be installed because it appears to be corrupt.
addonError-4=#1 could not be installed because Firefox cannot modify the needed file. addonError-4=#1 could not be installed because #3 cannot modify the needed file.
addonErrorIncompatible=#1 could not be installed because it is not compatible with #3 #4. addonErrorIncompatible=#1 could not be installed because it is not compatible with #3 #4.
addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems. addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems.

View File

@ -51,7 +51,6 @@ browser/components/migration/Makefile
browser/components/migration/public/Makefile browser/components/migration/public/Makefile
browser/components/migration/src/Makefile browser/components/migration/src/Makefile
browser/components/places/Makefile browser/components/places/Makefile
browser/components/places/public/Makefile
browser/components/places/src/Makefile browser/components/places/src/Makefile
browser/components/preferences/Makefile browser/components/preferences/Makefile
browser/components/privatebrowsing/Makefile browser/components/privatebrowsing/Makefile

View File

@ -181,7 +181,7 @@ statusbarpanel#statusbar-display {
position: relative !important; position: relative !important;
background-color: -moz-dialog !important; background-color: -moz-dialog !important;
} }
#navigator-toolbox[tabsontop="true"] > #toolbar-menubar[autohide="true"] ~ #TabsToolbar { #navigator-toolbox[tabsontop="true"] > #toolbar-menubar[autohide="true"] ~ #TabsToolbar:not([inFullscreen]) {
-moz-padding-start: 10em !important; -moz-padding-start: 10em !important;
} }
%ifdef WINSTRIPE_AERO %ifdef WINSTRIPE_AERO

View File

@ -40,12 +40,28 @@
@import "chrome://global/skin/"; @import "chrome://global/skin/";
/* View buttons */ /* View buttons */
#viewGroup {
-moz-padding-start: 10px;
}
#viewGroup > radio { #viewGroup > radio {
list-style-image: url("chrome://browser/skin/pageInfo.png"); list-style-image: url("chrome://browser/skin/pageInfo.png");
-moz-box-orient: vertical; -moz-box-orient: vertical;
-moz-box-align: center; -moz-box-align: center;
-moz-appearance: none; -moz-appearance: none;
padding: 5px 3px 1px 3px; padding: 5px 3px 1px 3px;
margin: 0 1px;
min-width: 4.5em;
}
#viewGroup > radio:hover {
background-color: #E0E8F6;
color: black;
}
#viewGroup > radio[selected="true"] {
background-color: #C1D2EE;
color: black;
} }
#topBar { #topBar {

View File

@ -1,2 +1,2 @@
repo: f5ab154deef2ffa97f1b2139589ae4a1962090a4 repo: f5ab154deef2ffa97f1b2139589ae4a1962090a4
node: 3476582628db128ad061c30cab1a74a0c5d14b9b node: 7ae0b4af32617677698f9de3ab76bcb154bbf085

View File

@ -1402,7 +1402,7 @@ class Makefile(object):
Inform the makefile of a target which is a candidate for being the default target, Inform the makefile of a target which is a candidate for being the default target,
if there isn't already a default target. if there isn't already a default target.
""" """
if self.defaulttarget is None: if self.defaulttarget is None and t != '.PHONY':
self.defaulttarget = t self.defaulttarget = t
def getpatternvariables(self, pattern): def getpatternvariables(self, pattern):

View File

@ -284,7 +284,7 @@ def ifeq(d, offset):
if token == '(': if token == '(':
arg1, t, offset = parsemakesyntax(d, offset, (',',), itermakefilechars) arg1, t, offset = parsemakesyntax(d, offset, (',',), itermakefilechars)
if t is None: if t is None:
raise SyntaxError("Expected two arguments in conditional", d.getloc(offset)) raise SyntaxError("Expected two arguments in conditional", d.getloc(d.lend))
arg1.rstrip() arg1.rstrip()
@ -604,6 +604,9 @@ class ParseStackFrame(object):
self.function = function self.function = function
self.loc = loc self.loc = loc
def __str__(self):
return "<state=%i expansion=%s tokenlist=%s openbrace=%s closebrace=%s>" % (self.parsestate, self.expansion, self.tokenlist, self.openbrace, self.closebrace)
_matchingbrace = { _matchingbrace = {
'(': ')', '(': ')',
'{': '}', '{': '}',
@ -689,7 +692,7 @@ def parsemakesyntax(d, offset, stopon, iterfunc):
stacktop.expansion.appendstr(token) stacktop.expansion.appendstr(token)
stacktop = ParseStackFrame(_PARSESTATE_PARENMATCH, stacktop, stacktop = ParseStackFrame(_PARSESTATE_PARENMATCH, stacktop,
stacktop.expansion, stacktop.expansion,
(token, stacktop.closebrace), (token, stacktop.closebrace, '$'),
openbrace=token, closebrace=stacktop.closebrace, loc=d.getloc(tokenoffset)) openbrace=token, closebrace=stacktop.closebrace, loc=d.getloc(tokenoffset))
elif parsestate == _PARSESTATE_PARENMATCH: elif parsestate == _PARSESTATE_PARENMATCH:
assert token == stacktop.closebrace assert token == stacktop.closebrace

View File

@ -3,6 +3,8 @@ test: VAR = value
%.do: %.do:
@echo TEST-FAIL: ran target "$@", should have run "all" @echo TEST-FAIL: ran target "$@", should have run "all"
.PHONY: test
all: all:
@echo TEST-PASS: the default target is all @echo TEST-PASS: the default target is all

View File

@ -0,0 +1,6 @@
#T returncode: 2
ifeq ($(FOO,VAR))
all:
@echo TEST_FAIL
endif

View File

@ -1,5 +1,5 @@
$(shell \ $(shell \
if test ! -f include-dynamic.inc; then \ if ! test -f include-dynamic.inc; then \
echo "TESTVAR = oldval" > include-dynamic.inc; \ echo "TESTVAR = oldval" > include-dynamic.inc; \
sleep 2; \ sleep 2; \
echo "TESTVAR = newval" > include-dynamic.inc.in; \ echo "TESTVAR = newval" > include-dynamic.inc.in; \

File diff suppressed because one or more lines are too long

View File

@ -78,7 +78,7 @@ nsNullPrincipal::Release()
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount); nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
NS_LOG_RELEASE(this, count, "nsNullPrincipal"); NS_LOG_RELEASE(this, count, "nsNullPrincipal");
if (count == 0) { if (count == 0) {
NS_DELETEXPCOM(this); delete this;
} }
return count; return count;

View File

@ -166,7 +166,7 @@ nsPrincipal::Release()
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount); nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
NS_LOG_RELEASE(this, count, "nsPrincipal"); NS_LOG_RELEASE(this, count, "nsPrincipal");
if (count == 0) { if (count == 0) {
NS_DELETEXPCOM(this); delete this;
} }
return count; return count;

View File

@ -75,7 +75,7 @@ nsSystemPrincipal::Release()
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount); nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
NS_LOG_RELEASE(this, count, "nsSystemPrincipal"); NS_LOG_RELEASE(this, count, "nsSystemPrincipal");
if (count == 0) { if (count == 0) {
NS_DELETEXPCOM(this); delete this;
} }
return count; return count;

View File

@ -46,6 +46,7 @@ MODULE = chrome
LIBRARY_NAME = chrome_s LIBRARY_NAME = chrome_s
LIBXUL_LIBRARY = 1 LIBXUL_LIBRARY = 1
FORCE_STATIC_LIB = 1 FORCE_STATIC_LIB = 1
FORCE_USE_PIC = 1
EXPORTS_NAMESPACES = mozilla/chrome EXPORTS_NAMESPACES = mozilla/chrome

View File

@ -51,10 +51,12 @@ function do_run_test()
let cr = Cc["@mozilla.org/chrome/chrome-registry;1"]. let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIChromeRegistry); getService(Ci.nsIChromeRegistry);
var runtime = Components.classes["@mozilla.org/xre/app-info;1"] // If we don't have libxul or e10s then we don't have process separation, so
.getService(Components.interfaces.nsIXULRuntime); // we don't need to worry about checking for new chrome.
if (runtime.processType == var appInfo = Cc["@mozilla.org/xre/app-info;1"];
Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { if (!appInfo ||
(appInfo.getService(Ci.nsIXULRuntime).processType ==
Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT)) {
cr.checkForNewChrome(); cr.checkForNewChrome();
} }

View File

@ -1,3 +1,4 @@
#line 2 "nsStaticComponents.cpp.in"
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -40,21 +41,16 @@
#define XPCOM_TRANSLATE_NSGM_ENTRY_POINT 1 #define XPCOM_TRANSLATE_NSGM_ENTRY_POINT 1
#include "nsIGenericFactory.h" #include "mozilla/ModuleUtils.h"
#include "nsXPCOM.h" #include "nsXPCOM.h"
#include "nsMemory.h" #include "nsMemory.h"
#include "nsStaticComponents.h" #include "nsStaticComponents.h"
/**
* Construct a unique NSGetModule entry point for a generic module.
*/
#define NSGETMODULE(_name) _name##_NSGetModule
/** /**
* Declare an NSGetModule() routine for a generic module. * Declare an NSGetModule() routine for a generic module.
*/ */
#define MODULE(_name) \ #define MODULE(_name) \
NSGETMODULE_ENTRY_POINT(_name) (nsIComponentManager*, nsIFile*, nsIModule**); NSMODULE_DECL(_name);
%MODULE_LIST% %MODULE_LIST%
#line 57 "nsStaticComponents.cpp.in" #line 57 "nsStaticComponents.cpp.in"
@ -62,15 +58,16 @@ NSGETMODULE_ENTRY_POINT(_name) (nsIComponentManager*, nsIFile*, nsIModule**);
#undef MODULE #undef MODULE
#define MODULE(_name) { #_name, NSGETMODULE(_name) }, #define MODULE(_name) \
NSMODULE_NAME(_name),
/** /**
* The nsStaticModuleInfo * The nsStaticModuleInfo
*/ */
static nsStaticModuleInfo const gStaticModuleInfo[] = { static const mozilla::Module *const kStaticModules[] = {
%MODULE_LIST% %MODULE_LIST%
#line 69 "nsStaticComponents.cpp.in" #line 70 "nsStaticComponents.cpp.in"
NULL
}; };
nsStaticModuleInfo const *const kPStaticModules = gStaticModuleInfo; mozilla::Module const *const *const kPStaticModules = kStaticModules;
PRUint32 const kStaticModuleCount = NS_ARRAY_LENGTH(gStaticModuleInfo);

View File

@ -47,7 +47,7 @@
$found = 1; $found = 1;
# GLOBALS # GLOBALS
$SEP = 0; # the paltform independent path separator $SEP = 0; # the platform independent path separator
$CFG = 0; # the value of the -cfg flag $CFG = 0; # the value of the -cfg flag
# determine the path separator # determine the path separator

View File

@ -168,6 +168,7 @@ xpcshell-tests:
-I$(topsrcdir)/build \ -I$(topsrcdir)/build \
$(testxpcsrcdir)/runxpcshelltests.py \ $(testxpcsrcdir)/runxpcshelltests.py \
--symbols-path=$(DIST)/crashreporter-symbols \ --symbols-path=$(DIST)/crashreporter-symbols \
$(EXTRA_TEST_ARGS) \
$(DIST)/bin/xpcshell \ $(DIST)/bin/xpcshell \
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(MODULE)/$(dir)) $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(MODULE)/$(dir))
@ -193,6 +194,8 @@ check-one:
--symbols-path=$(DIST)/crashreporter-symbols \ --symbols-path=$(DIST)/crashreporter-symbols \
--test-path=$(SOLO_FILE) \ --test-path=$(SOLO_FILE) \
--profile-name=$(MOZ_APP_NAME) \ --profile-name=$(MOZ_APP_NAME) \
--verbose \
$(EXTRA_TEST_ARGS) \
$(DIST)/bin/xpcshell \ $(DIST)/bin/xpcshell \
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(MODULE)/$(dir)) $(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(MODULE)/$(dir))
@ -2291,3 +2294,6 @@ CHECK_FROZEN_VARIABLES = $(foreach var,$(FREEZE_VARIABLES), \
libs export libs:: libs export libs::
$(CHECK_FROZEN_VARIABLES) $(CHECK_FROZEN_VARIABLES)
default::
if test -d $(DIST)/bin ; then touch $(DIST)/bin/.purgecaches ; fi

View File

@ -1538,7 +1538,7 @@ x86_64 | ia64)
CPU_ARCH="$OS_TEST" CPU_ARCH="$OS_TEST"
;; ;;
arm) arm*)
CPU_ARCH=arm CPU_ARCH=arm
;; ;;
esac esac
@ -1567,8 +1567,8 @@ if test "$GNU_CC"; then
ASFLAGS="$ASFLAGS -fPIC" ASFLAGS="$ASFLAGS -fPIC"
_MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti _MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti
_MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti _MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti
_MOZ_EXCEPTIONS_FLAGS_ON='-fhandle-exceptions' _MOZ_EXCEPTIONS_FLAGS_ON='-fexceptions'
_MOZ_EXCEPTIONS_FLAGS_OFF='-fno-handle-exceptions' _MOZ_EXCEPTIONS_FLAGS_OFF='-fno-exceptions'
# Turn on GNU specific features # Turn on GNU specific features
# -Wall - turn on all warnings # -Wall - turn on all warnings
@ -2539,8 +2539,8 @@ ia64*-hpux*)
USE_PTHREADS=1 USE_PTHREADS=1
_PEDANTIC= _PEDANTIC=
LIBS="$LIBS -lsocket -lstdc++" LIBS="$LIBS -lsocket -lstdc++"
_DEFINES_CFLAGS='-Wp,-include -Wp,$(DEPTH)/mozilla-config.h -DMOZILLA_CLIENT -D_POSIX_C_SOURCE=199506' _DEFINES_CFLAGS='-include $(DEPTH)/mozilla-config.h -DMOZILLA_CLIENT -D_POSIX_C_SOURCE=199506'
_DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -Wp,-include -Wp,$(DEPTH)/mozilla-config.h -D_POSIX_C_SOURCE=199506' _DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(DEPTH)/mozilla-config.h -D_POSIX_C_SOURCE=199506'
if test "$with_x" != "yes" if test "$with_x" != "yes"
then then
_PLATFORM_DEFAULT_TOOLKIT="photon" _PLATFORM_DEFAULT_TOOLKIT="photon"
@ -4024,32 +4024,6 @@ EOF
esac esac
dnl =================================================================== dnl ===================================================================
dnl ========================================================
dnl By default, turn rtti and exceptions off on g++/egcs
dnl ========================================================
if test "$GNU_CXX"; then
AC_MSG_CHECKING(for C++ exceptions flag)
dnl They changed -f[no-]handle-exceptions to -f[no-]exceptions in g++ 2.8
AC_CACHE_VAL(ac_cv_cxx_exceptions_flags,
[echo "int main() { return 0; }" | cat > conftest.C
${CXX-g++} ${CXXFLAGS} -c -fno-handle-exceptions conftest.C > conftest.out 2>&1
if egrep "warning.*renamed" conftest.out >/dev/null; then
ac_cv_cxx_exceptions_flags=${_COMPILER_PREFIX}-fno-exceptions
else
ac_cv_cxx_exceptions_flags=${_COMPILER_PREFIX}-fno-handle-exceptions
fi
rm -f conftest*])
AC_MSG_RESULT($ac_cv_cxx_exceptions_flags)
_MOZ_EXCEPTIONS_FLAGS_OFF=$ac_cv_cxx_exceptions_flags
_MOZ_EXCEPTIONS_FLAGS_ON=`echo $ac_cv_cxx_exceptions_flags | sed 's|no-||'`
fi
dnl ======================================================== dnl ========================================================
dnl Put your C++ language/feature checks below dnl Put your C++ language/feature checks below
dnl ======================================================== dnl ========================================================
@ -6005,7 +5979,7 @@ if test -n "$MOZ_SYDNEYAUDIO"; then
linux*) linux*)
PKG_CHECK_MODULES(MOZ_ALSA, alsa, , PKG_CHECK_MODULES(MOZ_ALSA, alsa, ,
[echo "$MOZ_ALSA_PKG_ERRORS" [echo "$MOZ_ALSA_PKG_ERRORS"
AC_MSG_ERROR([Need alsa for Ogg or Wave decoding on Linux. Disable with --disable-ogg --disable-wave. (On Ubuntu, you might try installing the package libasound2-dev.)])]) AC_MSG_ERROR([Need alsa for Ogg, Wave or WebM decoding on Linux. Disable with --disable-ogg --disable-wave --disable-webm. (On Ubuntu, you might try installing the package libasound2-dev.)])])
;; ;;
esac esac
fi fi
@ -7977,7 +7951,7 @@ if test "$_cpp_md_flag"; then
if test "$OS_ARCH" = "OpenVMS"; then if test "$OS_ARCH" = "OpenVMS"; then
_DEPEND_CFLAGS='$(subst =, ,$(filter-out %/.pp,-MM=-MD=-MF=$(MDDEPDIR)/$(basename $(@F)).pp))' _DEPEND_CFLAGS='$(subst =, ,$(filter-out %/.pp,-MM=-MD=-MF=$(MDDEPDIR)/$(basename $(@F)).pp))'
else else
_DEPEND_CFLAGS='$(filter-out %/.pp,-Wp,-MD,$(MDDEPDIR)/$(basename $(@F)).pp)' _DEPEND_CFLAGS='$(filter-out %/.pp,-MD -MF $(MDDEPDIR)/$(basename $(@F)).pp)'
fi fi
dnl Sun Studio on Solaris use -xM instead of -MD, see config/rules.mk dnl Sun Studio on Solaris use -xM instead of -MD, see config/rules.mk
if test "$SOLARIS_SUNPRO_CC"; then if test "$SOLARIS_SUNPRO_CC"; then

View File

@ -130,6 +130,7 @@ class nsIMIMEHeaderParam;
class nsIObserver; class nsIObserver;
class nsPresContext; class nsPresContext;
class nsIChannel; class nsIChannel;
struct nsIntMargin;
#ifndef have_PrefChangedFunc_typedef #ifndef have_PrefChangedFunc_typedef
typedef int (*PR_CALLBACK PrefChangedFunc)(const char *, void *); typedef int (*PR_CALLBACK PrefChangedFunc)(const char *, void *);

View File

@ -39,6 +39,7 @@
#define nsCopySupport_h__ #define nsCopySupport_h__
#include "nscore.h" #include "nscore.h"
#include "nsINode.h"
class nsISelection; class nsISelection;
class nsIDocument; class nsIDocument;
@ -47,7 +48,6 @@ class nsIContent;
class nsITransferable; class nsITransferable;
class nsACString; class nsACString;
class nsAString; class nsAString;
class nsIDOMNode;
class nsIPresShell; class nsIPresShell;
class nsCopySupport class nsCopySupport
@ -69,10 +69,14 @@ class nsCopySupport
// Get the selection as a transferable. Similar to HTMLCopy except does // Get the selection as a transferable. Similar to HTMLCopy except does
// not deal with the clipboard. // not deal with the clipboard.
static nsresult GetTransferableForSelection(nsISelection * aSelection, static nsresult GetTransferableForSelection(nsISelection* aSelection,
nsIDocument * aDocument, nsIDocument* aDocument,
nsITransferable ** aTransferable); nsITransferable** aTransferable);
// Same as GetTransferableForSelection, but doesn't skip invisible content.
static nsresult GetTransferableForNode(nsINode* aNode,
nsIDocument* aDoc,
nsITransferable** aTransferable);
/** /**
* Retrieve the selection for the given document. If the current focus * Retrieve the selection for the given document. If the current focus
* within the document has its own selection, aSelection will be set to it * within the document has its own selection, aSelection will be set to it

View File

@ -55,7 +55,7 @@
#include "nsChannelProperties.h" #include "nsChannelProperties.h"
/* Keeps track of whether or not CSP is enabled */ /* Keeps track of whether or not CSP is enabled */
static PRBool gCSPEnabled = PR_TRUE; PRBool CSPService::sCSPEnabled = PR_TRUE;
#ifdef PR_LOGGING #ifdef PR_LOGGING
static PRLogModuleInfo* gCspPRLog; static PRLogModuleInfo* gCspPRLog;
@ -63,7 +63,7 @@ static PRLogModuleInfo* gCspPRLog;
CSPService::CSPService() CSPService::CSPService()
{ {
nsContentUtils::AddBoolPrefVarCache("security.csp.enable", &gCSPEnabled); nsContentUtils::AddBoolPrefVarCache("security.csp.enable", &sCSPEnabled);
#ifdef PR_LOGGING #ifdef PR_LOGGING
if (!gCspPRLog) if (!gCspPRLog)
@ -102,7 +102,7 @@ CSPService::ShouldLoad(PRUint32 aContentType,
*aDecision = nsIContentPolicy::ACCEPT; *aDecision = nsIContentPolicy::ACCEPT;
// No need to continue processing if CSP is disabled // No need to continue processing if CSP is disabled
if (!gCSPEnabled) if (!sCSPEnabled)
return NS_OK; return NS_OK;
// find the principal of the document that initiated this request and see // find the principal of the document that initiated this request and see
@ -160,7 +160,7 @@ CSPService::ShouldProcess(PRUint32 aContentType,
*aDecision = nsIContentPolicy::ACCEPT; *aDecision = nsIContentPolicy::ACCEPT;
// No need to continue processing if CSP is disabled // No need to continue processing if CSP is disabled
if (!gCSPEnabled) if (!sCSPEnabled)
return NS_OK; return NS_OK;
// find the nsDocument that initiated this request and see if it has a // find the nsDocument that initiated this request and see if it has a

View File

@ -52,7 +52,8 @@ public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPOLICY NS_DECL_NSICONTENTPOLICY
NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSICHANNELEVENTSINK
CSPService(); CSPService();
virtual ~CSPService(); virtual ~CSPService();
static PRBool sCSPEnabled;
}; };

View File

@ -37,6 +37,7 @@
#include "nsChannelPolicy.h" #include "nsChannelPolicy.h"
nsChannelPolicy::nsChannelPolicy() nsChannelPolicy::nsChannelPolicy()
: mLoadType(0)
{ {
} }

View File

@ -79,7 +79,6 @@
#include "nsIScriptSecurityManager.h" #include "nsIScriptSecurityManager.h"
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeItem.h"
#include "nsRange.h"
#include "nsIWebBrowserPersist.h" #include "nsIWebBrowserPersist.h"
#include "nsEscape.h" #include "nsEscape.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
@ -92,9 +91,7 @@
#define kHTMLContext "text/_moz_htmlcontext" #define kHTMLContext "text/_moz_htmlcontext"
#define kHTMLInfo "text/_moz_htmlinfo" #define kHTMLInfo "text/_moz_htmlinfo"
nsresult NS_NewDomSelection(nsISelection **aDomSelection); // if aNode is null, use the selection from the window
// if inNode is null, use the selection from the window
static nsresult static nsresult
GetTransferableForNodeOrSelection(nsIDOMWindow* aWindow, GetTransferableForNodeOrSelection(nsIDOMWindow* aWindow,
nsIContent* aNode, nsIContent* aNode,
@ -108,25 +105,15 @@ GetTransferableForNodeOrSelection(nsIDOMWindow* aWindow,
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
nsresult rv; nsresult rv;
nsCOMPtr<nsISelection> selection; if (aNode) {
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode); rv = nsCopySupport::GetTransferableForNode(aNode, doc, aTransferable);
if (node) {
// Make a temporary selection with this node in a single range.
rv = NS_NewDomSelection(getter_AddRefs(selection));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMRange> range;
rv = NS_NewRange(getter_AddRefs(range));
NS_ENSURE_SUCCESS(rv, rv);
rv = range->SelectNode(node);
NS_ENSURE_SUCCESS(rv, rv);
rv = selection->AddRange(range);
NS_ENSURE_SUCCESS(rv, rv);
} else { } else {
nsCOMPtr<nsISelection> selection;
aWindow->GetSelection(getter_AddRefs(selection)); aWindow->GetSelection(getter_AddRefs(selection));
rv = nsCopySupport::GetTransferableForSelection(selection, doc,
aTransferable);
} }
rv = nsCopySupport::GetTransferableForSelection(selection, doc,
aTransferable);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return rv; return rv;
} }
@ -424,7 +411,6 @@ DragDataProducer::GetNodeString(nsIContent* inNode,
} }
} }
nsresult nsresult
DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer, DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
PRBool* aCanDrag, PRBool* aCanDrag,

View File

@ -2415,7 +2415,8 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
NS_PRECONDITION(aLoadingPrincipal, "Must have a principal"); NS_PRECONDITION(aLoadingPrincipal, "Must have a principal");
NS_PRECONDITION(aRequest, "Null out param"); NS_PRECONDITION(aRequest, "Null out param");
if (!sImgLoader) { imgILoader* imgLoader = GetImgLoader();
if (!imgLoader) {
// nothing we can do here // nothing we can do here
return NS_OK; return NS_OK;
} }
@ -2444,17 +2445,17 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
// XXXbz using "documentURI" for the initialDocumentURI is not quite // XXXbz using "documentURI" for the initialDocumentURI is not quite
// right, but the best we can do here... // right, but the best we can do here...
return sImgLoader->LoadImage(aURI, /* uri to load */ return imgLoader->LoadImage(aURI, /* uri to load */
documentURI, /* initialDocumentURI */ documentURI, /* initialDocumentURI */
aReferrer, /* referrer */ aReferrer, /* referrer */
loadGroup, /* loadgroup */ loadGroup, /* loadgroup */
aObserver, /* imgIDecoderObserver */ aObserver, /* imgIDecoderObserver */
aLoadingDocument, /* uniquification key */ aLoadingDocument, /* uniquification key */
aLoadFlags, /* load flags */ aLoadFlags, /* load flags */
nsnull, /* cache key */ nsnull, /* cache key */
nsnull, /* existing request*/ nsnull, /* existing request*/
channelPolicy, /* CSP info */ channelPolicy, /* CSP info */
aRequest); aRequest);
} }
// static // static

View File

@ -50,6 +50,7 @@
#include "nsXPCOM.h" #include "nsXPCOM.h"
#include "nsISupportsPrimitives.h" #include "nsISupportsPrimitives.h"
#include "nsIDOMRange.h" #include "nsIDOMRange.h"
#include "nsRange.h"
#include "imgIContainer.h" #include "imgIContainer.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "nsFocusManager.h" #include "nsFocusManager.h"
@ -78,6 +79,8 @@
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsContentCID.h" #include "nsContentCID.h"
nsresult NS_NewDomSelection(nsISelection **aDomSelection);
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID); static NS_DEFINE_CID(kCTransferableCID, NS_TRANSFERABLE_CID);
static NS_DEFINE_CID(kHTMLConverterCID, NS_HTMLFORMATCONVERTER_CID); static NS_DEFINE_CID(kHTMLConverterCID, NS_HTMLFORMATCONVERTER_CID);
@ -100,7 +103,7 @@ static nsresult AppendDOMNode(nsITransferable *aTransferable,
static nsresult static nsresult
SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc, SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
PRBool doPutOnClipboard, PRInt16 aClipboardID, PRBool doPutOnClipboard, PRInt16 aClipboardID,
nsITransferable ** aTransferable) PRUint32 aFlags, nsITransferable ** aTransferable)
{ {
// Clear the output parameter for the transferable, if provided. // Clear the output parameter for the transferable, if provided.
if (aTransferable) { if (aTransferable) {
@ -135,9 +138,8 @@ SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
// we want preformatted for the case where the selection is inside input/textarea // we want preformatted for the case where the selection is inside input/textarea
// and we don't want pretty printing for others cases, to not have additionnal // and we don't want pretty printing for others cases, to not have additionnal
// line breaks which are then converted into spaces by the htmlConverter (see bug #524975) // line breaks which are then converted into spaces by the htmlConverter (see bug #524975)
PRUint32 flags = nsIDocumentEncoder::OutputPreformatted PRUint32 flags = aFlags | nsIDocumentEncoder::OutputPreformatted
| nsIDocumentEncoder::OutputRaw | nsIDocumentEncoder::OutputRaw;
| nsIDocumentEncoder::SkipInvisibleContent;
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc); nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDoc);
NS_ASSERTION(domDoc, "Need a document"); NS_ASSERTION(domDoc, "Need a document");
@ -178,7 +180,7 @@ SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
mimeType.AssignLiteral(kHTMLMime); mimeType.AssignLiteral(kHTMLMime);
flags = nsIDocumentEncoder::SkipInvisibleContent; flags = aFlags;
rv = docEncoder->Init(domDoc, mimeType, flags); rv = docEncoder->Init(domDoc, mimeType, flags);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
@ -279,17 +281,47 @@ SelectionCopyHelper(nsISelection *aSel, nsIDocument *aDoc,
return rv; return rv;
} }
nsresult nsCopySupport::HTMLCopy(nsISelection *aSel, nsIDocument *aDoc, PRInt16 aClipboardID) nsresult
nsCopySupport::HTMLCopy(nsISelection* aSel, nsIDocument* aDoc,
PRInt16 aClipboardID)
{ {
return SelectionCopyHelper(aSel, aDoc, PR_TRUE, aClipboardID, nsnull); return SelectionCopyHelper(aSel, aDoc, PR_TRUE, aClipboardID,
nsIDocumentEncoder::SkipInvisibleContent,
nsnull);
} }
nsresult nsresult
nsCopySupport::GetTransferableForSelection(nsISelection * aSel, nsCopySupport::GetTransferableForSelection(nsISelection* aSel,
nsIDocument * aDoc, nsIDocument* aDoc,
nsITransferable ** aTransferable) nsITransferable** aTransferable)
{ {
return SelectionCopyHelper(aSel, aDoc, PR_FALSE, 0, aTransferable); return SelectionCopyHelper(aSel, aDoc, PR_FALSE, 0,
nsIDocumentEncoder::SkipInvisibleContent,
aTransferable);
}
nsresult
nsCopySupport::GetTransferableForNode(nsINode* aNode,
nsIDocument* aDoc,
nsITransferable** aTransferable)
{
nsCOMPtr<nsISelection> selection;
// Make a temporary selection with aNode in a single range.
nsresult rv = NS_NewDomSelection(getter_AddRefs(selection));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMRange> range;
rv = NS_NewRange(getter_AddRefs(range));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode);
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
rv = range->SelectNode(node);
NS_ENSURE_SUCCESS(rv, rv);
rv = selection->AddRange(range);
NS_ENSURE_SUCCESS(rv, rv);
// It's not the primary selection - so don't skip invisible content.
PRUint32 flags = 0;
return SelectionCopyHelper(selection, aDoc, PR_FALSE, 0, flags,
aTransferable);
} }
nsresult nsCopySupport::DoHooks(nsIDocument *aDoc, nsITransferable *aTrans, nsresult nsCopySupport::DoHooks(nsIDocument *aDoc, nsITransferable *aTrans,

View File

@ -195,6 +195,7 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
// FOR CSP (autogenerated by xpidl) // FOR CSP (autogenerated by xpidl)
#include "nsIContentSecurityPolicy.h" #include "nsIContentSecurityPolicy.h"
#include "nsCSPService.h"
#include "nsHTMLStyleSheet.h" #include "nsHTMLStyleSheet.h"
#include "nsHTMLCSSStyleSheet.h" #include "nsHTMLCSSStyleSheet.h"
@ -202,9 +203,6 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
using namespace mozilla::dom; using namespace mozilla::dom;
/* Keeps track of whether or not CSP is enabled */
static PRBool gCSPEnabled = PR_TRUE;
#ifdef PR_LOGGING #ifdef PR_LOGGING
static PRLogModuleInfo* gDocumentLeakPRLog; static PRLogModuleInfo* gDocumentLeakPRLog;
static PRLogModuleInfo* gCspPRLog; static PRLogModuleInfo* gCspPRLog;
@ -1409,8 +1407,6 @@ nsDocument::nsDocument(const char* aContentType)
gCspPRLog = PR_NewLogModule("CSP"); gCspPRLog = PR_NewLogModule("CSP");
#endif #endif
nsContentUtils::AddBoolPrefVarCache("security.csp.enable", &gCSPEnabled);
// Start out mLastStyleSheetSet as null, per spec // Start out mLastStyleSheetSet as null, per spec
SetDOMStringToNull(mLastStyleSheetSet); SetDOMStringToNull(mLastStyleSheetSet);
} }
@ -2175,7 +2171,7 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
nsresult nsresult
nsDocument::InitCSP() nsDocument::InitCSP()
{ {
if (gCSPEnabled) { if (CSPService::sCSPEnabled) {
nsAutoString cspHeaderValue; nsAutoString cspHeaderValue;
nsAutoString cspROHeaderValue; nsAutoString cspROHeaderValue;

View File

@ -61,7 +61,7 @@ bool SendSyncMessageToParent(void* aCallbackData,
nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages; nsTArray<nsCOMPtr<nsIRunnable> > asyncMessages;
asyncMessages.SwapElements(tabChild->mASyncMessages); asyncMessages.SwapElements(tabChild->mASyncMessages);
PRUint32 len = asyncMessages.Length(); PRUint32 len = asyncMessages.Length();
for (PRInt32 i = 0; i < len; ++i) { for (PRUint32 i = 0; i < len; ++i) {
nsCOMPtr<nsIRunnable> async = asyncMessages[i]; nsCOMPtr<nsIRunnable> async = asyncMessages[i];
async->Run(); async->Run();
} }
@ -286,8 +286,9 @@ nsInProcessTabChildGlobal::InitTabChildGlobal()
nsresult rv = nsresult rv =
xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports, xpc->InitClassesWithNewWrappedGlobal(cx, scopeSupports,
NS_GET_IID(nsISupports), flags, NS_GET_IID(nsISupports),
getter_AddRefs(mGlobal)); GetPrincipal(), EmptyCString(),
flags, getter_AddRefs(mGlobal));
NS_ENSURE_SUCCESS(rv, false); NS_ENSURE_SUCCESS(rv, false);
JSObject* global = nsnull; JSObject* global = nsnull;

View File

@ -1360,8 +1360,7 @@ nsXMLHttpRequest::GetAllResponseHeaders(char **_retval)
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel(); nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
if (httpChannel) { if (httpChannel) {
nsHeaderVisitor *visitor = nsnull; nsHeaderVisitor *visitor = new nsHeaderVisitor();
NS_NEWXPCOM(visitor, nsHeaderVisitor);
if (!visitor) if (!visitor)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(visitor); NS_ADDREF(visitor);

View File

@ -402,6 +402,7 @@ _TEST_FILES2 = \
test_websocket.html \ test_websocket.html \
file_websocket_wsh.py \ file_websocket_wsh.py \
file_websocket_http_resource.txt \ file_websocket_http_resource.txt \
test_bug574596.html \
$(NULL) $(NULL)
# This test fails on the Mac for some reason # This test fails on the Mac for some reason

View File

@ -0,0 +1,86 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=574596
-->
<head>
<title>Test for Bug 574596</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=574596">Mozilla Bug 574596</a>
<style type="text/css">
#link1 a { -moz-user-select:none; }
</style>
<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>
<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 574596 **/
function ignoreFunc(actualData, expectedData) {
return true;
}
var dragLinkText = [[
{ type:"text/x-moz-url", data:"", eqTest:ignoreFunc },
{ type:"text/x-moz-url-data", data:"http://www.mozilla.org/" },
{ type:"text/x-moz-url-desc", data:"link1" },
{ type:"text/uri-list", data:"http://www.mozilla.org/" },
{ type:"text/_moz_htmlcontext", data:"", eqTest:ignoreFunc },
{ type:"text/_moz_htmlinfo", data:"", eqTest:ignoreFunc },
{ type:"text/html", data:'<div id="link1"><a href="http://www.mozilla.org/">link1</a></div>' },
{ type:"text/plain", data:"http://www.mozilla.org/" }
]];
function dumpTransfer(dataTransfer,expect) {
dtData = dataTransfer.mozItemCount + "items:\n";
for (var i = 0; i < dataTransfer.mozItemCount; i++) {
var dtTypes = dataTransfer.mozTypesAt(i);
for (var j = 0; j < dtTypes.length; j++) {
var actualData = dataTransfer.mozGetDataAt(dtTypes[j],i)
if (expect && expect[i] && expect[i][j]) {
if (expect[i][j].eqTest)
dtData += expect[i][j].eqTest(actualData,expect[i][j].data) ? "ok" : "fail";
else
dtData += (actualData == expect[i][j].data) ? "ok" : "fail";
}
dtData += "["+i+"]" + "["+j+"]: " + '"' + dtTypes[j] + '" "' + actualData + '"\n';
}
}
alert(dtData);
}
function runTest() {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var result = synthesizeDragStart($('link1'), dragLinkText, window);
is(result, null, "Drag -moz-user-select:none link (#link1)");
// if (result) dumpTransfer(result,dragLinkText);
dragLinkText[0][2].data = "link2";
dragLinkText[0][6].data = '<div id="link2"><a href="http://www.mozilla.org/">link2</a></div>'
var result = synthesizeDragStart($('link2'), dragLinkText, window);
is(result, null, "Drag link (#link2)");
// if (result) dumpTransfer(result,dragLinkText);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(runTest);
</script>
</pre>
</body>
</html>

View File

@ -262,7 +262,7 @@ try {
} catch(ex) { } catch(ex) {
didThrow = true; didThrow = true;
} }
// Once this test passes, we shoud test that onerror gets called and // Once this test passes, we should test that onerror gets called and
// that the FileReader object is in the right state during that call. // that the FileReader object is in the right state during that call.
todo(!didThrow, "shouldn't throw when opening nonexistent file, should fire error instead"); todo(!didThrow, "shouldn't throw when opening nonexistent file, should fire error instead");

View File

@ -63,7 +63,21 @@ function shouldNotOpen(e)
function shouldNotReceiveCloseEvent(e) function shouldNotReceiveCloseEvent(e)
{ {
var ws = e.target; var ws = e.target;
ok(false, "onclose shouldn't be called on test " + ws._testNumber + "!"); var extendedErrorInfo = "";
if (!ws._testNumber) {
extendedErrorInfo += "\nws members:\n";
for (var i in ws) {
extendedErrorInfo += (i + ": " + ws[i] + "\n");
}
extendedErrorInfo += "\ne members:\n";
for (var i in e) {
extendedErrorInfo += (i + ": " + e[i] + "\n");
}
}
// FIXME: see bug 578276. This should be a test failure, but it's too flaky on the tbox.
ok(true, "onclose shouldn't be called on test " + ws._testNumber + "!" + extendedErrorInfo);
} }
function shouldCloseCleanly(e) function shouldCloseCleanly(e)
@ -89,12 +103,15 @@ function CreateTestWS(ws_location, ws_protocol)
ws = new WebSocket(ws_location, ws_protocol); ws = new WebSocket(ws_location, ws_protocol);
} }
ws._testNumber = current_test;
ws._receivedCloseEvent = false;
ok(true, "added testNumber: " + ws._testNumber +"\n");
ws.onerror = function(e) ws.onerror = function(e)
{ {
ok(false, "onerror called on test " + e.target._testNumber + "!"); ok(false, "onerror called on test " + e.target._testNumber + "!");
}; };
ws._testNumber = current_test;
ws._receivedCloseEvent = false;
ws.addEventListener("close", function(e) ws.addEventListener("close", function(e)
{ {
ws._receivedCloseEvent = true; ws._receivedCloseEvent = true;
@ -419,6 +436,7 @@ var status_test17 = "not started";
window._test17 = function() window._test17 = function()
{ {
var local_ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 17"); var local_ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 17");
local_ws._testNumber = "local17";
current_test++; current_test++;
status_test17 = "started"; status_test17 = "started";
@ -491,6 +509,7 @@ function test19()
window._test20 = function() window._test20 = function()
{ {
var local_ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 20"); var local_ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 20");
local_ws._testNumber = "local20";
current_test++; current_test++;
local_ws.onerror = function() local_ws.onerror = function()

View File

@ -138,8 +138,8 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
// If incrementing the generation would cause overflow, // If incrementing the generation would cause overflow,
// don't allow it. Allowing this would allow us to use // don't allow it. Allowing this would allow us to use
// resource handles created from older context generations. // resource handles created from older context generations.
if (mGeneration + 1 == 0) if (!(mGeneration+1).valid())
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
if (mWidth == width && mHeight == height) if (mWidth == width && mHeight == height)
return NS_OK; return NS_OK;
@ -181,7 +181,7 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
mHeight = height; mHeight = height;
// increment the generation number // increment the generation number
mGeneration++; ++mGeneration;
MakeContextCurrent(); MakeContextCurrent();

View File

@ -60,6 +60,8 @@
#include "GLContext.h" #include "GLContext.h"
#include "Layers.h" #include "Layers.h"
#include "CheckedInt.h"
#define UNPACK_FLIP_Y_WEBGL 0x9240 #define UNPACK_FLIP_Y_WEBGL 0x9240
#define UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241 #define UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241
#define CONTEXT_LOST_WEBGL 0x9242 #define CONTEXT_LOST_WEBGL 0x9242
@ -307,7 +309,7 @@ public:
// a number that increments every time we have an event that causes // a number that increments every time we have an event that causes
// all context resources to be lost. // all context resources to be lost.
PRUint32 Generation() { return mGeneration; } PRUint32 Generation() { return mGeneration.value(); }
protected: protected:
nsCOMPtr<nsIDOMHTMLCanvasElement> mCanvasElement; nsCOMPtr<nsIDOMHTMLCanvasElement> mCanvasElement;
nsHTMLCanvasElement *HTMLCanvasElement() { nsHTMLCanvasElement *HTMLCanvasElement() {
@ -317,7 +319,7 @@ protected:
nsRefPtr<gl::GLContext> gl; nsRefPtr<gl::GLContext> gl;
PRInt32 mWidth, mHeight; PRInt32 mWidth, mHeight;
PRUint32 mGeneration; CheckedUint32 mGeneration;
PRBool mInvalidated; PRBool mInvalidated;
@ -335,6 +337,7 @@ protected:
PRBool ValidateComparisonEnum(WebGLenum target, const char *info); PRBool ValidateComparisonEnum(WebGLenum target, const char *info);
PRBool ValidateStencilOpEnum(WebGLenum action, const char *info); PRBool ValidateStencilOpEnum(WebGLenum action, const char *info);
PRBool ValidateFaceEnum(WebGLenum target, const char *info); PRBool ValidateFaceEnum(WebGLenum target, const char *info);
PRBool ValidateBufferUsageEnum(WebGLenum target, const char *info);
PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type, PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type,
PRUint32 *texelSize, const char *info); PRUint32 *texelSize, const char *info);
@ -705,7 +708,7 @@ public:
WebGLuint GLName() { return mName; } WebGLuint GLName() { return mName; }
const nsTArray<WebGLShader*>& AttachedShaders() const { return mAttachedShaders; } const nsTArray<WebGLShader*>& AttachedShaders() const { return mAttachedShaders; }
PRBool LinkStatus() { return mLinkStatus; } PRBool LinkStatus() { return mLinkStatus; }
GLuint Generation() const { return mGeneration; } PRUint32 Generation() const { return mGeneration.value(); }
void SetLinkStatus(PRBool val) { mLinkStatus = val; } void SetLinkStatus(PRBool val) { mLinkStatus = val; }
PRBool ContainsShader(WebGLShader *shader) { PRBool ContainsShader(WebGLShader *shader) {
@ -742,10 +745,9 @@ public:
PRBool NextGeneration() PRBool NextGeneration()
{ {
GLuint nextGeneration = mGeneration + 1; if (!(mGeneration+1).valid())
if (nextGeneration == 0)
return PR_FALSE; // must exit without changing mGeneration return PR_FALSE; // must exit without changing mGeneration
mGeneration = nextGeneration; ++mGeneration;
mMapUniformLocations.Clear(); mMapUniformLocations.Clear();
return PR_TRUE; return PR_TRUE;
} }
@ -770,7 +772,7 @@ protected:
PRPackedBool mLinkStatus; PRPackedBool mLinkStatus;
nsTArray<WebGLShader*> mAttachedShaders; nsTArray<WebGLShader*> mAttachedShaders;
nsRefPtrHashtable<nsUint32HashKey, WebGLUniformLocation> mMapUniformLocations; nsRefPtrHashtable<nsUint32HashKey, WebGLUniformLocation> mMapUniformLocations;
GLuint mGeneration; CheckedUint32 mGeneration;
GLint mUniformMaxNameLength; GLint mUniformMaxNameLength;
GLint mAttribMaxNameLength; GLint mAttribMaxNameLength;
GLint mUniformCount; GLint mUniformCount;
@ -864,7 +866,7 @@ public:
WebGLProgram *Program() const { return mProgram; } WebGLProgram *Program() const { return mProgram; }
GLint Location() const { return mLocation; } GLint Location() const { return mLocation; }
GLuint ProgramGeneration() const { return mProgramGeneration; } PRUint32 ProgramGeneration() const { return mProgramGeneration; }
// needed for our generic helpers to check nsIxxx parameters, see GetConcreteObject. // needed for our generic helpers to check nsIxxx parameters, see GetConcreteObject.
PRBool Deleted() { return PR_FALSE; } PRBool Deleted() { return PR_FALSE; }
@ -873,7 +875,7 @@ public:
NS_DECL_NSIWEBGLUNIFORMLOCATION NS_DECL_NSIWEBGLUNIFORMLOCATION
protected: protected:
WebGLObjectRefPtr<WebGLProgram> mProgram; WebGLObjectRefPtr<WebGLProgram> mProgram;
GLuint mProgramGeneration; PRUint32 mProgramGeneration;
GLint mLocation; GLint mLocation;
}; };

View File

@ -125,21 +125,6 @@ WebGLContext::Present()
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
/* long sizeInBytes (in GLenum type); */
NS_IMETHODIMP
WebGLContext::SizeInBytes(WebGLenum type, PRInt32 *retval)
{
if (type == LOCAL_GL_FLOAT) *retval = sizeof(float);
if (type == LOCAL_GL_SHORT) *retval = sizeof(short);
if (type == LOCAL_GL_UNSIGNED_SHORT) *retval = sizeof(unsigned short);
if (type == LOCAL_GL_BYTE) *retval = 1;
if (type == LOCAL_GL_UNSIGNED_BYTE) *retval = 1;
if (type == LOCAL_GL_INT) *retval = sizeof(int);
if (type == LOCAL_GL_UNSIGNED_INT) *retval = sizeof(unsigned int);
if (type == LOCAL_GL_DOUBLE) *retval = sizeof(double);
return NS_OK;
}
/* void GlActiveTexture (in GLenum texture); */ /* void GlActiveTexture (in GLenum texture); */
NS_IMETHODIMP NS_IMETHODIMP
WebGLContext::ActiveTexture(WebGLenum texture) WebGLContext::ActiveTexture(WebGLenum texture)
@ -292,7 +277,7 @@ WebGLContext::BindTexture(WebGLenum target, nsIWebGLTexture *tobj)
return NS_OK; return NS_OK;
} }
GL_SAME_METHOD_4(BlendColor, BlendColor, float, float, float, float) GL_SAME_METHOD_4(BlendColor, BlendColor, WebGLfloat, WebGLfloat, WebGLfloat, WebGLfloat)
NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode) NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode)
{ {
@ -362,6 +347,12 @@ WebGLContext::BufferData_size(WebGLenum target, WebGLsizei size, WebGLenum usage
return ErrorInvalidEnum("BufferData: invalid target"); return ErrorInvalidEnum("BufferData: invalid target");
} }
if (size < 0)
return ErrorInvalidValue("bufferData: negative size");
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
return NS_OK;
if (!boundBuffer) if (!boundBuffer)
return ErrorInvalidOperation("BufferData: no buffer bound!"); return ErrorInvalidOperation("BufferData: no buffer bound!");
@ -388,6 +379,9 @@ WebGLContext::BufferData_buf(WebGLenum target, js::ArrayBuffer *wb, WebGLenum us
return ErrorInvalidEnum("BufferData: invalid target"); return ErrorInvalidEnum("BufferData: invalid target");
} }
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
return NS_OK;
if (!boundBuffer) if (!boundBuffer)
return ErrorInvalidOperation("BufferData: no buffer bound!"); return ErrorInvalidOperation("BufferData: no buffer bound!");
@ -414,6 +408,9 @@ WebGLContext::BufferData_array(WebGLenum target, js::TypedArray *wa, WebGLenum u
return ErrorInvalidEnum("BufferData: invalid target"); return ErrorInvalidEnum("BufferData: invalid target");
} }
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
return NS_OK;
if (!boundBuffer) if (!boundBuffer)
return ErrorInvalidOperation("BufferData: no buffer bound!"); return ErrorInvalidOperation("BufferData: no buffer bound!");
@ -449,8 +446,11 @@ WebGLContext::BufferSubData_buf(GLenum target, WebGLsizei byteOffset, js::ArrayB
if (!boundBuffer) if (!boundBuffer)
return ErrorInvalidOperation("BufferData: no buffer bound!"); return ErrorInvalidOperation("BufferData: no buffer bound!");
// XXX check for overflow CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + wb->byteLength;
if (byteOffset + wb->byteLength > boundBuffer->ByteLength()) if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
if (checked_neededByteLength.value() > boundBuffer->ByteLength())
return ErrorInvalidOperation("BufferSubData: not enough data - operation requires %d bytes, but buffer only has %d bytes", return ErrorInvalidOperation("BufferSubData: not enough data - operation requires %d bytes, but buffer only has %d bytes",
byteOffset, wb->byteLength, boundBuffer->ByteLength()); byteOffset, wb->byteLength, boundBuffer->ByteLength());
@ -479,8 +479,11 @@ WebGLContext::BufferSubData_array(WebGLenum target, WebGLsizei byteOffset, js::T
if (!boundBuffer) if (!boundBuffer)
return ErrorInvalidOperation("BufferData: no buffer bound!"); return ErrorInvalidOperation("BufferData: no buffer bound!");
// XXX check for overflow CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + wa->byteLength;
if (byteOffset + wa->byteLength > boundBuffer->ByteLength()) if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
if (checked_neededByteLength.value() > boundBuffer->ByteLength())
return ErrorInvalidOperation("BufferSubData: not enough data -- operation requires %d bytes, but buffer only has %d bytes", return ErrorInvalidOperation("BufferSubData: not enough data -- operation requires %d bytes, but buffer only has %d bytes",
byteOffset, wa->byteLength, boundBuffer->ByteLength()); byteOffset, wa->byteLength, boundBuffer->ByteLength());
@ -512,15 +515,15 @@ WebGLContext::Clear(PRUint32 mask)
return NS_OK; return NS_OK;
} }
GL_SAME_METHOD_4(ClearColor, ClearColor, float, float, float, float) GL_SAME_METHOD_4(ClearColor, ClearColor, WebGLfloat, WebGLfloat, WebGLfloat, WebGLfloat)
#ifdef USE_GLES2 #ifdef USE_GLES2
GL_SAME_METHOD_1(ClearDepthf, ClearDepth, float) GL_SAME_METHOD_1(ClearDepthf, ClearDepth, WebGLfloat)
#else #else
GL_SAME_METHOD_1(ClearDepth, ClearDepth, float) GL_SAME_METHOD_1(ClearDepth, ClearDepth, WebGLfloat)
#endif #endif
GL_SAME_METHOD_1(ClearStencil, ClearStencil, PRInt32) GL_SAME_METHOD_1(ClearStencil, ClearStencil, WebGLint)
GL_SAME_METHOD_4(ColorMask, ColorMask, WebGLboolean, WebGLboolean, WebGLboolean, WebGLboolean) GL_SAME_METHOD_4(ColorMask, ColorMask, WebGLboolean, WebGLboolean, WebGLboolean, WebGLboolean)
@ -640,7 +643,16 @@ WebGLContext::CreateShader(WebGLenum type, nsIWebGLShader **retval)
return NS_OK; return NS_OK;
} }
GL_SAME_METHOD_1(CullFace, CullFace, WebGLenum) NS_IMETHODIMP
WebGLContext::CullFace(WebGLenum face)
{
if (!ValidateFaceEnum(face, "cullFace"))
return NS_OK;
MakeContextCurrent();
gl->fCullFace(face);
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
WebGLContext::DeleteBuffer(nsIWebGLBuffer *bobj) WebGLContext::DeleteBuffer(nsIWebGLBuffer *bobj)
@ -816,9 +828,9 @@ WebGLContext::DepthFunc(WebGLenum func)
GL_SAME_METHOD_1(DepthMask, DepthMask, WebGLboolean) GL_SAME_METHOD_1(DepthMask, DepthMask, WebGLboolean)
#ifdef USE_GLES2 #ifdef USE_GLES2
GL_SAME_METHOD_2(DepthRangef, DepthRange, float, float) GL_SAME_METHOD_2(DepthRangef, DepthRange, WebGLfloat, WebGLfloat)
#else #else
GL_SAME_METHOD_2(DepthRange, DepthRange, float, float) GL_SAME_METHOD_2(DepthRange, DepthRange, WebGLfloat, WebGLfloat)
#endif #endif
NS_IMETHODIMP NS_IMETHODIMP
@ -863,10 +875,12 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
if (!mCurrentProgram) if (!mCurrentProgram)
return NS_OK; return NS_OK;
if (first+count < first || first+count < count) CheckedInt32 checked_firstPlusCount = CheckedInt32(first) + count;
return ErrorInvalidOperation("DrawArrays: overflow in first+count");
if (!ValidateBuffers(first+count)) if (!checked_firstPlusCount.valid())
return ErrorInvalidOperation("drawArrays: overflow in first+count");
if (!ValidateBuffers(checked_firstPlusCount.value()))
return ErrorInvalidOperation("DrawArrays: bound vertex attribute buffers do not have sufficient data for given first and count"); return ErrorInvalidOperation("DrawArrays: bound vertex attribute buffers do not have sufficient data for given first and count");
MakeContextCurrent(); MakeContextCurrent();
@ -897,20 +911,21 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
if (count < 0 || byteOffset < 0) if (count < 0 || byteOffset < 0)
return ErrorInvalidValue("DrawElements: negative count or offset"); return ErrorInvalidValue("DrawElements: negative count or offset");
WebGLuint byteCount; CheckedUint32 checked_byteCount;
if (type == LOCAL_GL_UNSIGNED_SHORT) {
byteCount = WebGLuint(count) << 1;
if (byteCount >> 1 != WebGLuint(count))
return ErrorInvalidValue("DrawElements: overflow in byteCount");
if (type == LOCAL_GL_UNSIGNED_SHORT) {
checked_byteCount = 2 * CheckedUint32(count);
if (byteOffset % 2 != 0) if (byteOffset % 2 != 0)
return ErrorInvalidValue("DrawElements: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)"); return ErrorInvalidValue("DrawElements: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)");
} else if (type == LOCAL_GL_UNSIGNED_BYTE) { } else if (type == LOCAL_GL_UNSIGNED_BYTE) {
byteCount = count; checked_byteCount = count;
} else { } else {
return ErrorInvalidEnum("DrawElements: type must be UNSIGNED_SHORT or UNSIGNED_BYTE"); return ErrorInvalidEnum("DrawElements: type must be UNSIGNED_SHORT or UNSIGNED_BYTE");
} }
if (!checked_byteCount.valid())
return ErrorInvalidValue("DrawElements: overflow in byteCount");
// If count is 0, there's nothing to do. // If count is 0, there's nothing to do.
if (count == 0) if (count == 0)
return NS_OK; return NS_OK;
@ -923,10 +938,12 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
if (!mBoundElementArrayBuffer) if (!mBoundElementArrayBuffer)
return ErrorInvalidOperation("DrawElements: must have element array buffer binding"); return ErrorInvalidOperation("DrawElements: must have element array buffer binding");
if (byteOffset+byteCount < WebGLuint(byteOffset) || byteOffset+byteCount < byteCount) CheckedUint32 checked_neededByteCount = checked_byteCount + byteOffset;
if (!checked_neededByteCount.valid())
return ErrorInvalidOperation("DrawElements: overflow in byteOffset+byteCount"); return ErrorInvalidOperation("DrawElements: overflow in byteOffset+byteCount");
if (byteOffset + byteCount > mBoundElementArrayBuffer->ByteLength()) if (checked_neededByteCount.value() > mBoundElementArrayBuffer->ByteLength())
return ErrorInvalidOperation("DrawElements: bound element array buffer is too small for given count and offset"); return ErrorInvalidOperation("DrawElements: bound element array buffer is too small for given count and offset");
WebGLuint maxIndex = 0; WebGLuint maxIndex = 0;
@ -936,8 +953,13 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
maxIndex = mBoundElementArrayBuffer->FindMaximum<GLubyte>(count, byteOffset); maxIndex = mBoundElementArrayBuffer->FindMaximum<GLubyte>(count, byteOffset);
} }
// maxIndex+1 because ValidateBuffers expects the number of elements needed // maxIndex+1 because ValidateBuffers expects the number of elements needed.
if (!ValidateBuffers(maxIndex+1)) { // it is very important here to check tha maxIndex+1 doesn't overflow, otherwise the buffer validation is bypassed !!!
// maxIndex is a WebGLuint, ValidateBuffers takes a PRUint32, we validate maxIndex+1 as a PRUint32.
CheckedUint32 checked_neededCount = CheckedUint32(maxIndex) + 1;
if (!checked_neededCount.valid())
return ErrorInvalidOperation("drawElements: overflow in maxIndex+1");
if (!ValidateBuffers(checked_neededCount.value())) {
return ErrorInvalidOperation("DrawElements: bound vertex attribute buffers do not have sufficient " return ErrorInvalidOperation("DrawElements: bound vertex attribute buffers do not have sufficient "
"data for given indices from the bound element array"); "data for given indices from the bound element array");
} }
@ -1306,14 +1328,7 @@ WebGLContext::GetParameter(PRUint32 pname, nsIVariant **retval)
break; break;
#define LOCAL_GL_MAX_VARYING_VECTORS 0x8dfc // not present in desktop OpenGL #define LOCAL_GL_MAX_VARYING_VECTORS 0x8dfc // not present in desktop OpenGL
// temporarily add those defs here, as they're missing from
// gfx/thebes/public/GLDefs.h
// and from
// gfx/layers/opengl/glDefs.h
// and I don't know in which of these 2 files they should go (probably we're going to
// kill one of them soon?)
#define LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
#define LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
case LOCAL_GL_MAX_VARYING_VECTORS: case LOCAL_GL_MAX_VARYING_VECTORS:
{ {
#ifdef USE_GLES2 #ifdef USE_GLES2
@ -2117,7 +2132,7 @@ WebGLContext::IsEnabled(WebGLenum cap, WebGLboolean *retval)
return NS_OK; return NS_OK;
} }
GL_SAME_METHOD_1(LineWidth, LineWidth, float) GL_SAME_METHOD_1(LineWidth, LineWidth, WebGLfloat)
NS_IMETHODIMP NS_IMETHODIMP
WebGLContext::LinkProgram(nsIWebGLProgram *pobj) WebGLContext::LinkProgram(nsIWebGLProgram *pobj)
@ -2179,7 +2194,7 @@ WebGLContext::PixelStorei(WebGLenum pname, WebGLint param)
} }
GL_SAME_METHOD_2(PolygonOffset, PolygonOffset, float, float) GL_SAME_METHOD_2(PolygonOffset, PolygonOffset, WebGLfloat, WebGLfloat)
NS_IMETHODIMP NS_IMETHODIMP
WebGLContext::ReadPixels(PRInt32 dummy) WebGLContext::ReadPixels(PRInt32 dummy)
@ -2232,16 +2247,19 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
PRUint32 packAlignment; PRUint32 packAlignment;
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*) &packAlignment); gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*) &packAlignment);
PRUint32 plainRowSize = width*size; CheckedUint32 checked_plainRowSize = CheckedUint32(width) * size;
// alignedRowSize = row size rounded up to next multiple of // alignedRowSize = row size rounded up to next multiple of packAlignment
// packAlignment which is a power of 2 CheckedUint32 checked_alignedRowSize
PRUint32 alignedRowSize = (plainRowSize + packAlignment-1) & = ((checked_plainRowSize + packAlignment-1) / packAlignment) * packAlignment;
~PRUint32(packAlignment-1);
PRUint32 neededByteLength = (height-1)*alignedRowSize + plainRowSize; CheckedUint32 checked_neededByteLength
= (height-1) * checked_alignedRowSize + checked_plainRowSize;
if(neededByteLength > byteLength) if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
if (checked_neededByteLength.value() > byteLength)
return ErrorInvalidOperation("ReadPixels: buffer too small"); return ErrorInvalidOperation("ReadPixels: buffer too small");
if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, boundWidth, boundHeight)) { if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, boundWidth, boundHeight)) {
@ -2277,7 +2295,14 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
GLint subrect_end_y = PR_MIN(y+height, boundHeight); GLint subrect_end_y = PR_MIN(y+height, boundHeight);
GLsizei subrect_height = subrect_end_y - subrect_y; GLsizei subrect_height = subrect_end_y - subrect_y;
if (subrect_width < 0 || subrect_height < 0 ||
subrect_width > width || subrect_height)
return ErrorInvalidOperation("ReadPixels: integer overflow computing clipped rect size");
// now we know that subrect_width is in the [0..width] interval, and same for heights.
// now, same computation as above to find the size of the intermediate buffer to allocate for the subrect // now, same computation as above to find the size of the intermediate buffer to allocate for the subrect
// no need to check again for integer overflow here, since we already know the sizes aren't greater than before
PRUint32 subrect_plainRowSize = subrect_width * size; PRUint32 subrect_plainRowSize = subrect_width * size;
PRUint32 subrect_alignedRowSize = (subrect_plainRowSize + packAlignment-1) & PRUint32 subrect_alignedRowSize = (subrect_plainRowSize + packAlignment-1) &
~PRUint32(packAlignment-1); ~PRUint32(packAlignment-1);
@ -2286,11 +2311,13 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
// create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
GLubyte *subrect_data = new GLubyte[subrect_byteLength]; GLubyte *subrect_data = new GLubyte[subrect_byteLength];
gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, format, type, subrect_data); gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, format, type, subrect_data);
// notice that this for loop terminates because we already checked that subrect_height is at most height
for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) { for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
GLint subrect_x_in_dest_buffer = subrect_x - x; GLint subrect_x_in_dest_buffer = subrect_x - x;
GLint subrect_y_in_dest_buffer = subrect_y - y; GLint subrect_y_in_dest_buffer = subrect_y - y;
memcpy(static_cast<GLubyte*>(data) memcpy(static_cast<GLubyte*>(data)
+ alignedRowSize * (subrect_y_in_dest_buffer + y_inside_subrect) + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
+ size * subrect_x_in_dest_buffer, // destination + size * subrect_x_in_dest_buffer, // destination
subrect_data + subrect_alignedRowSize * y_inside_subrect, // source subrect_data + subrect_alignedRowSize * y_inside_subrect, // source
subrect_plainRowSize); // size subrect_plainRowSize); // size
@ -2353,14 +2380,19 @@ WebGLContext::ReadPixels_byteLength_old_API_deprecated(WebGLsizei width, WebGLsi
PRUint32 packAlignment; PRUint32 packAlignment;
gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*) &packAlignment); gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*) &packAlignment);
PRUint32 plainRowSize = width*size; CheckedUint32 checked_plainRowSize = CheckedUint32(width) * size;
// alignedRowSize = row size rounded up to next multiple of // alignedRowSize = row size rounded up to next multiple of
// packAlignment which is a power of 2 // packAlignment which is a power of 2
PRUint32 alignedRowSize = (plainRowSize + packAlignment-1) & CheckedUint32 checked_alignedRowSize
~PRUint32(packAlignment-1); = ((checked_plainRowSize + packAlignment-1) / packAlignment) * packAlignment;
*retval = (height-1)*alignedRowSize + plainRowSize; CheckedUint32 checked_neededByteLength = (height-1)*checked_alignedRowSize + checked_plainRowSize;
if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
*retval = checked_neededByteLength.value();
return NS_OK; return NS_OK;
} }
@ -2395,7 +2427,7 @@ WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, We
return NS_OK; return NS_OK;
} }
GL_SAME_METHOD_2(SampleCoverage, SampleCoverage, float, WebGLboolean) GL_SAME_METHOD_2(SampleCoverage, SampleCoverage, WebGLfloat, WebGLboolean)
NS_IMETHODIMP NS_IMETHODIMP
WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height) WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height)
@ -2943,9 +2975,6 @@ WebGLContext::VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type
if (size < 1 || size > 4) if (size < 1 || size > 4)
return ErrorInvalidValue("VertexAttribPointer: invalid element size"); return ErrorInvalidValue("VertexAttribPointer: invalid element size");
if (stride < 0)
return ErrorInvalidValue("VertexAttribPointer: stride cannot be negative");
/* XXX make work with bufferSubData & heterogeneous types /* XXX make work with bufferSubData & heterogeneous types
if (type != mBoundArrayBuffer->GLType()) if (type != mBoundArrayBuffer->GLType())
return ErrorInvalidOperation("VertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType()); return ErrorInvalidOperation("VertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType());
@ -3021,11 +3050,15 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
if (!ValidateTexFormatAndType(format, type, &texelSize, "texImage2D")) if (!ValidateTexFormatAndType(format, type, &texelSize, "texImage2D"))
return NS_OK; return NS_OK;
// XXX overflow! CheckedUint32 checked_bytesNeeded = CheckedUint32(width) * height * texelSize;
uint32 bytesNeeded = width * height * texelSize;
if (!checked_bytesNeeded.valid())
return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
PRUint32 bytesNeeded = checked_bytesNeeded.value();
if (byteLength && byteLength < bytesNeeded) if (byteLength && byteLength < bytesNeeded)
return ErrorInvalidValue("TexImage2D: not enough data for operation (need %d, have %d)", return ErrorInvalidOperation("TexImage2D: not enough data for operation (need %d, have %d)",
bytesNeeded, byteLength); bytesNeeded, byteLength);
MakeContextCurrent(); MakeContextCurrent();
@ -3154,8 +3187,13 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
if (width == 0 || height == 0) if (width == 0 || height == 0)
return NS_OK; // ES 2.0 says it has no effect, we better return right now return NS_OK; // ES 2.0 says it has no effect, we better return right now
// XXX overflow! CheckedUint32 checked_bytesNeeded = CheckedUint32(width) * height * texelSize;
uint32 bytesNeeded = width * height * texelSize;
if (!checked_bytesNeeded.valid())
return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
PRUint32 bytesNeeded = checked_bytesNeeded.value();
if (byteLength < bytesNeeded) if (byteLength < bytesNeeded)
return ErrorInvalidValue("TexSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength); return ErrorInvalidValue("TexSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);

View File

@ -39,6 +39,8 @@
#include "WebGLContext.h" #include "WebGLContext.h"
#include "CheckedInt.h"
using namespace mozilla; using namespace mozilla;
/* /*
@ -112,12 +114,18 @@ WebGLContext::ValidateBuffers(PRUint32 count)
continue; continue;
// compute the number of bytes we actually need // compute the number of bytes we actually need
WebGLuint needed = vd.byteOffset + // the base offset CheckedUint32 checked_needed = CheckedUint32(vd.byteOffset) + // the base offset
vd.actualStride() * (count-1) + // to stride to the start of the last element group CheckedUint32(vd.actualStride()) * (count-1) + // to stride to the start of the last element group
vd.componentSize() * vd.size; // and the number of bytes needed for these components CheckedUint32(vd.componentSize()) * vd.size; // and the number of bytes needed for these components
if (vd.buf->ByteLength() < needed) { if (!checked_needed.valid()) {
LogMessage("VBO too small for bound attrib index %d: need at least %d bytes, but have only %d", i, needed, vd.buf->ByteLength()); LogMessage("Integer overflow computing the size of bound vertex attrib buffer at index %d", i);
return PR_FALSE;
}
if (vd.buf->ByteLength() < checked_needed.value()) {
LogMessage("VBO too small for bound attrib index %d: need at least %d bytes, but have only %d",
i, checked_needed.value(), vd.buf->ByteLength());
return PR_FALSE; return PR_FALSE;
} }
} }
@ -250,6 +258,19 @@ PRBool WebGLContext::ValidateFaceEnum(WebGLenum target, const char *info)
} }
} }
PRBool WebGLContext::ValidateBufferUsageEnum(WebGLenum target, const char *info)
{
switch (target) {
case LOCAL_GL_STREAM_DRAW:
case LOCAL_GL_STATIC_DRAW:
case LOCAL_GL_DYNAMIC_DRAW:
return PR_TRUE;
default:
ErrorInvalidEnumInfo(info);
return PR_FALSE;
}
}
PRBool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type, PRBool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type,
PRUint32 *texelSize, const char *info) PRUint32 *texelSize, const char *info)
{ {

View File

@ -3111,7 +3111,7 @@ nsCanvasRenderingContext2D::SetLineCap(const nsAString& capstyle)
cap = gfxContext::LINE_CAP_SQUARE; cap = gfxContext::LINE_CAP_SQUARE;
else else
// XXX ERRMSG we need to report an error to developers here! (bug 329026) // XXX ERRMSG we need to report an error to developers here! (bug 329026)
return NS_ERROR_NOT_IMPLEMENTED; return NS_OK;
mThebes->SetLineCap(cap); mThebes->SetLineCap(cap);
return NS_OK; return NS_OK;
@ -3147,7 +3147,7 @@ nsCanvasRenderingContext2D::SetLineJoin(const nsAString& joinstyle)
j = gfxContext::LINE_JOIN_MITER; j = gfxContext::LINE_JOIN_MITER;
else else
// XXX ERRMSG we need to report an error to developers here! (bug 329026) // XXX ERRMSG we need to report an error to developers here! (bug 329026)
return NS_ERROR_NOT_IMPLEMENTED; return NS_OK;
mThebes->SetLineJoin(j); mThebes->SetLineJoin(j);
return NS_OK; return NS_OK;
@ -3532,7 +3532,8 @@ nsCanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op)
else CANVAS_OP_TO_THEBES_OP("xor", XOR) else CANVAS_OP_TO_THEBES_OP("xor", XOR)
// not part of spec, kept here for compat // not part of spec, kept here for compat
else CANVAS_OP_TO_THEBES_OP("over", OVER) else CANVAS_OP_TO_THEBES_OP("over", OVER)
else return NS_ERROR_NOT_IMPLEMENTED; // XXX ERRMSG we need to report an error to developers here! (bug 329026)
else return NS_OK;
#undef CANVAS_OP_TO_THEBES_OP #undef CANVAS_OP_TO_THEBES_OP

View File

@ -1463,7 +1463,7 @@ ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor'
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -1569,7 +1569,7 @@ ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor'
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -1596,7 +1596,7 @@ ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor'
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -1642,7 +1642,7 @@ ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor'
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -9131,7 +9131,7 @@ ok(ctx.lineCap === 'butt', "ctx.lineCap === 'butt'");
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -9505,7 +9505,7 @@ ok(ctx.lineJoin === 'bevel', "ctx.lineJoin === 'bevel'");
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -19316,7 +19316,7 @@ ok(canvas.getContext('2D') === null, "canvas.getContext('2D') === null");
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -19342,7 +19342,7 @@ ok(canvas.getContext("") === null, "canvas.getContext(\"\") === null");
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -19368,7 +19368,7 @@ ok(canvas.getContext('This is not an implemented context in any real browser') =
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -19394,7 +19394,7 @@ ok(canvas.getContext("2d#") === null, "canvas.getContext(\"2d#\") === null");
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -19420,7 +19420,7 @@ ok(canvas.getContext("2d\0") === null, "canvas.getContext(\"2d\\0\") === null");
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -19446,7 +19446,7 @@ ok(canvas.getContext("2\uFF44") === null, "canvas.getContext(\"2\\uFF44\") === n
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -20607,7 +20607,7 @@ ok(/^data:image\/png[;,]/.test(data), "data =~ /^data:image\\/png[;,]/");
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }
@ -20715,7 +20715,7 @@ ok(/^data:image\/png[;,]/.test(data), "data =~ /^data:image\\/png[;,]/");
} catch (e) { } catch (e) {
_thrown_outer = true; _thrown_outer = true;
} }
todo(!_thrown_outer, 'should not throw exception'); ok(!_thrown_outer, 'should not throw exception');
} }

View File

@ -140,11 +140,11 @@ function go() {
checkGetAttachedShaders([fs], [], [fs], "attaching a single shader should give the expected list"); checkGetAttachedShaders([fs], [], [fs], "attaching a single shader should give the expected list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [], [fs, vs, fs2, vs2], checkGetAttachedShaders([fs, vs, fs2, vs2], [], [fs, vs, fs2, vs2],
"attaching some shaders should give the expected list"); "attaching some shaders should give the expected list");
checkGetAttachedShaders([fs], [fs], [], "attaching a shader and detaching it shoud leave an empty list"); checkGetAttachedShaders([fs], [fs], [], "attaching a shader and detaching it should leave an empty list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs, fs2, vs2], [], checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs, fs2, vs2], [],
"attaching some shaders and detaching them in same order shoud leave an empty list"); "attaching some shaders and detaching them in same order should leave an empty list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs2, vs, fs2], [], checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs2, vs, fs2], [],
"attaching some shaders and detaching them in random order shoud leave an empty list"); "attaching some shaders and detaching them in random order should leave an empty list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [vs], [fs, fs2, vs2], checkGetAttachedShaders([fs, vs, fs2, vs2], [vs], [fs, fs2, vs2],
"attaching and detaching some shaders should leave the difference list"); "attaching and detaching some shaders should leave the difference list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs2], [vs, fs2], checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs2], [vs, fs2],

View File

@ -139,10 +139,13 @@ nsEventListenerInfo::ToSource(nsAString& aResult)
JSContext* cx = nsnull; JSContext* cx = nsnull;
stack->GetSafeJSContext(&cx); stack->GetSafeJSContext(&cx);
if (cx && NS_SUCCEEDED(stack->Push(cx))) { if (cx && NS_SUCCEEDED(stack->Push(cx))) {
JSAutoRequest ar(cx); {
JSString* str = JS_ValueToSource(cx, v); // Extra block to finish the auto request before calling pop
if (str) { JSAutoRequest ar(cx);
aResult.Assign(nsDependentJSString(str)); JSString* str = JS_ValueToSource(cx, v);
if (str) {
aResult.Assign(nsDependentJSString(str));
}
} }
stack->Pop(&cx); stack->Pop(&cx);
} }

View File

@ -1581,9 +1581,9 @@ nsGenericHTMLElement::ParseTableVAlignValue(const nsAString& aString,
return aResult.ParseEnumValue(aString, kTableVAlignTable, PR_FALSE); return aResult.ParseEnumValue(aString, kTableVAlignTable, PR_FALSE);
} }
PRBool PRBool
nsGenericHTMLElement::ParseDivAlignValue(const nsAString& aString, nsGenericHTMLElement::ParseDivAlignValue(const nsAString& aString,
nsAttrValue& aResult) const nsAttrValue& aResult)
{ {
return aResult.ParseEnumValue(aString, kDivAlignTable, PR_FALSE); return aResult.ParseEnumValue(aString, kDivAlignTable, PR_FALSE);
} }

View File

@ -253,8 +253,8 @@ public:
* @param aResult the resulting HTMLValue * @param aResult the resulting HTMLValue
* @return whether the value was parsed * @return whether the value was parsed
*/ */
PRBool ParseDivAlignValue(const nsAString& aString, static PRBool ParseDivAlignValue(const nsAString& aString,
nsAttrValue& aResult) const; nsAttrValue& aResult);
/** /**
* Convert a table halign string to value (left/right/center/char/justify) * Convert a table halign string to value (left/right/center/char/justify)

View File

@ -202,13 +202,7 @@ nsHTMLCanvasElement::ToDataURL(const nsAString& aType, const nsAString& aParams,
return NS_ERROR_DOM_SECURITY_ERR; return NS_ERROR_DOM_SECURITY_ERR;
} }
nsAutoString type(aType); return ToDataURLImpl(aType, aParams, aDataURL);
if (type.IsEmpty()) {
type.AssignLiteral("image/png");
}
return ToDataURLImpl(type, aParams, aDataURL);
} }
@ -229,13 +223,13 @@ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
const nsAString& aEncoderOptions, const nsAString& aEncoderOptions,
nsAString& aDataURL) nsAString& aDataURL)
{ {
nsresult rv; bool fallbackToPNG = false;
// We get an input stream from the context. If more than one context type // We get an input stream from the context. If more than one context type
// is supported in the future, this will have to be changed to do the right // is supported in the future, this will have to be changed to do the right
// thing. For now, just assume that the 2D context has all the goods. // thing. For now, just assume that the 2D context has all the goods.
nsCOMPtr<nsICanvasRenderingContextInternal> context; nsCOMPtr<nsICanvasRenderingContextInternal> context;
rv = GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(context)); nsresult rv = GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(context));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// get image bytes // get image bytes
@ -244,8 +238,15 @@ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
rv = context->GetInputStream(nsPromiseFlatCString(aMimeType8).get(), rv = context->GetInputStream(nsPromiseFlatCString(aMimeType8).get(),
nsPromiseFlatString(aEncoderOptions).get(), nsPromiseFlatString(aEncoderOptions).get(),
getter_AddRefs(imgStream)); getter_AddRefs(imgStream));
// XXX ERRMSG we need to report an error to developers here! (bug 329026) if (NS_FAILED(rv)) {
NS_ENSURE_SUCCESS(rv, rv); // Use image/png instead.
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
fallbackToPNG = true;
rv = context->GetInputStream("image/png",
nsPromiseFlatString(aEncoderOptions).get(),
getter_AddRefs(imgStream));
NS_ENSURE_SUCCESS(rv, rv);
}
// Generally, there will be only one chunk of data, and it will be available // Generally, there will be only one chunk of data, and it will be available
// for us to read right away, so optimize this case. // for us to read right away, so optimize this case.
@ -283,8 +284,12 @@ nsHTMLCanvasElement::ToDataURLImpl(const nsAString& aMimeType,
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
// build data URL string // build data URL string
aDataURL = NS_LITERAL_STRING("data:") + aMimeType + if (fallbackToPNG)
NS_LITERAL_STRING(";base64,") + NS_ConvertUTF8toUTF16(encodedImg); aDataURL = NS_LITERAL_STRING("data:image/png;base64,") +
NS_ConvertUTF8toUTF16(encodedImg);
else
aDataURL = NS_LITERAL_STRING("data:") + aMimeType +
NS_LITERAL_STRING(";base64,") + NS_ConvertUTF8toUTF16(encodedImg);
PR_Free(encodedImg); PR_Free(encodedImg);
@ -309,7 +314,7 @@ nsHTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
(ctxId[i] != '_')) (ctxId[i] != '_'))
{ {
// XXX ERRMSG we need to report an error to developers here! (bug 329026) // XXX ERRMSG we need to report an error to developers here! (bug 329026)
return NS_ERROR_INVALID_ARG; return NS_OK;
} }
} }
@ -326,7 +331,7 @@ nsHTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
*aContext = nsnull; *aContext = nsnull;
// XXX ERRMSG we need to report an error to developers here! (bug 329026) // XXX ERRMSG we need to report an error to developers here! (bug 329026)
return NS_ERROR_INVALID_ARG; return NS_OK;
} }
rv = ctx->SetCanvasElement(this); rv = ctx->SetCanvasElement(this);
@ -376,7 +381,7 @@ nsHTMLCanvasElement::GetContext(const nsAString& aContextId,
mCurrentContextId.Assign(aContextId); mCurrentContextId.Assign(aContextId);
} else if (!mCurrentContextId.Equals(aContextId)) { } else if (!mCurrentContextId.Equals(aContextId)) {
//XXX eventually allow for more than one active context on a given canvas //XXX eventually allow for more than one active context on a given canvas
return NS_ERROR_INVALID_ARG; return NS_OK;
} }
NS_ADDREF (*aContext = mCurrentContext); NS_ADDREF (*aContext = mCurrentContext);

View File

@ -116,7 +116,7 @@ function checkHtmlForIDLAttribute(element)
// DOMSettableTokenList is tested in another bug so we just test assignation // DOMSettableTokenList is tested in another bug so we just test assignation
element.htmlFor.value = 'a b c'; element.htmlFor.value = 'a b c';
is(element.htmlFor, 'a b c', "htmlFor shoud have changed"); is(element.htmlFor, 'a b c', "htmlFor should have changed");
} }
function submitForm() function submitForm()

View File

@ -148,11 +148,13 @@ NS_NewHTMLNOTUSEDElement(nsINodeInfo *aNodeInfo, PRUint32 aFromParser)
} }
#define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element, #define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element,
#define HTML_HTMLELEMENT_TAG(_tag) NS_NewHTMLElement,
#define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement, #define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
static const contentCreatorCallback sContentCreatorCallbacks[] = { static const contentCreatorCallback sContentCreatorCallbacks[] = {
NS_NewHTMLUnknownElement, NS_NewHTMLUnknownElement,
#include "nsHTMLTagList.h" #include "nsHTMLTagList.h"
#undef HTML_TAG #undef HTML_TAG
#undef HTML_HTMLELEMENT_TAG
#undef HTML_OTHER #undef HTML_OTHER
NS_NewHTMLUnknownElement NS_NewHTMLUnknownElement
}; };

View File

@ -1254,21 +1254,11 @@ nsHTMLDocument::CreateElement(const nsAString& aTagName,
nsIDOMElement** aReturn) nsIDOMElement** aReturn)
{ {
*aReturn = nsnull; *aReturn = nsnull;
nsresult rv; nsresult rv = nsContentUtils::CheckQName(aTagName, PR_FALSE);
if (NS_FAILED(rv))
return rv;
nsAutoString tagName(aTagName); nsAutoString tagName(aTagName);
// if we are in quirks, allow surrounding '<' '>' for IE compat
if (mCompatMode == eCompatibility_NavQuirks &&
tagName.Length() > 2 &&
tagName.First() == '<' &&
tagName.Last() == '>') {
tagName = Substring(tagName, 1, tagName.Length() - 2);
}
rv = nsContentUtils::CheckQName(tagName, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
if (IsHTML()) { if (IsHTML()) {
ToLowerCase(tagName); ToLowerCase(tagName);
} }

View File

@ -1006,7 +1006,10 @@ nsHTMLParanoidFragmentSink::AddAttributes(const nsIParserNode& aNode,
nsContentUtils::TrimCharsInSet(kWhitespace, aNode.GetValueAt(i)); nsContentUtils::TrimCharsInSet(kWhitespace, aNode.GetValueAt(i));
// check the attributes we allow that contain URIs // check the attributes we allow that contain URIs
if (IsAttrURI(keyAtom)) { // special case src attributes for img tags, because they can't
// run any dangerous code.
if (IsAttrURI(keyAtom) &&
!(nodeType == eHTMLTag_img && keyAtom == nsGkAtoms::src)) {
if (!baseURI) { if (!baseURI) {
baseURI = aContent->GetBaseURI(); baseURI = aContent->GetBaseURI();
} }

View File

@ -61,6 +61,7 @@ _TEST_FILES = test_bug1682.html \
test_bug311681.xhtml \ test_bug311681.xhtml \
test_bug324378.html \ test_bug324378.html \
test_bug332848.xhtml \ test_bug332848.xhtml \
test_bug340017.xhtml \
test_bug359657.html \ test_bug359657.html \
test_bug369370.html \ test_bug369370.html \
bug369370-popup.png \ bug369370-popup.png \
@ -95,13 +96,13 @@ _TEST_FILES = test_bug1682.html \
test_bug481647.html \ test_bug481647.html \
test_bug482659.html \ test_bug482659.html \
test_bug486741.html \ test_bug486741.html \
test_bug489532.html \
test_bug497242.xhtml \ test_bug497242.xhtml \
test_bug512367.html \
test_bug570375.html \
test_bug340017.xhtml \
test_bug499092.html \ test_bug499092.html \
bug499092.xml \ bug499092.xml \
bug499092.html \ bug499092.html \
test_bug512367.html \
test_bug570376.html \
test_bug571981.html \ test_bug571981.html \
$(NULL) $(NULL)

View File

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=489532
-->
<head>
<title>Test for Bug 489532</title>
<script src="/MochiKit/packed.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489532">Mozilla Bug 489532</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script>
/** Test for Bug 489532 **/
try {
document.createElement("<div>");
ok(false, "Should throw.")
} catch (e) {
ok(e instanceof DOMException, "Expected DOMException.");
is(e.code, DOMException.INVALID_CHARACTER_ERR,
"Expected INVALID_CHARACTER_ERR.");
}
</script>
</pre>
</body>
</html>

View File

@ -1,16 +1,16 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html>
<!-- <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=570375 https://bugzilla.mozilla.org/show_bug.cgi?id=570376
--> -->
<head> <head>
<title>Test for Bug 570375</title> <title>Test for Bug 570376</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script> <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/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head> </head>
<body> <body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=570375">Mozilla Bug 570375</a> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=570376">Mozilla Bug 570376</a>
<p id="display"> <p id="display">
<iframe id="testiframe"></iframe> <iframe id="testiframe"></iframe>
</p> </p>
@ -19,7 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=570375
<pre id="test"> <pre id="test">
<script type="application/javascript"> <script type="application/javascript">
/** Test for Bug 570375 /** Test for Bug 570376
Don't crash loading <form><legend> with the html5 parser preffed off. Don't crash loading <form><legend> with the html5 parser preffed off.
**/ **/

View File

@ -126,9 +126,9 @@ VideoData* VideoData::Create(nsVideoInfo& aInfo,
PRUint32 picXLimit; PRUint32 picXLimit;
PRUint32 picYLimit; PRUint32 picYLimit;
if (!AddOverflow32(aInfo.mPicture.x, aInfo.mPicture.width, picXLimit) || if (!AddOverflow32(aInfo.mPicture.x, aInfo.mPicture.width, picXLimit) ||
picXLimit > PRUint32(aBuffer.mPlanes[0].mStride) || picXLimit > aBuffer.mPlanes[0].mStride ||
!AddOverflow32(aInfo.mPicture.y, aInfo.mPicture.height, picYLimit) || !AddOverflow32(aInfo.mPicture.y, aInfo.mPicture.height, picYLimit) ||
picYLimit > PRUint32(aBuffer.mPlanes[0].mHeight)) picYLimit > aBuffer.mPlanes[0].mHeight)
{ {
// The specified picture dimensions can't be contained inside the video // The specified picture dimensions can't be contained inside the video
// frame, we'll stomp memory if we try to copy it. Fail. // frame, we'll stomp memory if we try to copy it. Fail.

View File

@ -904,10 +904,11 @@ PRInt64 nsOggReader::FindEndTime(PRInt64 aEndOffset)
// This page is from a bitstream which we haven't encountered yet. // This page is from a bitstream which we haven't encountered yet.
// It's probably from a new "link" in a "chained" ogg. Don't // It's probably from a new "link" in a "chained" ogg. Don't
// bother even trying to find a duration... // bother even trying to find a duration...
endTime = -1;
break; break;
} }
PRInt64 t = codecState ? codecState->Time(granulepos) : -1; PRInt64 t = codecState->Time(granulepos);
if (t != -1) { if (t != -1) {
endTime = t; endTime = t;
} }

View File

@ -325,6 +325,9 @@ nsSMILAnimationController::DoSample(PRBool aSkipUnchangedContainers)
mResampleNeeded = PR_FALSE; mResampleNeeded = PR_FALSE;
// STEP 1: Bring model up to date // STEP 1: Bring model up to date
// (i) Rewind elements where necessary
// (ii) Run milestone samples
RewindElements();
DoMilestoneSamples(); DoMilestoneSamples();
// STEP 2: Sample the child time containers // STEP 2: Sample the child time containers
@ -402,6 +405,56 @@ nsSMILAnimationController::DoSample(PRBool aSkipUnchangedContainers)
NS_ASSERTION(!mResampleNeeded, "Resample dirty flag set during sample!"); NS_ASSERTION(!mResampleNeeded, "Resample dirty flag set during sample!");
} }
void
nsSMILAnimationController::RewindElements()
{
PRBool rewindNeeded = PR_FALSE;
mChildContainerTable.EnumerateEntries(RewindNeeded, &rewindNeeded);
if (!rewindNeeded)
return;
mAnimationElementTable.EnumerateEntries(RewindAnimation, nsnull);
mChildContainerTable.EnumerateEntries(ClearRewindNeeded, nsnull);
}
/*static*/ PR_CALLBACK PLDHashOperator
nsSMILAnimationController::RewindNeeded(TimeContainerPtrKey* aKey,
void* aData)
{
NS_ABORT_IF_FALSE(aData,
"Null data pointer during time container enumeration");
PRBool* rewindNeeded = static_cast<PRBool*>(aData);
nsSMILTimeContainer* container = aKey->GetKey();
if (container->NeedsRewind()) {
*rewindNeeded = PR_TRUE;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
/*static*/ PR_CALLBACK PLDHashOperator
nsSMILAnimationController::RewindAnimation(AnimationElementPtrKey* aKey,
void* aData)
{
nsISMILAnimationElement* animElem = aKey->GetKey();
nsSMILTimeContainer* timeContainer = animElem->GetTimeContainer();
if (timeContainer && timeContainer->NeedsRewind()) {
animElem->TimedElement().Rewind();
}
return PL_DHASH_NEXT;
}
/*static*/ PR_CALLBACK PLDHashOperator
nsSMILAnimationController::ClearRewindNeeded(TimeContainerPtrKey* aKey,
void* aData)
{
aKey->GetKey()->ClearNeedsRewind();
return PL_DHASH_NEXT;
}
void void
nsSMILAnimationController::DoMilestoneSamples() nsSMILAnimationController::DoMilestoneSamples()
{ {
@ -542,6 +595,7 @@ nsSMILAnimationController::SampleTimeContainer(TimeContainerPtrKey* aKey,
(container->NeedsSample() || !params->mSkipUnchangedContainers)) { (container->NeedsSample() || !params->mSkipUnchangedContainers)) {
container->ClearMilestones(); container->ClearMilestones();
container->Sample(); container->Sample();
container->MarkSeekFinished();
params->mActiveContainers->PutEntry(container); params->mActiveContainers->PutEntry(container);
} }
@ -587,6 +641,8 @@ nsSMILAnimationController::SampleTimedElement(
nsSMILTime containerTime = timeContainer->GetCurrentTime(); nsSMILTime containerTime = timeContainer->GetCurrentTime();
NS_ABORT_IF_FALSE(!timeContainer->IsSeeking(),
"Doing a regular sample but the time container is still seeking");
aElement->TimedElement().SampleAt(containerTime); aElement->TimedElement().SampleAt(containerTime);
} }

View File

@ -152,11 +152,21 @@ protected:
// Sample-related callbacks and implementation helpers // Sample-related callbacks and implementation helpers
virtual void DoSample(); virtual void DoSample();
void DoSample(PRBool aSkipUnchangedContainers); void DoSample(PRBool aSkipUnchangedContainers);
void RewindElements();
PR_STATIC_CALLBACK(PLDHashOperator) RewindNeeded(
TimeContainerPtrKey* aKey, void* aData);
PR_STATIC_CALLBACK(PLDHashOperator) RewindAnimation(
AnimationElementPtrKey* aKey, void* aData);
PR_STATIC_CALLBACK(PLDHashOperator) ClearRewindNeeded(
TimeContainerPtrKey* aKey, void* aData);
void DoMilestoneSamples(); void DoMilestoneSamples();
PR_STATIC_CALLBACK(PLDHashOperator) GetNextMilestone( PR_STATIC_CALLBACK(PLDHashOperator) GetNextMilestone(
TimeContainerPtrKey* aKey, void* aData); TimeContainerPtrKey* aKey, void* aData);
PR_STATIC_CALLBACK(PLDHashOperator) GetMilestoneElements( PR_STATIC_CALLBACK(PLDHashOperator) GetMilestoneElements(
TimeContainerPtrKey* aKey, void* aData); TimeContainerPtrKey* aKey, void* aData);
PR_STATIC_CALLBACK(PLDHashOperator) SampleTimeContainer( PR_STATIC_CALLBACK(PLDHashOperator) SampleTimeContainer(
TimeContainerPtrKey* aKey, void* aData); TimeContainerPtrKey* aKey, void* aData);
PR_STATIC_CALLBACK(PLDHashOperator) SampleAnimation( PR_STATIC_CALLBACK(PLDHashOperator) SampleAnimation(

View File

@ -74,9 +74,9 @@ nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
nsSMILInterval* aBaseInterval) nsSMILInterval* aBaseInterval)
: mTime(aTime), : mTime(aTime),
mFlags(0), mFlags(0),
mSerial(0),
mVisited(PR_FALSE), mVisited(PR_FALSE),
mChainEnd(PR_FALSE), mFixedEndpointRefCnt(0),
mSerial(0),
mCreator(aCreator), mCreator(aCreator),
mBaseInterval(nsnull) // This will get set to aBaseInterval in a call to mBaseInterval(nsnull) // This will get set to aBaseInterval in a call to
// SetBaseInterval() at end of constructor // SetBaseInterval() at end of constructor
@ -87,7 +87,7 @@ nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
break; break;
case SOURCE_DOM: case SOURCE_DOM:
mFlags = kClearOnReset | kFromDOM; mFlags = kDynamic | kFromDOM;
break; break;
case SOURCE_SYNCBASE: case SOURCE_SYNCBASE:
@ -95,7 +95,7 @@ nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
break; break;
case SOURCE_EVENT: case SOURCE_EVENT:
mFlags = kClearOnReset; mFlags = kDynamic;
break; break;
} }
@ -106,6 +106,9 @@ nsSMILInstanceTime::~nsSMILInstanceTime()
{ {
NS_ABORT_IF_FALSE(!mBaseInterval && !mCreator, NS_ABORT_IF_FALSE(!mBaseInterval && !mCreator,
"Destroying instance time without first calling Unlink()"); "Destroying instance time without first calling Unlink()");
NS_ABORT_IF_FALSE(mFixedEndpointRefCnt == 0,
"Destroying instance time that is still used as the fixed endpoint of an "
"interval");
} }
void void
@ -129,12 +132,9 @@ nsSMILInstanceTime::HandleChangedInterval(
"Got call to HandleChangedInterval on an independent instance time."); "Got call to HandleChangedInterval on an independent instance time.");
NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not."); NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not.");
if (mVisited || mChainEnd) { if (mVisited) {
// We're breaking the cycle here but we need to ensure that if we later // Break the cycle here
// receive a change notice in a different context (e.g. due to a time Unlink();
// container change) that we don't end up following the chain further and so
// we set a flag to that effect.
mChainEnd = PR_TRUE;
return; return;
} }
@ -152,20 +152,63 @@ void
nsSMILInstanceTime::HandleDeletedInterval() nsSMILInstanceTime::HandleDeletedInterval()
{ {
NS_ABORT_IF_FALSE(mBaseInterval, NS_ABORT_IF_FALSE(mBaseInterval,
"Got call to HandleDeletedInterval on an independent instance time."); "Got call to HandleDeletedInterval on an independent instance time");
NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not."); NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not");
mBaseInterval = nsnull; mBaseInterval = nsnull;
mFlags &= ~kMayUpdate; // Can't update without a base interval
nsRefPtr<nsSMILInstanceTime> deathGrip(this); nsRefPtr<nsSMILInstanceTime> deathGrip(this);
mCreator->HandleDeletedInstanceTime(*this); mCreator->HandleDeletedInstanceTime(*this);
mCreator = nsnull; mCreator = nsnull;
} }
PRBool void
nsSMILInstanceTime::IsDependent(const nsSMILInstanceTime& aOther) const nsSMILInstanceTime::HandleFilteredInterval()
{ {
if (mVisited || mChainEnd) NS_ABORT_IF_FALSE(mBaseInterval,
"Got call to HandleFilteredInterval on an independent instance time");
mBaseInterval = nsnull;
mFlags &= ~kMayUpdate; // Can't update without a base interval
mCreator = nsnull;
}
PRBool
nsSMILInstanceTime::ShouldPreserve() const
{
return mFixedEndpointRefCnt > 0 || (mFlags & kWasDynamicEndpoint);
}
void
nsSMILInstanceTime::UnmarkShouldPreserve()
{
mFlags &= ~kWasDynamicEndpoint;
}
void
nsSMILInstanceTime::AddRefFixedEndpoint()
{
NS_ABORT_IF_FALSE(mFixedEndpointRefCnt < PR_UINT16_MAX,
"Fixed endpoint reference count upper limit reached");
++mFixedEndpointRefCnt;
mFlags &= ~kMayUpdate; // Once fixed, always fixed
}
void
nsSMILInstanceTime::ReleaseFixedEndpoint()
{
NS_ABORT_IF_FALSE(mFixedEndpointRefCnt > 0, "Duplicate release");
--mFixedEndpointRefCnt;
if (mFixedEndpointRefCnt == 0 && IsDynamic()) {
mFlags |= kWasDynamicEndpoint;
}
}
PRBool
nsSMILInstanceTime::IsDependentOn(const nsSMILInstanceTime& aOther) const
{
if (mVisited)
return PR_FALSE; return PR_FALSE;
const nsSMILInstanceTime* myBaseTime = GetBaseTime(); const nsSMILInstanceTime* myBaseTime = GetBaseTime();
@ -177,7 +220,7 @@ nsSMILInstanceTime::IsDependent(const nsSMILInstanceTime& aOther) const
// mVisited is mutable // mVisited is mutable
AutoBoolSetter setVisited(const_cast<nsSMILInstanceTime*>(this)->mVisited); AutoBoolSetter setVisited(const_cast<nsSMILInstanceTime*>(this)->mVisited);
return myBaseTime->IsDependent(aOther); return myBaseTime->IsDependentOn(aOther);
} }
void void

View File

@ -92,24 +92,31 @@ public:
PRBool aBeginObjectChanged, PRBool aBeginObjectChanged,
PRBool aEndObjectChanged); PRBool aEndObjectChanged);
void HandleDeletedInterval(); void HandleDeletedInterval();
void HandleFilteredInterval();
const nsSMILTimeValue& Time() const { return mTime; } const nsSMILTimeValue& Time() const { return mTime; }
const nsSMILTimeValueSpec* GetCreator() const { return mCreator; } const nsSMILTimeValueSpec* GetCreator() const { return mCreator; }
PRBool ClearOnReset() const { return !!(mFlags & kClearOnReset); } PRBool IsDynamic() const { return !!(mFlags & kDynamic); }
PRBool MayUpdate() const { return !!(mFlags & kMayUpdate); } PRBool IsFixedTime() const { return !(mFlags & kMayUpdate); }
PRBool FromDOM() const { return !!(mFlags & kFromDOM); } PRBool FromDOM() const { return !!(mFlags & kFromDOM); }
void MarkNoLongerUpdating() { mFlags &= ~kMayUpdate; } PRBool ShouldPreserve() const;
void UnmarkShouldPreserve();
void AddRefFixedEndpoint();
void ReleaseFixedEndpoint();
void DependentUpdate(const nsSMILTimeValue& aNewTime) void DependentUpdate(const nsSMILTimeValue& aNewTime)
{ {
NS_ABORT_IF_FALSE(MayUpdate(), NS_ABORT_IF_FALSE(!IsFixedTime(),
"Updating an instance time that is not expected to be updated"); "Updating an instance time that is not expected to be updated");
mTime = aNewTime; mTime = aNewTime;
} }
PRBool IsDependent(const nsSMILInstanceTime& aOther) const; PRBool IsDependent() const { return !!mBaseInterval; }
PRBool IsDependentOn(const nsSMILInstanceTime& aOther) const;
const nsSMILInterval* GetBaseInterval() const { return mBaseInterval; }
PRBool SameTimeAndBase(const nsSMILInstanceTime& aOther) const PRBool SameTimeAndBase(const nsSMILInstanceTime& aOther) const
{ {
@ -131,15 +138,16 @@ protected:
// Internal flags used to represent the behaviour of different instance times // Internal flags used to represent the behaviour of different instance times
enum { enum {
// Indicates if this instance time should be removed when the owning timed // Indicates that this instance time was generated by an event or a DOM
// element is reset. True for events and DOM calls. // call. Such instance times require special handling when (i) the owning
kClearOnReset = 1, // element is reset, and (ii) when a backwards seek is performed and the
// timing model is reconstructed.
kDynamic = 1,
// Indicates that this instance time is referred to by an // Indicates that this instance time is referred to by an
// nsSMILTimeValueSpec and as such may be updated. Such instance time should // nsSMILTimeValueSpec and as such may be updated. Such instance time should
// not be filtered out by the nsSMILTimedElement even if they appear to be // not be filtered out by the nsSMILTimedElement even if they appear to be
// in the past as they may be updated to a future time. Initially set for // in the past as they may be updated to a future time.
// syncbase-generated times until they are frozen.
kMayUpdate = 2, kMayUpdate = 2,
// Indicates that this instance time was generated from the DOM as opposed // Indicates that this instance time was generated from the DOM as opposed
@ -147,17 +155,33 @@ protected:
// reset we should clear all the instance times that have been generated by // reset we should clear all the instance times that have been generated by
// that attribute (and hence an nsSMILTimeValueSpec), but not those from the // that attribute (and hence an nsSMILTimeValueSpec), but not those from the
// DOM. // DOM.
kFromDOM = 4 kFromDOM = 4,
// Indicates that this instance time was used as the endpoint of an interval
// that has been filtered or removed. However, since it is a dynamic time it
// should be preserved and not filtered.
kWasDynamicEndpoint = 8
}; };
PRUint8 mFlags; // Combination of kClearOnReset, kMayUpdate, etc. PRUint8 mFlags; // Combination of kDynamic, kMayUpdate, etc.
PRPackedBool mVisited; // (mutable) Cycle tracking
// Additional reference count to determine if this instance time is currently
// used as a fixed endpoint in any intervals. Instance times that are used in
// this way should not be removed when the owning nsSMILTimedElement removes
// instance times in response to a restart or in an attempt to free up memory
// by filtering out old instance times.
//
// Instance times are only shared in a few cases, namely:
// a) early ends,
// b) zero-duration intervals, and
// c) momentarily whilst establishing new intervals and updating the current
// interval
// Hence the limited range of a PRUint16 should be more than adequate.
PRUint16 mFixedEndpointRefCnt;
PRUint32 mSerial; // A serial number used by the containing class to PRUint32 mSerial; // A serial number used by the containing class to
// specify the sort order for instance times with the // specify the sort order for instance times with the
// same mTime. // same mTime.
PRPackedBool mVisited; // (mutable) Cycle tracking
PRPackedBool mChainEnd; // Flag to indicate that this instance time is part
// of some cyclic dependency and that in order to
// avoid infinite recursion the cycle should not be
// followed any further than this point.
nsSMILTimeValueSpec* mCreator; // The nsSMILTimeValueSpec object that created nsSMILTimeValueSpec* mCreator; // The nsSMILTimeValueSpec object that created
// us. (currently only needed for syncbase // us. (currently only needed for syncbase

View File

@ -39,6 +39,8 @@
nsSMILInterval::nsSMILInterval() nsSMILInterval::nsSMILInterval()
: :
mBeginFixed(PR_FALSE),
mEndFixed(PR_FALSE),
mBeginObjectChanged(PR_FALSE), mBeginObjectChanged(PR_FALSE),
mEndObjectChanged(PR_FALSE) mEndObjectChanged(PR_FALSE)
{ {
@ -48,19 +50,28 @@ nsSMILInterval::nsSMILInterval(const nsSMILInterval& aOther)
: :
mBegin(aOther.mBegin), mBegin(aOther.mBegin),
mEnd(aOther.mEnd), mEnd(aOther.mEnd),
mBeginFixed(PR_FALSE),
mEndFixed(PR_FALSE),
mBeginObjectChanged(PR_FALSE), mBeginObjectChanged(PR_FALSE),
mEndObjectChanged(PR_FALSE) mEndObjectChanged(PR_FALSE)
{ {
NS_ABORT_IF_FALSE(aOther.mDependentTimes.IsEmpty(), NS_ABORT_IF_FALSE(aOther.mDependentTimes.IsEmpty(),
"Attempting to copy-construct an interval with dependent times, " "Attempting to copy-construct an interval with dependent times, "
"this will lead to instance times being shared between intervals."); "this will lead to instance times being shared between intervals.");
// For the time being we don't allow intervals with fixed endpoints to be
// copied since we only ever copy-construct to establish a new current
// interval. If we ever need to copy historical intervals we may need to move
// the ReleaseFixedEndpoint calls from Unlink to the dtor.
NS_ABORT_IF_FALSE(!aOther.mBeginFixed && !aOther.mEndFixed,
"Attempting to copy-construct an interval with fixed endpoints");
} }
nsSMILInterval::~nsSMILInterval() nsSMILInterval::~nsSMILInterval()
{ {
NS_ABORT_IF_FALSE(mDependentTimes.IsEmpty(), NS_ABORT_IF_FALSE(mDependentTimes.IsEmpty(),
"Destroying interval without disassociating dependent instance times. " "Destroying interval without disassociating dependent instance times. "
"NotifyDeleting was not called."); "Unlink was not called");
} }
void void
@ -76,12 +87,24 @@ nsSMILInterval::NotifyChanged(const nsSMILTimeContainer* aContainer)
} }
void void
nsSMILInterval::NotifyDeleting() nsSMILInterval::Unlink(PRBool aFiltered)
{ {
for (PRInt32 i = mDependentTimes.Length() - 1; i >= 0; --i) { for (PRInt32 i = mDependentTimes.Length() - 1; i >= 0; --i) {
mDependentTimes[i]->HandleDeletedInterval(); if (aFiltered) {
mDependentTimes[i]->HandleFilteredInterval();
} else {
mDependentTimes[i]->HandleDeletedInterval();
}
} }
mDependentTimes.Clear(); mDependentTimes.Clear();
if (mBegin && mBeginFixed) {
mBegin->ReleaseFixedEndpoint();
}
mBegin = nsnull;
if (mEnd && mEndFixed) {
mEnd->ReleaseFixedEndpoint();
}
mEnd = nsnull;
} }
nsSMILInstanceTime* nsSMILInstanceTime*
@ -104,7 +127,9 @@ void
nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin) nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin)
{ {
NS_ABORT_IF_FALSE(aBegin.Time().IsResolved(), NS_ABORT_IF_FALSE(aBegin.Time().IsResolved(),
"Attempting to set unresolved begin time on interval."); "Attempting to set unresolved begin time on interval");
NS_ABORT_IF_FALSE(!mBeginFixed,
"Attempting to set begin time but the begin point is fixed");
if (mBegin == &aBegin) if (mBegin == &aBegin)
return; return;
@ -116,6 +141,9 @@ nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin)
void void
nsSMILInterval::SetEnd(nsSMILInstanceTime& aEnd) nsSMILInterval::SetEnd(nsSMILInstanceTime& aEnd)
{ {
NS_ABORT_IF_FALSE(!mEndFixed,
"Attempting to set end time but the end point is fixed");
if (mEnd == &aEnd) if (mEnd == &aEnd)
return; return;
@ -123,6 +151,28 @@ nsSMILInterval::SetEnd(nsSMILInstanceTime& aEnd)
mEndObjectChanged = PR_TRUE; mEndObjectChanged = PR_TRUE;
} }
void
nsSMILInterval::FixBegin()
{
NS_ABORT_IF_FALSE(mBegin && mEnd,
"Fixing begin point on un-initialized interval");
NS_ABORT_IF_FALSE(!mBeginFixed, "Duplicate calls to FixBegin()");
mBeginFixed = PR_TRUE;
mBegin->AddRefFixedEndpoint();
}
void
nsSMILInterval::FixEnd()
{
NS_ABORT_IF_FALSE(mBegin && mEnd,
"Fixing end point on un-initialized interval");
NS_ABORT_IF_FALSE(mBeginFixed,
"Fixing the end of an interval without a fixed begin");
NS_ABORT_IF_FALSE(!mEndFixed, "Duplicate calls to FixEnd()");
mEndFixed = PR_TRUE;
mEnd->AddRefFixedEndpoint();
}
void void
nsSMILInterval::AddDependentTime(nsSMILInstanceTime& aTime) nsSMILInterval::AddDependentTime(nsSMILInstanceTime& aTime)
{ {
@ -142,3 +192,19 @@ nsSMILInterval::RemoveDependentTime(const nsSMILInstanceTime& aTime)
mDependentTimes.RemoveElementSorted(&aTime); mDependentTimes.RemoveElementSorted(&aTime);
NS_ABORT_IF_FALSE(found, "Couldn't find instance time to delete."); NS_ABORT_IF_FALSE(found, "Couldn't find instance time to delete.");
} }
PRBool
nsSMILInterval::IsDependencyChainLink() const
{
if (!mBegin || !mEnd)
return PR_FALSE; // Not yet initialised so it can't be part of a chain
if (mDependentTimes.IsEmpty())
return PR_FALSE; // No dependents, chain end
// So we have dependents, but we're still only a link in the chain (as opposed
// to the end of the chain) if one of our endpoints is dependent on an
// interval other than ourselves.
return (mBegin->IsDependent() && mBegin->GetBaseInterval() != this) ||
(mEnd->IsDependent() && mEnd->GetBaseInterval() != this);
}

Some files were not shown because too many files have changed in this diff Show More