mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Merge mozilla-central to tracemonkey.
This commit is contained in:
commit
f94d6c3608
@ -45,7 +45,7 @@
|
||||
interface nsIAccessible;
|
||||
interface nsIArray;
|
||||
|
||||
[scriptable, uuid(035c0c0e-41e3-4985-8ad9-d9f14cdc667a)]
|
||||
[scriptable, uuid(cb0bf7b9-117e-40e2-9e46-189c3d43ce4a)]
|
||||
interface nsIAccessibleTable : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -104,6 +104,17 @@ interface nsIAccessibleTable : nsISupports
|
||||
*/
|
||||
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
|
||||
* the specified row and column in the table. The result differs from 1 if
|
||||
|
169
accessible/src/base/AccGroupInfo.cpp
Normal file
169
accessible/src/base/AccGroupInfo.cpp
Normal 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;
|
||||
}
|
96
accessible/src/base/AccGroupInfo.h
Normal file
96
accessible/src/base/AccGroupInfo.h
Normal 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
|
@ -49,6 +49,7 @@ LIBXUL_LIBRARY = 1
|
||||
|
||||
CPPSRCS = \
|
||||
AccCollector.cpp \
|
||||
AccGroupInfo.cpp \
|
||||
AccIterator.cpp \
|
||||
filters.cpp \
|
||||
nsAccDocManager.cpp \
|
||||
|
@ -221,6 +221,34 @@ nsARIAGridAccessible::GetRowIndexAt(PRInt32 aCellIndex, PRInt32 *aRowIndex)
|
||||
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
|
||||
nsARIAGridAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn,
|
||||
PRInt32 *aExtentCount)
|
||||
|
@ -367,106 +367,6 @@ nsAccUtils::GetAncestorWithRole(nsAccessible *aDescendant, PRUint32 aRole)
|
||||
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 *
|
||||
nsAccUtils::GetSelectableContainer(nsAccessible *aAccessible, PRUint32 aState)
|
||||
{
|
||||
|
@ -198,19 +198,6 @@ public:
|
||||
static nsAccessible * GetAncestorWithRole(nsAccessible *aDescendant,
|
||||
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.
|
||||
*
|
||||
|
@ -131,7 +131,7 @@ void nsAccessNode::LastRelease()
|
||||
NS_ASSERTION(!mWeakShell, "A Shutdown() impl forgot to call its parent's Shutdown?");
|
||||
}
|
||||
// ... then die.
|
||||
NS_DELETEXPCOM(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "nsIXBLAccessible.h"
|
||||
|
||||
#include "AccGroupInfo.h"
|
||||
#include "AccIterator.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsARIAMap.h"
|
||||
@ -2125,11 +2126,12 @@ nsAccessible::GetRelationByType(PRUint32 aRelationType,
|
||||
(mRoleMapEntry->role == nsIAccessibleRole::ROLE_OUTLINEITEM ||
|
||||
mRoleMapEntry->role == nsIAccessibleRole::ROLE_ROW)) {
|
||||
|
||||
nsCOMPtr<nsIAccessible> accTarget;
|
||||
nsAccUtils::GetARIATreeItemParent(this, mContent,
|
||||
getter_AddRefs(accTarget));
|
||||
AccGroupInfo* groupInfo = GetGroupInfo();
|
||||
if (!groupInfo)
|
||||
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,
|
||||
@ -3091,98 +3093,24 @@ nsAccessible::GetActionRule(PRUint32 aStates)
|
||||
return eNoAction;
|
||||
}
|
||||
|
||||
AccGroupInfo*
|
||||
nsAccessible::GetGroupInfo()
|
||||
{
|
||||
if (mGroupInfo)
|
||||
return mGroupInfo;
|
||||
|
||||
mGroupInfo = AccGroupInfo::CreateGroupInfo(this);
|
||||
return mGroupInfo;
|
||||
}
|
||||
|
||||
void
|
||||
nsAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet, PRInt32 *aSetSize)
|
||||
{
|
||||
PRUint32 role = nsAccUtils::Role(this);
|
||||
if (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 &&
|
||||
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;
|
||||
}
|
||||
AccGroupInfo* groupInfo = GetGroupInfo();
|
||||
if (groupInfo) {
|
||||
*aPosInSet = groupInfo->PosInSet();
|
||||
*aSetSize = groupInfo->SetSize();
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "nsTArray.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
class AccGroupInfo;
|
||||
class nsAccessible;
|
||||
class nsAccEvent;
|
||||
struct nsRoleMapEntry;
|
||||
@ -324,7 +325,12 @@ protected:
|
||||
* Set accessible parent and index in parent.
|
||||
*/
|
||||
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.
|
||||
@ -424,6 +430,11 @@ protected:
|
||||
*/
|
||||
PRUint32 GetActionRule(PRUint32 aStates);
|
||||
|
||||
/**
|
||||
* Return group info.
|
||||
*/
|
||||
AccGroupInfo* GetGroupInfo();
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -440,6 +451,9 @@ protected:
|
||||
PRBool mAreChildrenInitialized;
|
||||
PRInt32 mIndexInParent;
|
||||
|
||||
nsAutoPtr<AccGroupInfo> mGroupInfo;
|
||||
friend class AccGroupInfo;
|
||||
|
||||
nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
|
||||
};
|
||||
|
||||
|
@ -953,6 +953,26 @@ nsHTMLTableAccessible::GetRowIndexAt(PRInt32 aIndex, PRInt32 *aRow)
|
||||
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
|
||||
nsHTMLTableAccessible::GetColumnExtentAt(PRInt32 aRowIndex,
|
||||
PRInt32 aColumnIndex,
|
||||
|
@ -666,33 +666,28 @@ __try {
|
||||
if (!tableAcc)
|
||||
return E_FAIL;
|
||||
|
||||
PRInt32 row = -1;
|
||||
nsresult rv = tableAcc->GetRowIndexAt(aIndex, &row);
|
||||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
|
||||
PRInt32 column = -1;
|
||||
rv = tableAcc->GetColumnIndexAt(aIndex, &column);
|
||||
PRInt32 rowIdx = -1, columnIdx = -1;
|
||||
nsresult rv = tableAcc->GetRowAndColumnIndicesAt(aIndex, &rowIdx, &columnIdx);
|
||||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
|
||||
PRInt32 rowExtents = 0;
|
||||
rv = tableAcc->GetRowExtentAt(row, column, &rowExtents);
|
||||
rv = tableAcc->GetRowExtentAt(rowIdx, columnIdx, &rowExtents);
|
||||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
|
||||
PRInt32 columnExtents = 0;
|
||||
rv = tableAcc->GetColumnExtentAt(row, column, &columnExtents);
|
||||
rv = tableAcc->GetColumnExtentAt(rowIdx, columnIdx, &columnExtents);
|
||||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
|
||||
PRBool isSelected = PR_FALSE;
|
||||
rv = tableAcc->IsCellSelected(row, column, &isSelected);
|
||||
rv = tableAcc->IsCellSelected(rowIdx, columnIdx, &isSelected);
|
||||
if (NS_FAILED(rv))
|
||||
return GetHRESULT(rv);
|
||||
|
||||
*aRow = row;
|
||||
*aColumn = column;
|
||||
*aRow = rowIdx;
|
||||
*aColumn = columnIdx;
|
||||
*aRowExtents = rowExtents;
|
||||
*aColumnExtents = columnExtents;
|
||||
*aIsSelected = isSelected;
|
||||
|
@ -412,6 +412,28 @@ nsXULListboxAccessible::GetRowIndexAt(PRInt32 aIndex, PRInt32 *aRow)
|
||||
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
|
||||
nsXULListboxAccessible::GetColumnExtentAt(PRInt32 aRow, PRInt32 aColumn,
|
||||
PRInt32 *aCellSpans)
|
||||
|
@ -411,6 +411,28 @@ nsXULTreeGridAccessible::GetRowIndexAt(PRInt32 aCellIndex, PRInt32 *aRowIndex)
|
||||
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
|
||||
nsXULTreeGridAccessible::GetColumnExtentAt(PRInt32 aRowIndex,
|
||||
PRInt32 aColumnIndex,
|
||||
|
@ -224,7 +224,7 @@ function testTableIndexes(aIdentifier, aIdxes)
|
||||
|
||||
if (idx != - 1) {
|
||||
|
||||
// getRowAtIndex
|
||||
// getRowIndexAt
|
||||
var origRowIdx = rowIdx;
|
||||
while (origRowIdx > 0 &&
|
||||
aIdxes[rowIdx][colIdx] == aIdxes[origRowIdx - 1][colIdx])
|
||||
@ -237,9 +237,9 @@ function testTableIndexes(aIdentifier, aIdxes)
|
||||
}
|
||||
|
||||
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;
|
||||
while (origColIdx > 0 &&
|
||||
aIdxes[rowIdx][colIdx] == aIdxes[rowIdx][origColIdx - 1])
|
||||
@ -252,7 +252,21 @@ function testTableIndexes(aIdentifier, aIdxes)
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
|
@ -320,8 +320,6 @@ pref("browser.tabs.loadInBackground", true);
|
||||
pref("browser.tabs.opentabfor.middleclick", true);
|
||||
pref("browser.tabs.loadDivertedInBackground", false);
|
||||
pref("browser.tabs.loadBookmarksInBackground", false);
|
||||
pref("browser.tabs.tabMinWidth", 100);
|
||||
pref("browser.tabs.tabMaxWidth", 250);
|
||||
pref("browser.tabs.tabClipWidth", 140);
|
||||
|
||||
// Where to show tab close buttons:
|
||||
|
@ -22,12 +22,18 @@ tabbrowser {
|
||||
|
||||
.tabbrowser-tab {
|
||||
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not([pinned]) {
|
||||
-moz-box-flex: 100;
|
||||
max-width: 250px;
|
||||
min-width: 100px;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.tabbrowser-tab:not([fadein]) {
|
||||
max-width: 1px !important;
|
||||
min-width: 1px !important;
|
||||
max-width: 1px;
|
||||
min-width: 1px;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[fadein]:not([pinned]) {
|
||||
@ -48,9 +54,6 @@ tabbrowser {
|
||||
|
||||
.tabbrowser-tab[pinned] {
|
||||
position: fixed;
|
||||
-moz-box-flex: 0;
|
||||
min-width: 0 !important;
|
||||
max-width: none !important;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[pinned] > .tab-text {
|
||||
@ -81,6 +84,12 @@ toolbar[printpreview="true"] {
|
||||
-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"] {
|
||||
display: none;
|
||||
}
|
||||
|
@ -4727,12 +4727,12 @@ var TabsOnTop = {
|
||||
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
function updateAppButtonDisplay() {
|
||||
var menubarHidden =
|
||||
var displayAppButton = window.menubar.visible &&
|
||||
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");
|
||||
else
|
||||
document.documentElement.removeAttribute("chromemargin");
|
||||
@ -7772,6 +7772,10 @@ var TabContextMenu = {
|
||||
Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore).
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -126,6 +126,12 @@
|
||||
accesskey="&openTabInNewWindow.accesskey;"
|
||||
tbattr="tabbrowser-multiple"
|
||||
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/>
|
||||
<menuitem id="context_bookmarkTab"
|
||||
label="&bookmarkThisTab.label;"
|
||||
|
@ -1210,9 +1210,6 @@
|
||||
t.setAttribute("label", aURI);
|
||||
|
||||
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("onerror", "this.removeAttribute('image');");
|
||||
t.className = "tabbrowser-tab";
|
||||
@ -2505,8 +2502,6 @@
|
||||
<implementation implements="nsIDOMEventListener">
|
||||
<constructor>
|
||||
<![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.mCloseButtons = Services.prefs.getIntPref("browser.tabs.closeButtons");
|
||||
this._closeWindowWithLastTab = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab");
|
||||
@ -2514,9 +2509,6 @@
|
||||
var tab = this.firstChild;
|
||||
tab.setAttribute("label",
|
||||
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("validate", "never");
|
||||
tab.setAttribute("onerror", "this.removeAttribute('image');");
|
||||
|
@ -25,7 +25,7 @@ function test() {
|
||||
function doTest() {
|
||||
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);
|
||||
while (tabContainer.childNodes.length < tabCountForOverflow)
|
||||
gBrowser.addTab("about:blank", {skipAnimation: true});
|
||||
|
@ -83,8 +83,7 @@ function test() {
|
||||
let numTests = 4;
|
||||
let completedTests = 0;
|
||||
|
||||
// access the pref service just once
|
||||
let tabMinWidth = gPrefService.getIntPref("browser.tabs.tabMinWidth");
|
||||
let tabMinWidth = parseInt(getComputedStyle(gBrowser.selectedTab, null).minWidth);
|
||||
|
||||
function runTest(testNum, totalTabs, selectedTab, shownTabs, order) {
|
||||
let test = {
|
||||
|
@ -22,6 +22,10 @@
|
||||
<!ENTITY closeOtherTabs.accesskey "o">
|
||||
<!ENTITY openTabInNewWindow.label "Open in a New Window">
|
||||
<!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.accesskey "B">
|
||||
<!ENTITY bookmarkAllTabs.label "Bookmark All Tabs…">
|
||||
|
@ -52,7 +52,7 @@ addonInstallManage.accesskey=O
|
||||
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-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.
|
||||
addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems.
|
||||
|
||||
|
@ -181,7 +181,7 @@ statusbarpanel#statusbar-display {
|
||||
position: relative !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;
|
||||
}
|
||||
%ifdef WINSTRIPE_AERO
|
||||
|
@ -40,12 +40,28 @@
|
||||
@import "chrome://global/skin/";
|
||||
|
||||
/* View buttons */
|
||||
#viewGroup {
|
||||
-moz-padding-start: 10px;
|
||||
}
|
||||
|
||||
#viewGroup > radio {
|
||||
list-style-image: url("chrome://browser/skin/pageInfo.png");
|
||||
-moz-box-orient: vertical;
|
||||
-moz-box-align: center;
|
||||
-moz-appearance: none;
|
||||
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 {
|
||||
|
@ -78,7 +78,7 @@ nsNullPrincipal::Release()
|
||||
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
|
||||
NS_LOG_RELEASE(this, count, "nsNullPrincipal");
|
||||
if (count == 0) {
|
||||
NS_DELETEXPCOM(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -166,7 +166,7 @@ nsPrincipal::Release()
|
||||
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
|
||||
NS_LOG_RELEASE(this, count, "nsPrincipal");
|
||||
if (count == 0) {
|
||||
NS_DELETEXPCOM(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -75,7 +75,7 @@ nsSystemPrincipal::Release()
|
||||
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
|
||||
NS_LOG_RELEASE(this, count, "nsSystemPrincipal");
|
||||
if (count == 0) {
|
||||
NS_DELETEXPCOM(this);
|
||||
delete this;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -51,10 +51,12 @@ function do_run_test()
|
||||
let cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIChromeRegistry);
|
||||
|
||||
var runtime = Components.classes["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Components.interfaces.nsIXULRuntime);
|
||||
if (runtime.processType ==
|
||||
Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
||||
// If we don't have libxul or e10s then we don't have process separation, so
|
||||
// we don't need to worry about checking for new chrome.
|
||||
var appInfo = Cc["@mozilla.org/xre/app-info;1"];
|
||||
if (!appInfo ||
|
||||
(appInfo.getService(Ci.nsIXULRuntime).processType ==
|
||||
Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT)) {
|
||||
cr.checkForNewChrome();
|
||||
}
|
||||
|
||||
|
@ -168,6 +168,7 @@ xpcshell-tests:
|
||||
-I$(topsrcdir)/build \
|
||||
$(testxpcsrcdir)/runxpcshelltests.py \
|
||||
--symbols-path=$(DIST)/crashreporter-symbols \
|
||||
$(EXTRA_TEST_ARGS) \
|
||||
$(DIST)/bin/xpcshell \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(MODULE)/$(dir))
|
||||
|
||||
@ -193,6 +194,8 @@ check-one:
|
||||
--symbols-path=$(DIST)/crashreporter-symbols \
|
||||
--test-path=$(SOLO_FILE) \
|
||||
--profile-name=$(MOZ_APP_NAME) \
|
||||
--verbose \
|
||||
$(EXTRA_TEST_ARGS) \
|
||||
$(DIST)/bin/xpcshell \
|
||||
$(foreach dir,$(XPCSHELL_TESTS),$(testxpcobjdir)/$(MODULE)/$(dir))
|
||||
|
||||
@ -2291,3 +2294,6 @@ CHECK_FROZEN_VARIABLES = $(foreach var,$(FREEZE_VARIABLES), \
|
||||
|
||||
libs export libs::
|
||||
$(CHECK_FROZEN_VARIABLES)
|
||||
|
||||
default::
|
||||
if test -d $(DIST)/bin ; then touch $(DIST)/bin/.purgecaches ; fi
|
||||
|
38
configure.in
38
configure.in
@ -1567,8 +1567,8 @@ if test "$GNU_CC"; then
|
||||
ASFLAGS="$ASFLAGS -fPIC"
|
||||
_MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti
|
||||
_MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti
|
||||
_MOZ_EXCEPTIONS_FLAGS_ON='-fhandle-exceptions'
|
||||
_MOZ_EXCEPTIONS_FLAGS_OFF='-fno-handle-exceptions'
|
||||
_MOZ_EXCEPTIONS_FLAGS_ON='-fexceptions'
|
||||
_MOZ_EXCEPTIONS_FLAGS_OFF='-fno-exceptions'
|
||||
|
||||
# Turn on GNU specific features
|
||||
# -Wall - turn on all warnings
|
||||
@ -2539,8 +2539,8 @@ ia64*-hpux*)
|
||||
USE_PTHREADS=1
|
||||
_PEDANTIC=
|
||||
LIBS="$LIBS -lsocket -lstdc++"
|
||||
_DEFINES_CFLAGS='-Wp,-include -Wp,$(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_CFLAGS='-include $(DEPTH)/mozilla-config.h -DMOZILLA_CLIENT -D_POSIX_C_SOURCE=199506'
|
||||
_DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -include $(DEPTH)/mozilla-config.h -D_POSIX_C_SOURCE=199506'
|
||||
if test "$with_x" != "yes"
|
||||
then
|
||||
_PLATFORM_DEFAULT_TOOLKIT="photon"
|
||||
@ -4024,32 +4024,6 @@ EOF
|
||||
esac
|
||||
|
||||
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 Put your C++ language/feature checks below
|
||||
dnl ========================================================
|
||||
@ -6005,7 +5979,7 @@ if test -n "$MOZ_SYDNEYAUDIO"; then
|
||||
linux*)
|
||||
PKG_CHECK_MODULES(MOZ_ALSA, alsa, ,
|
||||
[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
|
||||
fi
|
||||
@ -7977,7 +7951,7 @@ if test "$_cpp_md_flag"; then
|
||||
if test "$OS_ARCH" = "OpenVMS"; then
|
||||
_DEPEND_CFLAGS='$(subst =, ,$(filter-out %/.pp,-MM=-MD=-MF=$(MDDEPDIR)/$(basename $(@F)).pp))'
|
||||
else
|
||||
_DEPEND_CFLAGS='$(filter-out %/.pp,-Wp,-MD,$(MDDEPDIR)/$(basename $(@F)).pp)'
|
||||
_DEPEND_CFLAGS='$(filter-out %/.pp,-MD -MF $(MDDEPDIR)/$(basename $(@F)).pp)'
|
||||
fi
|
||||
dnl Sun Studio on Solaris use -xM instead of -MD, see config/rules.mk
|
||||
if test "$SOLARIS_SUNPRO_CC"; then
|
||||
|
@ -1360,8 +1360,7 @@ nsXMLHttpRequest::GetAllResponseHeaders(char **_retval)
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
|
||||
|
||||
if (httpChannel) {
|
||||
nsHeaderVisitor *visitor = nsnull;
|
||||
NS_NEWXPCOM(visitor, nsHeaderVisitor);
|
||||
nsHeaderVisitor *visitor = new nsHeaderVisitor();
|
||||
if (!visitor)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(visitor);
|
||||
|
@ -138,8 +138,8 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
|
||||
// If incrementing the generation would cause overflow,
|
||||
// don't allow it. Allowing this would allow us to use
|
||||
// resource handles created from older context generations.
|
||||
if (mGeneration + 1 == 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!(mGeneration+1).valid())
|
||||
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
|
||||
|
||||
if (mWidth == width && mHeight == height)
|
||||
return NS_OK;
|
||||
@ -181,7 +181,7 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
|
||||
mHeight = height;
|
||||
|
||||
// increment the generation number
|
||||
mGeneration++;
|
||||
++mGeneration;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
|
@ -60,6 +60,8 @@
|
||||
#include "GLContext.h"
|
||||
#include "Layers.h"
|
||||
|
||||
#include "CheckedInt.h"
|
||||
|
||||
#define UNPACK_FLIP_Y_WEBGL 0x9240
|
||||
#define UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241
|
||||
#define CONTEXT_LOST_WEBGL 0x9242
|
||||
@ -307,7 +309,7 @@ public:
|
||||
|
||||
// a number that increments every time we have an event that causes
|
||||
// all context resources to be lost.
|
||||
PRUint32 Generation() { return mGeneration; }
|
||||
PRUint32 Generation() { return mGeneration.value(); }
|
||||
protected:
|
||||
nsCOMPtr<nsIDOMHTMLCanvasElement> mCanvasElement;
|
||||
nsHTMLCanvasElement *HTMLCanvasElement() {
|
||||
@ -317,7 +319,7 @@ protected:
|
||||
nsRefPtr<gl::GLContext> gl;
|
||||
|
||||
PRInt32 mWidth, mHeight;
|
||||
PRUint32 mGeneration;
|
||||
CheckedUint32 mGeneration;
|
||||
|
||||
PRBool mInvalidated;
|
||||
|
||||
@ -335,6 +337,7 @@ protected:
|
||||
PRBool ValidateComparisonEnum(WebGLenum target, const char *info);
|
||||
PRBool ValidateStencilOpEnum(WebGLenum action, const char *info);
|
||||
PRBool ValidateFaceEnum(WebGLenum target, const char *info);
|
||||
PRBool ValidateBufferUsageEnum(WebGLenum target, const char *info);
|
||||
PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type,
|
||||
PRUint32 *texelSize, const char *info);
|
||||
|
||||
@ -705,7 +708,7 @@ public:
|
||||
WebGLuint GLName() { return mName; }
|
||||
const nsTArray<WebGLShader*>& AttachedShaders() const { return mAttachedShaders; }
|
||||
PRBool LinkStatus() { return mLinkStatus; }
|
||||
GLuint Generation() const { return mGeneration; }
|
||||
PRUint32 Generation() const { return mGeneration.value(); }
|
||||
void SetLinkStatus(PRBool val) { mLinkStatus = val; }
|
||||
|
||||
PRBool ContainsShader(WebGLShader *shader) {
|
||||
@ -742,10 +745,9 @@ public:
|
||||
|
||||
PRBool NextGeneration()
|
||||
{
|
||||
GLuint nextGeneration = mGeneration + 1;
|
||||
if (nextGeneration == 0)
|
||||
if (!(mGeneration+1).valid())
|
||||
return PR_FALSE; // must exit without changing mGeneration
|
||||
mGeneration = nextGeneration;
|
||||
++mGeneration;
|
||||
mMapUniformLocations.Clear();
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -770,7 +772,7 @@ protected:
|
||||
PRPackedBool mLinkStatus;
|
||||
nsTArray<WebGLShader*> mAttachedShaders;
|
||||
nsRefPtrHashtable<nsUint32HashKey, WebGLUniformLocation> mMapUniformLocations;
|
||||
GLuint mGeneration;
|
||||
CheckedUint32 mGeneration;
|
||||
GLint mUniformMaxNameLength;
|
||||
GLint mAttribMaxNameLength;
|
||||
GLint mUniformCount;
|
||||
@ -864,7 +866,7 @@ public:
|
||||
|
||||
WebGLProgram *Program() const { return mProgram; }
|
||||
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.
|
||||
PRBool Deleted() { return PR_FALSE; }
|
||||
@ -873,7 +875,7 @@ public:
|
||||
NS_DECL_NSIWEBGLUNIFORMLOCATION
|
||||
protected:
|
||||
WebGLObjectRefPtr<WebGLProgram> mProgram;
|
||||
GLuint mProgramGeneration;
|
||||
PRUint32 mProgramGeneration;
|
||||
GLint mLocation;
|
||||
};
|
||||
|
||||
|
@ -125,21 +125,6 @@ WebGLContext::Present()
|
||||
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); */
|
||||
NS_IMETHODIMP
|
||||
WebGLContext::ActiveTexture(WebGLenum texture)
|
||||
@ -292,7 +277,7 @@ WebGLContext::BindTexture(WebGLenum target, nsIWebGLTexture *tobj)
|
||||
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)
|
||||
{
|
||||
@ -362,6 +347,12 @@ WebGLContext::BufferData_size(WebGLenum target, WebGLsizei size, WebGLenum usage
|
||||
return ErrorInvalidEnum("BufferData: invalid target");
|
||||
}
|
||||
|
||||
if (size < 0)
|
||||
return ErrorInvalidValue("bufferData: negative size");
|
||||
|
||||
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
|
||||
return NS_OK;
|
||||
|
||||
if (!boundBuffer)
|
||||
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");
|
||||
}
|
||||
|
||||
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
|
||||
return NS_OK;
|
||||
|
||||
if (!boundBuffer)
|
||||
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");
|
||||
}
|
||||
|
||||
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
|
||||
return NS_OK;
|
||||
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("BufferData: no buffer bound!");
|
||||
|
||||
@ -449,8 +446,11 @@ WebGLContext::BufferSubData_buf(GLenum target, WebGLsizei byteOffset, js::ArrayB
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("BufferData: no buffer bound!");
|
||||
|
||||
// XXX check for overflow
|
||||
if (byteOffset + wb->byteLength > boundBuffer->ByteLength())
|
||||
CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + wb->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",
|
||||
byteOffset, wb->byteLength, boundBuffer->ByteLength());
|
||||
|
||||
@ -479,8 +479,11 @@ WebGLContext::BufferSubData_array(WebGLenum target, WebGLsizei byteOffset, js::T
|
||||
if (!boundBuffer)
|
||||
return ErrorInvalidOperation("BufferData: no buffer bound!");
|
||||
|
||||
// XXX check for overflow
|
||||
if (byteOffset + wa->byteLength > boundBuffer->ByteLength())
|
||||
CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + wa->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",
|
||||
byteOffset, wa->byteLength, boundBuffer->ByteLength());
|
||||
|
||||
@ -512,15 +515,15 @@ WebGLContext::Clear(PRUint32 mask)
|
||||
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
|
||||
GL_SAME_METHOD_1(ClearDepthf, ClearDepth, float)
|
||||
GL_SAME_METHOD_1(ClearDepthf, ClearDepth, WebGLfloat)
|
||||
#else
|
||||
GL_SAME_METHOD_1(ClearDepth, ClearDepth, float)
|
||||
GL_SAME_METHOD_1(ClearDepth, ClearDepth, WebGLfloat)
|
||||
#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)
|
||||
|
||||
@ -640,7 +643,16 @@ WebGLContext::CreateShader(WebGLenum type, nsIWebGLShader **retval)
|
||||
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
|
||||
WebGLContext::DeleteBuffer(nsIWebGLBuffer *bobj)
|
||||
@ -816,9 +828,9 @@ WebGLContext::DepthFunc(WebGLenum func)
|
||||
GL_SAME_METHOD_1(DepthMask, DepthMask, WebGLboolean)
|
||||
|
||||
#ifdef USE_GLES2
|
||||
GL_SAME_METHOD_2(DepthRangef, DepthRange, float, float)
|
||||
GL_SAME_METHOD_2(DepthRangef, DepthRange, WebGLfloat, WebGLfloat)
|
||||
#else
|
||||
GL_SAME_METHOD_2(DepthRange, DepthRange, float, float)
|
||||
GL_SAME_METHOD_2(DepthRange, DepthRange, WebGLfloat, WebGLfloat)
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -863,10 +875,12 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
|
||||
if (!mCurrentProgram)
|
||||
return NS_OK;
|
||||
|
||||
if (first+count < first || first+count < count)
|
||||
return ErrorInvalidOperation("DrawArrays: overflow in first+count");
|
||||
CheckedInt32 checked_firstPlusCount = CheckedInt32(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");
|
||||
|
||||
MakeContextCurrent();
|
||||
@ -897,20 +911,21 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
|
||||
if (count < 0 || byteOffset < 0)
|
||||
return ErrorInvalidValue("DrawElements: negative count or offset");
|
||||
|
||||
WebGLuint byteCount;
|
||||
if (type == LOCAL_GL_UNSIGNED_SHORT) {
|
||||
byteCount = WebGLuint(count) << 1;
|
||||
if (byteCount >> 1 != WebGLuint(count))
|
||||
return ErrorInvalidValue("DrawElements: overflow in byteCount");
|
||||
CheckedUint32 checked_byteCount;
|
||||
|
||||
if (type == LOCAL_GL_UNSIGNED_SHORT) {
|
||||
checked_byteCount = 2 * CheckedUint32(count);
|
||||
if (byteOffset % 2 != 0)
|
||||
return ErrorInvalidValue("DrawElements: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)");
|
||||
} else if (type == LOCAL_GL_UNSIGNED_BYTE) {
|
||||
byteCount = count;
|
||||
checked_byteCount = count;
|
||||
} else {
|
||||
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 == 0)
|
||||
return NS_OK;
|
||||
@ -923,10 +938,12 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
|
||||
if (!mBoundElementArrayBuffer)
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
WebGLuint maxIndex = 0;
|
||||
@ -936,8 +953,13 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type, Web
|
||||
maxIndex = mBoundElementArrayBuffer->FindMaximum<GLubyte>(count, byteOffset);
|
||||
}
|
||||
|
||||
// maxIndex+1 because ValidateBuffers expects the number of elements needed
|
||||
if (!ValidateBuffers(maxIndex+1)) {
|
||||
// maxIndex+1 because ValidateBuffers expects the number of elements needed.
|
||||
// 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 "
|
||||
"data for given indices from the bound element array");
|
||||
}
|
||||
@ -1306,14 +1328,7 @@ WebGLContext::GetParameter(PRUint32 pname, nsIVariant **retval)
|
||||
break;
|
||||
|
||||
#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:
|
||||
{
|
||||
#ifdef USE_GLES2
|
||||
@ -2117,7 +2132,7 @@ WebGLContext::IsEnabled(WebGLenum cap, WebGLboolean *retval)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GL_SAME_METHOD_1(LineWidth, LineWidth, float)
|
||||
GL_SAME_METHOD_1(LineWidth, LineWidth, WebGLfloat)
|
||||
|
||||
NS_IMETHODIMP
|
||||
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
|
||||
WebGLContext::ReadPixels(PRInt32 dummy)
|
||||
@ -2232,16 +2247,19 @@ WebGLContext::ReadPixels_base(WebGLint x, WebGLint y, WebGLsizei width, WebGLsiz
|
||||
PRUint32 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
|
||||
// packAlignment which is a power of 2
|
||||
PRUint32 alignedRowSize = (plainRowSize + packAlignment-1) &
|
||||
~PRUint32(packAlignment-1);
|
||||
// alignedRowSize = row size rounded up to next multiple of packAlignment
|
||||
CheckedUint32 checked_alignedRowSize
|
||||
= ((checked_plainRowSize + packAlignment-1) / packAlignment) * packAlignment;
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
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
|
||||
// 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_alignedRowSize = (subrect_plainRowSize + 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
|
||||
GLubyte *subrect_data = new GLubyte[subrect_byteLength];
|
||||
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) {
|
||||
GLint subrect_x_in_dest_buffer = subrect_x - x;
|
||||
GLint subrect_y_in_dest_buffer = subrect_y - y;
|
||||
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
|
||||
subrect_data + subrect_alignedRowSize * y_inside_subrect, // source
|
||||
subrect_plainRowSize); // size
|
||||
@ -2353,14 +2380,19 @@ WebGLContext::ReadPixels_byteLength_old_API_deprecated(WebGLsizei width, WebGLsi
|
||||
PRUint32 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
|
||||
// packAlignment which is a power of 2
|
||||
PRUint32 alignedRowSize = (plainRowSize + packAlignment-1) &
|
||||
~PRUint32(packAlignment-1);
|
||||
CheckedUint32 checked_alignedRowSize
|
||||
= ((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;
|
||||
}
|
||||
@ -2395,7 +2427,7 @@ WebGLContext::RenderbufferStorage(WebGLenum target, WebGLenum internalformat, We
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GL_SAME_METHOD_2(SampleCoverage, SampleCoverage, float, WebGLboolean)
|
||||
GL_SAME_METHOD_2(SampleCoverage, SampleCoverage, WebGLfloat, WebGLboolean)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height)
|
||||
@ -3021,11 +3053,15 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
|
||||
if (!ValidateTexFormatAndType(format, type, &texelSize, "texImage2D"))
|
||||
return NS_OK;
|
||||
|
||||
// XXX overflow!
|
||||
uint32 bytesNeeded = width * height * texelSize;
|
||||
CheckedUint32 checked_bytesNeeded = CheckedUint32(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)
|
||||
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);
|
||||
|
||||
MakeContextCurrent();
|
||||
@ -3154,8 +3190,13 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
|
||||
if (width == 0 || height == 0)
|
||||
return NS_OK; // ES 2.0 says it has no effect, we better return right now
|
||||
|
||||
// XXX overflow!
|
||||
uint32 bytesNeeded = width * height * texelSize;
|
||||
CheckedUint32 checked_bytesNeeded = CheckedUint32(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)
|
||||
return ErrorInvalidValue("TexSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
|
||||
|
||||
|
@ -39,6 +39,8 @@
|
||||
|
||||
#include "WebGLContext.h"
|
||||
|
||||
#include "CheckedInt.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/*
|
||||
@ -112,12 +114,18 @@ WebGLContext::ValidateBuffers(PRUint32 count)
|
||||
continue;
|
||||
|
||||
// compute the number of bytes we actually need
|
||||
WebGLuint needed = vd.byteOffset + // the base offset
|
||||
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 checked_needed = CheckedUint32(vd.byteOffset) + // the base offset
|
||||
CheckedUint32(vd.actualStride()) * (count-1) + // to stride to the start of the last element group
|
||||
CheckedUint32(vd.componentSize()) * vd.size; // and the number of bytes needed for these components
|
||||
|
||||
if (vd.buf->ByteLength() < needed) {
|
||||
LogMessage("VBO too small for bound attrib index %d: need at least %d bytes, but have only %d", i, needed, vd.buf->ByteLength());
|
||||
if (!checked_needed.valid()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
PRUint32 *texelSize, const char *info)
|
||||
{
|
||||
|
@ -1581,9 +1581,9 @@ nsGenericHTMLElement::ParseTableVAlignValue(const nsAString& aString,
|
||||
return aResult.ParseEnumValue(aString, kTableVAlignTable, PR_FALSE);
|
||||
}
|
||||
|
||||
PRBool
|
||||
PRBool
|
||||
nsGenericHTMLElement::ParseDivAlignValue(const nsAString& aString,
|
||||
nsAttrValue& aResult) const
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
return aResult.ParseEnumValue(aString, kDivAlignTable, PR_FALSE);
|
||||
}
|
||||
|
@ -253,8 +253,8 @@ public:
|
||||
* @param aResult the resulting HTMLValue
|
||||
* @return whether the value was parsed
|
||||
*/
|
||||
PRBool ParseDivAlignValue(const nsAString& aString,
|
||||
nsAttrValue& aResult) const;
|
||||
static PRBool ParseDivAlignValue(const nsAString& aString,
|
||||
nsAttrValue& aResult);
|
||||
|
||||
/**
|
||||
* Convert a table halign string to value (left/right/center/char/justify)
|
||||
|
@ -148,11 +148,13 @@ NS_NewHTMLNOTUSEDElement(nsINodeInfo *aNodeInfo, PRUint32 aFromParser)
|
||||
}
|
||||
|
||||
#define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element,
|
||||
#define HTML_HTMLELEMENT_TAG(_tag) NS_NewHTMLElement,
|
||||
#define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
|
||||
static const contentCreatorCallback sContentCreatorCallbacks[] = {
|
||||
NS_NewHTMLUnknownElement,
|
||||
#include "nsHTMLTagList.h"
|
||||
#undef HTML_TAG
|
||||
#undef HTML_HTMLELEMENT_TAG
|
||||
#undef HTML_OTHER
|
||||
NS_NewHTMLUnknownElement
|
||||
};
|
||||
|
@ -1254,21 +1254,11 @@ nsHTMLDocument::CreateElement(const nsAString& aTagName,
|
||||
nsIDOMElement** aReturn)
|
||||
{
|
||||
*aReturn = nsnull;
|
||||
nsresult rv;
|
||||
nsresult rv = nsContentUtils::CheckQName(aTagName, PR_FALSE);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
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()) {
|
||||
ToLowerCase(tagName);
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ _TEST_FILES = test_bug1682.html \
|
||||
test_bug311681.xhtml \
|
||||
test_bug324378.html \
|
||||
test_bug332848.xhtml \
|
||||
test_bug340017.xhtml \
|
||||
test_bug359657.html \
|
||||
test_bug369370.html \
|
||||
bug369370-popup.png \
|
||||
@ -95,13 +96,13 @@ _TEST_FILES = test_bug1682.html \
|
||||
test_bug481647.html \
|
||||
test_bug482659.html \
|
||||
test_bug486741.html \
|
||||
test_bug489532.html \
|
||||
test_bug497242.xhtml \
|
||||
test_bug512367.html \
|
||||
test_bug570375.html \
|
||||
test_bug340017.xhtml \
|
||||
test_bug499092.html \
|
||||
bug499092.xml \
|
||||
bug499092.html \
|
||||
test_bug512367.html \
|
||||
test_bug570376.html \
|
||||
test_bug571981.html \
|
||||
$(NULL)
|
||||
|
||||
|
32
content/html/document/test/test_bug489532.html
Normal file
32
content/html/document/test/test_bug489532.html
Normal 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>
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=570375
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=570376
|
||||
-->
|
||||
<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="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=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">
|
||||
<iframe id="testiframe"></iframe>
|
||||
</p>
|
||||
@ -19,7 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=570375
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 570375
|
||||
/** Test for Bug 570376
|
||||
Don't crash loading <form><legend> with the html5 parser preffed off.
|
||||
**/
|
||||
|
@ -325,6 +325,9 @@ nsSMILAnimationController::DoSample(PRBool aSkipUnchangedContainers)
|
||||
mResampleNeeded = PR_FALSE;
|
||||
|
||||
// STEP 1: Bring model up to date
|
||||
// (i) Rewind elements where necessary
|
||||
// (ii) Run milestone samples
|
||||
RewindElements();
|
||||
DoMilestoneSamples();
|
||||
|
||||
// STEP 2: Sample the child time containers
|
||||
@ -402,6 +405,56 @@ nsSMILAnimationController::DoSample(PRBool aSkipUnchangedContainers)
|
||||
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
|
||||
nsSMILAnimationController::DoMilestoneSamples()
|
||||
{
|
||||
@ -542,6 +595,7 @@ nsSMILAnimationController::SampleTimeContainer(TimeContainerPtrKey* aKey,
|
||||
(container->NeedsSample() || !params->mSkipUnchangedContainers)) {
|
||||
container->ClearMilestones();
|
||||
container->Sample();
|
||||
container->MarkSeekFinished();
|
||||
params->mActiveContainers->PutEntry(container);
|
||||
}
|
||||
|
||||
@ -587,6 +641,8 @@ nsSMILAnimationController::SampleTimedElement(
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -152,11 +152,21 @@ protected:
|
||||
// Sample-related callbacks and implementation helpers
|
||||
virtual void DoSample();
|
||||
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();
|
||||
PR_STATIC_CALLBACK(PLDHashOperator) GetNextMilestone(
|
||||
TimeContainerPtrKey* aKey, void* aData);
|
||||
PR_STATIC_CALLBACK(PLDHashOperator) GetMilestoneElements(
|
||||
TimeContainerPtrKey* aKey, void* aData);
|
||||
|
||||
PR_STATIC_CALLBACK(PLDHashOperator) SampleTimeContainer(
|
||||
TimeContainerPtrKey* aKey, void* aData);
|
||||
PR_STATIC_CALLBACK(PLDHashOperator) SampleAnimation(
|
||||
|
@ -74,9 +74,9 @@ nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
|
||||
nsSMILInterval* aBaseInterval)
|
||||
: mTime(aTime),
|
||||
mFlags(0),
|
||||
mSerial(0),
|
||||
mVisited(PR_FALSE),
|
||||
mChainEnd(PR_FALSE),
|
||||
mFixedEndpointRefCnt(0),
|
||||
mSerial(0),
|
||||
mCreator(aCreator),
|
||||
mBaseInterval(nsnull) // This will get set to aBaseInterval in a call to
|
||||
// SetBaseInterval() at end of constructor
|
||||
@ -87,7 +87,7 @@ nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
|
||||
break;
|
||||
|
||||
case SOURCE_DOM:
|
||||
mFlags = kClearOnReset | kFromDOM;
|
||||
mFlags = kDynamic | kFromDOM;
|
||||
break;
|
||||
|
||||
case SOURCE_SYNCBASE:
|
||||
@ -95,7 +95,7 @@ nsSMILInstanceTime::nsSMILInstanceTime(const nsSMILTimeValue& aTime,
|
||||
break;
|
||||
|
||||
case SOURCE_EVENT:
|
||||
mFlags = kClearOnReset;
|
||||
mFlags = kDynamic;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -106,6 +106,9 @@ nsSMILInstanceTime::~nsSMILInstanceTime()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mBaseInterval && !mCreator,
|
||||
"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
|
||||
@ -129,12 +132,9 @@ nsSMILInstanceTime::HandleChangedInterval(
|
||||
"Got call to HandleChangedInterval on an independent instance time.");
|
||||
NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not.");
|
||||
|
||||
if (mVisited || mChainEnd) {
|
||||
// We're breaking the cycle here but we need to ensure that if we later
|
||||
// receive a change notice in a different context (e.g. due to a time
|
||||
// container change) that we don't end up following the chain further and so
|
||||
// we set a flag to that effect.
|
||||
mChainEnd = PR_TRUE;
|
||||
if (mVisited) {
|
||||
// Break the cycle here
|
||||
Unlink();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -152,20 +152,63 @@ void
|
||||
nsSMILInstanceTime::HandleDeletedInterval()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mBaseInterval,
|
||||
"Got call to HandleDeletedInterval on an independent instance time.");
|
||||
NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not.");
|
||||
"Got call to HandleDeletedInterval on an independent instance time");
|
||||
NS_ABORT_IF_FALSE(mCreator, "Base interval is set but creator is not");
|
||||
|
||||
mBaseInterval = nsnull;
|
||||
mFlags &= ~kMayUpdate; // Can't update without a base interval
|
||||
|
||||
nsRefPtr<nsSMILInstanceTime> deathGrip(this);
|
||||
mCreator->HandleDeletedInstanceTime(*this);
|
||||
mCreator = nsnull;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSMILInstanceTime::IsDependent(const nsSMILInstanceTime& aOther) const
|
||||
void
|
||||
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;
|
||||
|
||||
const nsSMILInstanceTime* myBaseTime = GetBaseTime();
|
||||
@ -177,7 +220,7 @@ nsSMILInstanceTime::IsDependent(const nsSMILInstanceTime& aOther) const
|
||||
|
||||
// mVisited is mutable
|
||||
AutoBoolSetter setVisited(const_cast<nsSMILInstanceTime*>(this)->mVisited);
|
||||
return myBaseTime->IsDependent(aOther);
|
||||
return myBaseTime->IsDependentOn(aOther);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -92,24 +92,31 @@ public:
|
||||
PRBool aBeginObjectChanged,
|
||||
PRBool aEndObjectChanged);
|
||||
void HandleDeletedInterval();
|
||||
void HandleFilteredInterval();
|
||||
|
||||
const nsSMILTimeValue& Time() const { return mTime; }
|
||||
const nsSMILTimeValueSpec* GetCreator() const { return mCreator; }
|
||||
|
||||
PRBool ClearOnReset() const { return !!(mFlags & kClearOnReset); }
|
||||
PRBool MayUpdate() const { return !!(mFlags & kMayUpdate); }
|
||||
PRBool IsDynamic() const { return !!(mFlags & kDynamic); }
|
||||
PRBool IsFixedTime() const { return !(mFlags & kMayUpdate); }
|
||||
PRBool FromDOM() const { return !!(mFlags & kFromDOM); }
|
||||
|
||||
void MarkNoLongerUpdating() { mFlags &= ~kMayUpdate; }
|
||||
PRBool ShouldPreserve() const;
|
||||
void UnmarkShouldPreserve();
|
||||
|
||||
void AddRefFixedEndpoint();
|
||||
void ReleaseFixedEndpoint();
|
||||
|
||||
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");
|
||||
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
|
||||
{
|
||||
@ -131,15 +138,16 @@ protected:
|
||||
|
||||
// Internal flags used to represent the behaviour of different instance times
|
||||
enum {
|
||||
// Indicates if this instance time should be removed when the owning timed
|
||||
// element is reset. True for events and DOM calls.
|
||||
kClearOnReset = 1,
|
||||
// Indicates that this instance time was generated by an event or a DOM
|
||||
// call. Such instance times require special handling when (i) the owning
|
||||
// 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
|
||||
// nsSMILTimeValueSpec and as such may be updated. Such instance time should
|
||||
// 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
|
||||
// syncbase-generated times until they are frozen.
|
||||
// in the past as they may be updated to a future time.
|
||||
kMayUpdate = 2,
|
||||
|
||||
// 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
|
||||
// that attribute (and hence an nsSMILTimeValueSpec), but not those from the
|
||||
// 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
|
||||
// specify the sort order for instance times with the
|
||||
// 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
|
||||
// us. (currently only needed for syncbase
|
||||
|
@ -39,6 +39,8 @@
|
||||
|
||||
nsSMILInterval::nsSMILInterval()
|
||||
:
|
||||
mBeginFixed(PR_FALSE),
|
||||
mEndFixed(PR_FALSE),
|
||||
mBeginObjectChanged(PR_FALSE),
|
||||
mEndObjectChanged(PR_FALSE)
|
||||
{
|
||||
@ -48,19 +50,28 @@ nsSMILInterval::nsSMILInterval(const nsSMILInterval& aOther)
|
||||
:
|
||||
mBegin(aOther.mBegin),
|
||||
mEnd(aOther.mEnd),
|
||||
mBeginFixed(PR_FALSE),
|
||||
mEndFixed(PR_FALSE),
|
||||
mBeginObjectChanged(PR_FALSE),
|
||||
mEndObjectChanged(PR_FALSE)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aOther.mDependentTimes.IsEmpty(),
|
||||
"Attempting to copy-construct an interval with dependent times, "
|
||||
"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()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mDependentTimes.IsEmpty(),
|
||||
"Destroying interval without disassociating dependent instance times. "
|
||||
"NotifyDeleting was not called.");
|
||||
"Unlink was not called");
|
||||
}
|
||||
|
||||
void
|
||||
@ -76,12 +87,24 @@ nsSMILInterval::NotifyChanged(const nsSMILTimeContainer* aContainer)
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILInterval::NotifyDeleting()
|
||||
nsSMILInterval::Unlink(PRBool aFiltered)
|
||||
{
|
||||
for (PRInt32 i = mDependentTimes.Length() - 1; i >= 0; --i) {
|
||||
mDependentTimes[i]->HandleDeletedInterval();
|
||||
if (aFiltered) {
|
||||
mDependentTimes[i]->HandleFilteredInterval();
|
||||
} else {
|
||||
mDependentTimes[i]->HandleDeletedInterval();
|
||||
}
|
||||
}
|
||||
mDependentTimes.Clear();
|
||||
if (mBegin && mBeginFixed) {
|
||||
mBegin->ReleaseFixedEndpoint();
|
||||
}
|
||||
mBegin = nsnull;
|
||||
if (mEnd && mEndFixed) {
|
||||
mEnd->ReleaseFixedEndpoint();
|
||||
}
|
||||
mEnd = nsnull;
|
||||
}
|
||||
|
||||
nsSMILInstanceTime*
|
||||
@ -104,7 +127,9 @@ void
|
||||
nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin)
|
||||
{
|
||||
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)
|
||||
return;
|
||||
@ -116,6 +141,9 @@ nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin)
|
||||
void
|
||||
nsSMILInterval::SetEnd(nsSMILInstanceTime& aEnd)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mEndFixed,
|
||||
"Attempting to set end time but the end point is fixed");
|
||||
|
||||
if (mEnd == &aEnd)
|
||||
return;
|
||||
|
||||
@ -123,6 +151,28 @@ nsSMILInterval::SetEnd(nsSMILInstanceTime& aEnd)
|
||||
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
|
||||
nsSMILInterval::AddDependentTime(nsSMILInstanceTime& aTime)
|
||||
{
|
||||
@ -142,3 +192,19 @@ nsSMILInterval::RemoveDependentTime(const nsSMILInstanceTime& aTime)
|
||||
mDependentTimes.RemoveElementSorted(&aTime);
|
||||
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);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
nsSMILInterval(const nsSMILInterval& aOther);
|
||||
~nsSMILInterval();
|
||||
void NotifyChanged(const nsSMILTimeContainer* aContainer);
|
||||
void NotifyDeleting();
|
||||
void Unlink(PRBool aFiltered = PR_FALSE);
|
||||
|
||||
const nsSMILInstanceTime* Begin() const
|
||||
{
|
||||
@ -83,37 +83,15 @@ public:
|
||||
SetEnd(aEnd);
|
||||
}
|
||||
|
||||
void FreezeBegin()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mBegin && mEnd,
|
||||
"Freezing Begin() on un-initialized instance time");
|
||||
mBegin->MarkNoLongerUpdating();
|
||||
}
|
||||
|
||||
void FreezeEnd()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(mBegin && mEnd,
|
||||
"Freezing End() on un-initialized instance time");
|
||||
NS_ABORT_IF_FALSE(!mBegin->MayUpdate(),
|
||||
"Freezing the end of an interval without a fixed begin");
|
||||
mEnd->MarkNoLongerUpdating();
|
||||
}
|
||||
|
||||
// XXX Backwards seeking support (bug 492458)
|
||||
void Unfreeze()
|
||||
{
|
||||
// XXX
|
||||
UnfreezeEnd();
|
||||
}
|
||||
|
||||
void UnfreezeEnd()
|
||||
{
|
||||
// XXX
|
||||
}
|
||||
void FixBegin();
|
||||
void FixEnd();
|
||||
|
||||
void AddDependentTime(nsSMILInstanceTime& aTime);
|
||||
void RemoveDependentTime(const nsSMILInstanceTime& aTime);
|
||||
|
||||
// Cue for assessing if this interval can be filtered
|
||||
PRBool IsDependencyChainLink() const;
|
||||
|
||||
private:
|
||||
nsRefPtr<nsSMILInstanceTime> mBegin;
|
||||
nsRefPtr<nsSMILInstanceTime> mEnd;
|
||||
@ -123,6 +101,18 @@ private:
|
||||
// nsSMILInstanceTimes to notify when this interval is changed or deleted.
|
||||
InstanceTimeList mDependentTimes;
|
||||
|
||||
// Indicates if the end points of the interval are fixed or not.
|
||||
//
|
||||
// Note that this is not the same as having an end point whose TIME is fixed
|
||||
// (i.e. nsSMILInstanceTime::IsFixed() returns PR_TRUE). This is because it is
|
||||
// possible to have an end point with a fixed TIME and yet still update the
|
||||
// end point to refer to a different nsSMILInstanceTime object.
|
||||
//
|
||||
// However, if mBegin/EndFixed is PR_TRUE, then BOTH the nsSMILInstanceTime
|
||||
// OBJECT returned for that end point and its TIME value will not change.
|
||||
PRPackedBool mBeginFixed;
|
||||
PRPackedBool mEndFixed;
|
||||
|
||||
// When change notifications are passed around the timing model we try to
|
||||
// filter out all changes where there is no observable difference to an
|
||||
// instance time. Changes that may produce an observable difference are:
|
||||
|
@ -46,6 +46,8 @@ nsSMILTimeContainer::nsSMILTimeContainer()
|
||||
mParentOffset(0L),
|
||||
mPauseStart(0L),
|
||||
mNeedsPauseSample(PR_FALSE),
|
||||
mNeedsRewind(PR_FALSE),
|
||||
mIsSeeking(PR_FALSE),
|
||||
mPauseState(PAUSE_BEGIN)
|
||||
{
|
||||
}
|
||||
@ -145,6 +147,10 @@ nsSMILTimeContainer::GetCurrentTime() const
|
||||
void
|
||||
nsSMILTimeContainer::SetCurrentTime(nsSMILTime aSeekTo)
|
||||
{
|
||||
// SVG 1.1 doesn't specify what to do for negative times so we adopt SVGT1.2's
|
||||
// behaviour of clamping negative times to 0.
|
||||
aSeekTo = PR_MAX(0, aSeekTo);
|
||||
|
||||
// The following behaviour is consistent with:
|
||||
// http://www.w3.org/2003/01/REC-SVG11-20030114-errata
|
||||
// #getCurrentTime_setCurrentTime_undefined_before_document_timeline_begin
|
||||
@ -152,12 +158,19 @@ nsSMILTimeContainer::SetCurrentTime(nsSMILTime aSeekTo)
|
||||
// has begun we should still adjust the offset.
|
||||
nsSMILTime parentTime = GetParentTime();
|
||||
mParentOffset = parentTime - aSeekTo;
|
||||
mIsSeeking = PR_TRUE;
|
||||
|
||||
if (IsPaused()) {
|
||||
mNeedsPauseSample = PR_TRUE;
|
||||
mPauseStart = parentTime;
|
||||
}
|
||||
|
||||
if (aSeekTo < mCurrentTime) {
|
||||
// Backwards seek
|
||||
mNeedsRewind = PR_TRUE;
|
||||
ClearMilestones();
|
||||
}
|
||||
|
||||
// Force an update to the current time in case we get a call to GetCurrentTime
|
||||
// before another call to Sample().
|
||||
UpdateCurrentTime();
|
||||
|
@ -170,6 +170,21 @@ public:
|
||||
*/
|
||||
PRBool NeedsSample() const { return !mPauseState || mNeedsPauseSample; }
|
||||
|
||||
/*
|
||||
* Indicates if the elements of this time container need to be rewound.
|
||||
* This occurs during a backwards seek.
|
||||
*/
|
||||
PRBool NeedsRewind() const { return mNeedsRewind; }
|
||||
void ClearNeedsRewind() { mNeedsRewind = PR_FALSE; }
|
||||
|
||||
/*
|
||||
* Indicates the time container is currently processing a SetCurrentTime
|
||||
* request and appropriate seek behaviour should be applied by child elements
|
||||
* (e.g. not firing time events).
|
||||
*/
|
||||
PRBool IsSeeking() const { return mIsSeeking; }
|
||||
void MarkSeekFinished() { mIsSeeking = PR_FALSE; }
|
||||
|
||||
/*
|
||||
* Sets the parent time container.
|
||||
*
|
||||
@ -279,6 +294,9 @@ protected:
|
||||
// Whether or not a pause sample is required
|
||||
PRPackedBool mNeedsPauseSample;
|
||||
|
||||
PRPackedBool mNeedsRewind; // Backwards seek performed
|
||||
PRPackedBool mIsSeeking; // Currently in the middle of a seek operation
|
||||
|
||||
// A bitfield of the pause state for all pause requests
|
||||
PRUint32 mPauseState;
|
||||
|
||||
|
@ -160,8 +160,8 @@ nsSMILTimeValueSpec::HandleChangedInstanceTime(
|
||||
PRBool aObjectChanged)
|
||||
{
|
||||
// If the instance time is fixed (e.g. because it's being used as the begin
|
||||
// time of an active interval) we just ignore the change.
|
||||
if (!aInstanceTimeToUpdate.MayUpdate())
|
||||
// time of an active or postactive interval) we just ignore the change.
|
||||
if (aInstanceTimeToUpdate.IsFixedTime())
|
||||
return;
|
||||
|
||||
nsSMILTimeValue updatedTime =
|
||||
|
@ -90,6 +90,29 @@ nsSMILTimedElement::InstanceTimeComparator::LessThan(
|
||||
return cmp == 0 ? aElem1->Serial() < aElem2->Serial() : cmp < 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Templated helper functions
|
||||
|
||||
// Selectively remove elements from an array of type
|
||||
// nsTArray<nsRefPtr<nsSMILInstanceTime> > with O(n) performance.
|
||||
template <class TestFunctor>
|
||||
void
|
||||
nsSMILTimedElement::RemoveInstanceTimes(InstanceTimeList& aArray,
|
||||
TestFunctor& aTest)
|
||||
{
|
||||
InstanceTimeList newArray;
|
||||
for (PRUint32 i = 0; i < aArray.Length(); ++i) {
|
||||
nsSMILInstanceTime* item = aArray[i].get();
|
||||
if (aTest(item, i)) {
|
||||
item->Unlink();
|
||||
} else {
|
||||
newArray.AppendElement(item);
|
||||
}
|
||||
}
|
||||
aArray.Clear();
|
||||
aArray.SwapElements(newArray);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Static members
|
||||
|
||||
@ -108,6 +131,12 @@ nsAttrValue::EnumTable nsSMILTimedElement::sRestartModeTable[] = {
|
||||
|
||||
const nsSMILMilestone nsSMILTimedElement::sMaxMilestone(LL_MAXINT, PR_FALSE);
|
||||
|
||||
// The thresholds at which point we start filtering intervals and instance times
|
||||
// indiscriminately.
|
||||
// See FilterIntervals and FilterInstanceTimes.
|
||||
const PRUint8 nsSMILTimedElement::sMaxNumIntervals = 20;
|
||||
const PRUint8 nsSMILTimedElement::sMaxNumInstanceTimes = 100;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Ctor, dtor
|
||||
|
||||
@ -122,7 +151,8 @@ nsSMILTimedElement::nsSMILTimedElement()
|
||||
mClient(nsnull),
|
||||
mCurrentInterval(nsnull),
|
||||
mPrevRegisteredMilestone(sMaxMilestone),
|
||||
mElementState(STATE_STARTUP)
|
||||
mElementState(STATE_STARTUP),
|
||||
mSeekState(SEEK_NOT_SEEKING)
|
||||
{
|
||||
mSimpleDur.SetIndefinite();
|
||||
mMin.SetMillis(0L);
|
||||
@ -149,12 +179,12 @@ nsSMILTimedElement::~nsSMILTimedElement()
|
||||
// (We shouldn't get any callbacks from this because all our instance times
|
||||
// are now disassociated with any intervals)
|
||||
if (mCurrentInterval) {
|
||||
mCurrentInterval->NotifyDeleting();
|
||||
mCurrentInterval->Unlink();
|
||||
mCurrentInterval = nsnull;
|
||||
}
|
||||
|
||||
for (PRInt32 i = mOldIntervals.Length() - 1; i >= 0; --i) {
|
||||
mOldIntervals[i]->NotifyDeleting();
|
||||
mOldIntervals[i]->Unlink();
|
||||
}
|
||||
mOldIntervals.Clear();
|
||||
}
|
||||
@ -332,22 +362,33 @@ nsSMILTimedElement::RemoveInstanceTime(nsSMILInstanceTime* aInstanceTime,
|
||||
UpdateCurrentInterval();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class RemoveByCreator
|
||||
{
|
||||
public:
|
||||
RemoveByCreator(const nsSMILTimeValueSpec* aCreator) : mCreator(aCreator)
|
||||
{ }
|
||||
|
||||
PRBool operator()(nsSMILInstanceTime* aInstanceTime, PRUint32 /*aIndex*/)
|
||||
{
|
||||
return aInstanceTime->GetCreator() == mCreator;
|
||||
}
|
||||
|
||||
private:
|
||||
const nsSMILTimeValueSpec* mCreator;
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::RemoveInstanceTimesForCreator(
|
||||
const nsSMILTimeValueSpec* aCreator, PRBool aIsBegin)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(aCreator, "Creator not set");
|
||||
InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
|
||||
|
||||
PRInt32 count = instances.Length();
|
||||
for (PRInt32 i = count - 1; i >= 0; --i) {
|
||||
nsSMILInstanceTime* instance = instances[i].get();
|
||||
NS_ABORT_IF_FALSE(instance, "NULL instance in instances array");
|
||||
if (instance->GetCreator() == aCreator) {
|
||||
instance->Unlink();
|
||||
instances.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
|
||||
RemoveByCreator removeByCreator(aCreator);
|
||||
RemoveInstanceTimes(instances, removeByCreator);
|
||||
|
||||
UpdateCurrentInterval();
|
||||
}
|
||||
@ -416,6 +457,16 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
|
||||
"Got a regular sample during startup state, expected an end sample"
|
||||
" instead");
|
||||
|
||||
PRBool finishedSeek = PR_FALSE;
|
||||
if (GetTimeContainer()->IsSeeking() && mSeekState == SEEK_NOT_SEEKING) {
|
||||
mSeekState = mElementState == STATE_ACTIVE ?
|
||||
SEEK_FORWARD_FROM_ACTIVE :
|
||||
SEEK_FORWARD_FROM_INACTIVE;
|
||||
} else if (mSeekState != SEEK_NOT_SEEKING &&
|
||||
!GetTimeContainer()->IsSeeking()) {
|
||||
finishedSeek = PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool stateChanged;
|
||||
nsSMILTimeValue sampleTime(aContainerTime);
|
||||
|
||||
@ -445,12 +496,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
|
||||
stateChanged = PR_TRUE;
|
||||
if (mElementState == STATE_WAITING) {
|
||||
mCurrentInterval = new nsSMILInterval(firstInterval);
|
||||
if (!mCurrentInterval) {
|
||||
NS_WARNING("Failed to allocate memory for new interval");
|
||||
mElementState = STATE_POSTACTIVE;
|
||||
} else {
|
||||
NotifyNewInterval();
|
||||
}
|
||||
NotifyNewInterval();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -459,7 +505,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
|
||||
{
|
||||
if (mCurrentInterval->Begin()->Time() <= sampleTime) {
|
||||
mElementState = STATE_ACTIVE;
|
||||
mCurrentInterval->FreezeBegin();
|
||||
mCurrentInterval->FixBegin();
|
||||
if (HasPlayed()) {
|
||||
Reset(); // Apply restart behaviour
|
||||
}
|
||||
@ -483,14 +529,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
|
||||
|
||||
case STATE_ACTIVE:
|
||||
{
|
||||
// Only apply an early end if we're not already ending.
|
||||
if (mCurrentInterval->End()->Time() > sampleTime) {
|
||||
nsSMILInstanceTime* earlyEnd = CheckForEarlyEnd(sampleTime);
|
||||
if (earlyEnd) {
|
||||
mCurrentInterval->SetEnd(*earlyEnd);
|
||||
NotifyChangedInterval();
|
||||
}
|
||||
}
|
||||
ApplyEarlyEnd(sampleTime);
|
||||
|
||||
if (mCurrentInterval->End()->Time() <= sampleTime) {
|
||||
nsSMILInterval newInterval;
|
||||
@ -501,22 +540,20 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
|
||||
if (mClient) {
|
||||
mClient->Inactivate(mFillMode == FILL_FREEZE);
|
||||
}
|
||||
mCurrentInterval->FreezeEnd();
|
||||
mCurrentInterval->FixEnd();
|
||||
mOldIntervals.AppendElement(mCurrentInterval.forget());
|
||||
// We must update mOldIntervals before calling SampleFillValue
|
||||
SampleFillValue();
|
||||
if (mElementState == STATE_WAITING) {
|
||||
mCurrentInterval = new nsSMILInterval(newInterval);
|
||||
if (!mCurrentInterval) {
|
||||
NS_WARNING("Failed to allocate memory for new interval");
|
||||
mElementState = STATE_POSTACTIVE;
|
||||
} else {
|
||||
NotifyNewInterval();
|
||||
}
|
||||
NotifyNewInterval();
|
||||
}
|
||||
FilterHistory();
|
||||
stateChanged = PR_TRUE;
|
||||
} else {
|
||||
nsSMILTime beginTime = mCurrentInterval->Begin()->Time().GetMillis();
|
||||
NS_ASSERTION(aContainerTime >= beginTime,
|
||||
"Sample time should not precede current interval");
|
||||
nsSMILTime activeTime = aContainerTime - beginTime;
|
||||
SampleSimpleTime(activeTime);
|
||||
}
|
||||
@ -536,6 +573,9 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly)
|
||||
} while (stateChanged && (!aEndOnly || (mElementState != STATE_WAITING &&
|
||||
mElementState != STATE_POSTACTIVE)));
|
||||
|
||||
if (finishedSeek) {
|
||||
DoPostSeek();
|
||||
}
|
||||
RegisterMilestone();
|
||||
}
|
||||
|
||||
@ -553,34 +593,46 @@ nsSMILTimedElement::HandleContainerTimeChange()
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::Reset()
|
||||
nsSMILTimedElement::Rewind()
|
||||
{
|
||||
// SMIL 3.0 section 5.4.3, 'Resetting element state':
|
||||
// Any instance times associated with past Event-values, Repeat-values,
|
||||
// Accesskey-values or added via DOM method calls are removed from the
|
||||
// dependent begin and end instance times lists. In effect, all events and
|
||||
// DOM methods calls in the past are cleared. This does not apply to an
|
||||
// instance time that defines the begin of the current interval.
|
||||
PRInt32 count = mBeginInstances.Length();
|
||||
for (PRInt32 i = count - 1; i >= 0; --i) {
|
||||
nsSMILInstanceTime* instance = mBeginInstances[i].get();
|
||||
NS_ABORT_IF_FALSE(instance, "NULL instance in begin instances array");
|
||||
if (instance->ClearOnReset() &&
|
||||
(!mCurrentInterval || instance != mCurrentInterval->Begin())) {
|
||||
instance->Unlink();
|
||||
mBeginInstances.RemoveElementAt(i);
|
||||
}
|
||||
NS_ABORT_IF_FALSE(mAnimationElement,
|
||||
"Got rewind request before being attached to an animation element");
|
||||
NS_ABORT_IF_FALSE(mSeekState == SEEK_NOT_SEEKING,
|
||||
"Got rewind request whilst already seeking");
|
||||
|
||||
mSeekState = mElementState == STATE_ACTIVE ?
|
||||
SEEK_BACKWARD_FROM_ACTIVE :
|
||||
SEEK_BACKWARD_FROM_INACTIVE;
|
||||
|
||||
// Set the STARTUP state first so that if we get any callbacks we won't waste
|
||||
// time recalculating the current interval
|
||||
mElementState = STATE_STARTUP;
|
||||
|
||||
// Clear the intervals and instance times except those instance times we can't
|
||||
// regenerate (DOM calls etc.)
|
||||
RewindTiming();
|
||||
|
||||
UnsetBeginSpec();
|
||||
UnsetEndSpec();
|
||||
|
||||
if (mClient) {
|
||||
mClient->Inactivate(PR_FALSE);
|
||||
}
|
||||
|
||||
count = mEndInstances.Length();
|
||||
for (PRInt32 j = count - 1; j >= 0; --j) {
|
||||
nsSMILInstanceTime* instance = mEndInstances[j].get();
|
||||
NS_ABORT_IF_FALSE(instance, "NULL instance in end instances array");
|
||||
if (instance->ClearOnReset()) {
|
||||
instance->Unlink();
|
||||
mEndInstances.RemoveElementAt(j);
|
||||
}
|
||||
if (mAnimationElement->HasAnimAttr(nsGkAtoms::begin)) {
|
||||
nsAutoString attValue;
|
||||
mAnimationElement->GetAnimAttr(nsGkAtoms::begin, attValue);
|
||||
SetBeginSpec(attValue, &mAnimationElement->Content());
|
||||
}
|
||||
|
||||
if (mAnimationElement->HasAnimAttr(nsGkAtoms::end)) {
|
||||
nsAutoString attValue;
|
||||
mAnimationElement->GetAnimAttr(nsGkAtoms::end, attValue);
|
||||
SetEndSpec(attValue, &mAnimationElement->Content());
|
||||
}
|
||||
|
||||
mPrevRegisteredMilestone = sMaxMilestone;
|
||||
RegisterMilestone();
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -922,16 +974,15 @@ nsSMILTimedElement::AddDependent(nsSMILTimeValueSpec& aDependent)
|
||||
"nsSMILTimeValueSpec is already registered as a dependency");
|
||||
mTimeDependents.PutEntry(&aDependent);
|
||||
|
||||
// Add old and current intervals
|
||||
// Add current interval. We could add historical intervals too but that would
|
||||
// cause unpredictable results since some intervals may have been filtered.
|
||||
// SMIL doesn't say what to do here so for simplicity and consistency we
|
||||
// simply add the current interval if there is one.
|
||||
//
|
||||
// It's not necessary to call SyncPauseTime since we're dealing with
|
||||
// historical instance times not newly added ones.
|
||||
nsSMILTimeContainer* container = GetTimeContainer();
|
||||
for (PRUint32 i = 0; i < mOldIntervals.Length(); ++i) {
|
||||
aDependent.HandleNewInterval(*mOldIntervals[i], container);
|
||||
}
|
||||
if (mCurrentInterval) {
|
||||
aDependent.HandleNewInterval(*mCurrentInterval, container);
|
||||
aDependent.HandleNewInterval(*mCurrentInterval, GetTimeContainer());
|
||||
}
|
||||
}
|
||||
|
||||
@ -950,7 +1001,7 @@ nsSMILTimedElement::IsTimeDependent(const nsSMILTimedElement& aOther) const
|
||||
if (!thisBegin || !otherBegin)
|
||||
return PR_FALSE;
|
||||
|
||||
return thisBegin->IsDependent(*otherBegin);
|
||||
return thisBegin->IsDependentOn(*otherBegin);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1054,6 +1105,18 @@ nsSMILTimedElement::SetBeginOrEndSpec(const nsAString& aSpec,
|
||||
return rv;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class RemoveNonDOM
|
||||
{
|
||||
public:
|
||||
PRBool operator()(nsSMILInstanceTime* aInstanceTime, PRUint32 /*aIndex*/)
|
||||
{
|
||||
return !aInstanceTime->FromDOM();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::ClearBeginOrEndSpecs(PRBool aIsBegin)
|
||||
{
|
||||
@ -1063,14 +1126,276 @@ nsSMILTimedElement::ClearBeginOrEndSpecs(PRBool aIsBegin)
|
||||
// Remove only those instance times generated by the attribute, not those from
|
||||
// DOM calls.
|
||||
InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
|
||||
PRInt32 count = instances.Length();
|
||||
for (PRInt32 i = count - 1; i >= 0; --i) {
|
||||
nsSMILInstanceTime* instance = instances[i].get();
|
||||
NS_ABORT_IF_FALSE(instance, "NULL instance in instances array");
|
||||
if (!instance->FromDOM()) {
|
||||
instance->Unlink();
|
||||
instances.RemoveElementAt(i);
|
||||
RemoveNonDOM removeNonDOM;
|
||||
RemoveInstanceTimes(instances, removeNonDOM);
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::RewindTiming()
|
||||
{
|
||||
RewindInstanceTimes(mBeginInstances);
|
||||
RewindInstanceTimes(mEndInstances);
|
||||
|
||||
if (mCurrentInterval) {
|
||||
mCurrentInterval->Unlink();
|
||||
mCurrentInterval = nsnull;
|
||||
}
|
||||
|
||||
for (PRInt32 i = mOldIntervals.Length() - 1; i >= 0; --i) {
|
||||
mOldIntervals[i]->Unlink();
|
||||
}
|
||||
mOldIntervals.Clear();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class RemoveNonDynamic
|
||||
{
|
||||
public:
|
||||
PRBool operator()(nsSMILInstanceTime* aInstanceTime, PRUint32 /*aIndex*/)
|
||||
{
|
||||
// Generally dynamically-generated instance times (DOM calls, event-based
|
||||
// times) are not associated with their creator nsSMILTimeValueSpec.
|
||||
// If that ever changes though we'll need to make sure to disassociate
|
||||
// them here otherwise they'll get removed when we clear the set of
|
||||
// nsSMILTimeValueSpecs later on.
|
||||
NS_ABORT_IF_FALSE(!aInstanceTime->IsDynamic() ||
|
||||
!aInstanceTime->GetCreator(),
|
||||
"Instance time retained during rewind needs to be unlinked");
|
||||
return !aInstanceTime->IsDynamic();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::RewindInstanceTimes(InstanceTimeList& aList)
|
||||
{
|
||||
RemoveNonDynamic removeNonDynamic;
|
||||
RemoveInstanceTimes(aList, removeNonDynamic);
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::ApplyEarlyEnd(const nsSMILTimeValue& aSampleTime)
|
||||
{
|
||||
// This should only be called within DoSampleAt as a helper function
|
||||
NS_ABORT_IF_FALSE(mElementState == STATE_ACTIVE,
|
||||
"Unexpected state to try to apply an early end");
|
||||
|
||||
// Only apply an early end if we're not already ending.
|
||||
if (mCurrentInterval->End()->Time() > aSampleTime) {
|
||||
nsSMILInstanceTime* earlyEnd = CheckForEarlyEnd(aSampleTime);
|
||||
if (earlyEnd) {
|
||||
if (earlyEnd->IsDependent()) {
|
||||
// Generate a new instance time for the early end since the
|
||||
// existing instance time is part of some dependency chain that we
|
||||
// don't want to participate in.
|
||||
nsRefPtr<nsSMILInstanceTime> newEarlyEnd =
|
||||
new nsSMILInstanceTime(earlyEnd->Time());
|
||||
mCurrentInterval->SetEnd(*newEarlyEnd);
|
||||
} else {
|
||||
mCurrentInterval->SetEnd(*earlyEnd);
|
||||
}
|
||||
NotifyChangedInterval();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class RemoveReset
|
||||
{
|
||||
public:
|
||||
RemoveReset(const nsSMILInstanceTime* aCurrentIntervalBegin)
|
||||
: mCurrentIntervalBegin(aCurrentIntervalBegin) { }
|
||||
PRBool operator()(nsSMILInstanceTime* aInstanceTime, PRUint32 /*aIndex*/)
|
||||
{
|
||||
// SMIL 3.0 section 5.4.3, 'Resetting element state':
|
||||
// Any instance times associated with past Event-values, Repeat-values,
|
||||
// Accesskey-values or added via DOM method calls are removed from the
|
||||
// dependent begin and end instance times lists. In effect, all events
|
||||
// and DOM methods calls in the past are cleared. This does not apply to
|
||||
// an instance time that defines the begin of the current interval.
|
||||
return aInstanceTime->IsDynamic() &&
|
||||
!aInstanceTime->ShouldPreserve() &&
|
||||
(!mCurrentIntervalBegin || aInstanceTime != mCurrentIntervalBegin);
|
||||
}
|
||||
|
||||
private:
|
||||
const nsSMILInstanceTime* mCurrentIntervalBegin;
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::Reset()
|
||||
{
|
||||
RemoveReset resetBegin(mCurrentInterval ? mCurrentInterval->Begin() : nsnull);
|
||||
RemoveInstanceTimes(mBeginInstances, resetBegin);
|
||||
|
||||
RemoveReset resetEnd(nsnull);
|
||||
RemoveInstanceTimes(mEndInstances, resetEnd);
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::DoPostSeek()
|
||||
{
|
||||
// XXX When implementing TimeEvents we'll need to compare mElementState with
|
||||
// mSeekState and dispatch events as follows:
|
||||
// ACTIVE->INACTIVE: End event
|
||||
// INACTIVE->ACTIVE: Begin event
|
||||
// ACTIVE->ACTIVE: Nothing (even if they're different intervals)
|
||||
// INACTIVE->INACTIVE: Nothing (even if we've skipped intervals)
|
||||
|
||||
// Finish backwards seek
|
||||
if (mSeekState == SEEK_BACKWARD_FROM_INACTIVE ||
|
||||
mSeekState == SEEK_BACKWARD_FROM_ACTIVE) {
|
||||
// Previously some dynamic instance times may have been marked to be
|
||||
// preserved because they were endpoints of an historic interval (which may
|
||||
// or may not have been filtered). Now that we've finished a seek we should
|
||||
// clear that flag for those instance times whose intervals are no longer
|
||||
// historic.
|
||||
UnpreserveInstanceTimes(mBeginInstances);
|
||||
UnpreserveInstanceTimes(mEndInstances);
|
||||
|
||||
// Now that the times have been unmarked perform a reset. This might seem
|
||||
// counter-intuitive when we're only doing a seek within an interval but
|
||||
// SMIL seems to require this. SMIL 3.0, 'Hyperlinks and timing':
|
||||
// Resolved end times associated with events, Repeat-values,
|
||||
// Accesskey-values or added via DOM method calls are cleared when seeking
|
||||
// to time earlier than the resolved end time.
|
||||
Reset();
|
||||
UpdateCurrentInterval();
|
||||
}
|
||||
|
||||
mSeekState = SEEK_NOT_SEEKING;
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::UnpreserveInstanceTimes(InstanceTimeList& aList)
|
||||
{
|
||||
const nsSMILInterval* prevInterval = GetPreviousInterval();
|
||||
const nsSMILInstanceTime* cutoff = mCurrentInterval ?
|
||||
mCurrentInterval->Begin() :
|
||||
prevInterval ? prevInterval->Begin() : nsnull;
|
||||
InstanceTimeComparator cmp;
|
||||
PRUint32 count = aList.Length();
|
||||
for (PRUint32 i = 0; i < count; ++i) {
|
||||
nsSMILInstanceTime* instance = aList[i].get();
|
||||
if (!cutoff || cmp.LessThan(cutoff, instance)) {
|
||||
instance->UnmarkShouldPreserve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::FilterHistory()
|
||||
{
|
||||
// We should filter the intervals first, since instance times still used in an
|
||||
// interval won't be filtered.
|
||||
FilterIntervals();
|
||||
FilterInstanceTimes(mBeginInstances);
|
||||
FilterInstanceTimes(mEndInstances);
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::FilterIntervals()
|
||||
{
|
||||
// We can filter old intervals that:
|
||||
//
|
||||
// a) are not the previous interval; AND
|
||||
// b) are not in the middle of a dependency chain
|
||||
//
|
||||
// Condition (a) is necessary since the previous interval is used for applying
|
||||
// fill effects and updating the current interval.
|
||||
//
|
||||
// Condition (b) is necessary since even if this interval itself is not
|
||||
// active, it may be part of a dependency chain that includes active
|
||||
// intervals. Such chains are used to establish priorities within the
|
||||
// animation sandwich.
|
||||
//
|
||||
// Although the above conditions allow us to safely filter intervals for most
|
||||
// scenarios they do not cover all cases and there will still be scenarios
|
||||
// that generate intervals indefinitely. In such a case we simply set
|
||||
// a maximum number of intervals and drop any intervals beyond that threshold.
|
||||
|
||||
PRUint32 threshold = mOldIntervals.Length() > sMaxNumIntervals ?
|
||||
mOldIntervals.Length() - sMaxNumIntervals :
|
||||
0;
|
||||
IntervalList filteredList;
|
||||
for (PRUint32 i = 0; i < mOldIntervals.Length(); ++i)
|
||||
{
|
||||
nsSMILInterval* interval = mOldIntervals[i].get();
|
||||
if (i + 1 < mOldIntervals.Length() /*skip previous interval*/ &&
|
||||
(i < threshold || !interval->IsDependencyChainLink())) {
|
||||
interval->Unlink(PR_TRUE /*filtered, not deleted*/);
|
||||
} else {
|
||||
filteredList.AppendElement(mOldIntervals[i].forget());
|
||||
}
|
||||
}
|
||||
mOldIntervals.Clear();
|
||||
mOldIntervals.SwapElements(filteredList);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class RemoveFiltered
|
||||
{
|
||||
public:
|
||||
RemoveFiltered(nsSMILTimeValue aCutoff) : mCutoff(aCutoff) { }
|
||||
PRBool operator()(nsSMILInstanceTime* aInstanceTime, PRUint32 /*aIndex*/)
|
||||
{
|
||||
// We can filter instance times that:
|
||||
// a) Precede the end point of the previous interval; AND
|
||||
// b) Are NOT syncbase times that might be updated to a time after the end
|
||||
// point of the previous interval; AND
|
||||
// c) Are NOT fixed end points in any remaining interval.
|
||||
return aInstanceTime->Time() < mCutoff &&
|
||||
aInstanceTime->IsFixedTime() &&
|
||||
!aInstanceTime->ShouldPreserve();
|
||||
}
|
||||
|
||||
private:
|
||||
nsSMILTimeValue mCutoff;
|
||||
};
|
||||
|
||||
class RemoveBelowThreshold
|
||||
{
|
||||
public:
|
||||
RemoveBelowThreshold(PRUint32 aThreshold,
|
||||
const nsSMILInstanceTime* aCurrentIntervalBegin)
|
||||
: mThreshold(aThreshold),
|
||||
mCurrentIntervalBegin(aCurrentIntervalBegin) { }
|
||||
PRBool operator()(nsSMILInstanceTime* aInstanceTime, PRUint32 aIndex)
|
||||
{
|
||||
return aInstanceTime != mCurrentIntervalBegin && aIndex < mThreshold;
|
||||
}
|
||||
|
||||
private:
|
||||
PRUint32 mThreshold;
|
||||
const nsSMILInstanceTime* mCurrentIntervalBegin;
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
nsSMILTimedElement::FilterInstanceTimes(InstanceTimeList& aList)
|
||||
{
|
||||
if (GetPreviousInterval()) {
|
||||
RemoveFiltered removeFiltered(GetPreviousInterval()->End()->Time());
|
||||
RemoveInstanceTimes(aList, removeFiltered);
|
||||
}
|
||||
|
||||
// As with intervals it is possible to create a document that, even despite
|
||||
// our most aggressive filtering, will generate instance times indefinitely
|
||||
// (e.g. cyclic dependencies with TimeEvents---we can't filter such times as
|
||||
// they're unpredictable due to the possibility of seeking the document which
|
||||
// may prevent some events from being generated). Therefore we introduce
|
||||
// a hard cutoff at which point we just drop the oldest instance times.
|
||||
if (aList.Length() > sMaxNumInstanceTimes) {
|
||||
PRUint32 threshold = aList.Length() - sMaxNumInstanceTimes;
|
||||
// We should still preserve the current interval begin time however
|
||||
const nsSMILInstanceTime* currentIntervalBegin = mCurrentInterval ?
|
||||
mCurrentInterval->Begin() : nsnull;
|
||||
RemoveBelowThreshold removeBelowThreshold(threshold, currentIntervalBegin);
|
||||
RemoveInstanceTimes(aList, removeBelowThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1119,8 +1444,6 @@ nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
|
||||
tempBegin = const_cast<nsSMILInstanceTime*>(aFixedBeginTime);
|
||||
} else if (!mBeginSpecSet && beginAfter <= zeroTime) {
|
||||
tempBegin = new nsSMILInstanceTime(nsSMILTimeValue(0));
|
||||
if (!tempBegin)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
} else {
|
||||
PRInt32 beginPos = 0;
|
||||
tempBegin = GetNextGreaterOrEqual(mBeginInstances, beginAfter, beginPos);
|
||||
@ -1166,8 +1489,6 @@ nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
|
||||
if (!tempEnd || intervalEnd != activeEnd) {
|
||||
tempEnd = new nsSMILInstanceTime(activeEnd);
|
||||
}
|
||||
if (!tempEnd)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
NS_ABORT_IF_FALSE(tempEnd, "Failed to get end point for next interval");
|
||||
|
||||
@ -1333,6 +1654,9 @@ nsSMILTimedElement::ActiveTimeToSimpleTime(nsSMILTime aActiveTime,
|
||||
|
||||
NS_ASSERTION(mSimpleDur.IsResolved() || mSimpleDur.IsIndefinite(),
|
||||
"Unresolved simple duration in ActiveTimeToSimpleTime");
|
||||
NS_ASSERTION(aActiveTime >= 0, "Expecting non-negative active time");
|
||||
// Note that a negative aActiveTime will give us a negative value for
|
||||
// aRepeatIteration, which is bad because aRepeatIteration is unsigned
|
||||
|
||||
if (mSimpleDur.IsIndefinite() || mSimpleDur.GetMillis() == 0L) {
|
||||
aRepeatIteration = 0;
|
||||
@ -1409,10 +1733,6 @@ nsSMILTimedElement::UpdateCurrentInterval(PRBool aForceChangeNotice)
|
||||
NS_ABORT_IF_FALSE(!mCurrentInterval,
|
||||
"In postactive state but the interval has been set");
|
||||
mCurrentInterval = new nsSMILInterval(updatedInterval);
|
||||
if (!mCurrentInterval) {
|
||||
NS_WARNING("Failed to allocate memory for new interval.");
|
||||
return;
|
||||
}
|
||||
mElementState = STATE_WAITING;
|
||||
NotifyNewInterval();
|
||||
|
||||
@ -1450,7 +1770,7 @@ nsSMILTimedElement::UpdateCurrentInterval(PRBool aForceChangeNotice)
|
||||
|
||||
if (mElementState == STATE_ACTIVE || mElementState == STATE_WAITING) {
|
||||
mElementState = STATE_POSTACTIVE;
|
||||
mCurrentInterval->NotifyDeleting();
|
||||
mCurrentInterval->Unlink();
|
||||
mCurrentInterval = nsnull;
|
||||
}
|
||||
}
|
||||
@ -1477,9 +1797,9 @@ nsSMILTimedElement::SampleFillValue()
|
||||
NS_ABORT_IF_FALSE(prevInterval,
|
||||
"Attempting to sample fill value but there is no previous interval");
|
||||
NS_ABORT_IF_FALSE(prevInterval->End()->Time().IsResolved() &&
|
||||
!prevInterval->End()->MayUpdate(),
|
||||
prevInterval->End()->IsFixedTime(),
|
||||
"Attempting to sample fill value but the endpoint of the previous "
|
||||
"interval is not resolved and frozen");
|
||||
"interval is not resolved and fixed");
|
||||
|
||||
nsSMILTime activeTime = prevInterval->End()->Time().GetMillis() -
|
||||
prevInterval->Begin()->Time().GetMillis();
|
||||
@ -1508,10 +1828,6 @@ nsSMILTimedElement::AddInstanceTimeFromCurrentTime(nsSMILTime aCurrentTime,
|
||||
// so we don't end up setting SOURCE_DOM for event-based times.
|
||||
nsRefPtr<nsSMILInstanceTime> instanceTime =
|
||||
new nsSMILInstanceTime(timeVal, nsSMILInstanceTime::SOURCE_DOM);
|
||||
if (!instanceTime) {
|
||||
NS_WARNING("Insufficient memory to create instance time");
|
||||
return;
|
||||
}
|
||||
|
||||
AddInstanceTime(instanceTime, aIsBegin);
|
||||
}
|
||||
|
@ -229,10 +229,14 @@ public:
|
||||
void HandleContainerTimeChange();
|
||||
|
||||
/**
|
||||
* Reset the element's internal state. As described in SMILANIM 3.3.7, all
|
||||
* instance times associated with DOM calls, events, etc. are cleared.
|
||||
* Resets this timed element's accumulated times and intervals back to start
|
||||
* up state.
|
||||
*
|
||||
* This is used for backwards seeking where rather than accumulating
|
||||
* historical timing state and winding it back, we reset the element and seek
|
||||
* forwards.
|
||||
*/
|
||||
void Reset();
|
||||
void Rewind();
|
||||
|
||||
/**
|
||||
* Attempts to set an attribute on this timed element.
|
||||
@ -345,6 +349,10 @@ protected:
|
||||
nsSMILTimeContainer* mTimeContainer;
|
||||
};
|
||||
|
||||
// Templated helper functions
|
||||
template <class TestFunctor>
|
||||
void RemoveInstanceTimes(InstanceTimeList& aArray, TestFunctor& aTest);
|
||||
|
||||
//
|
||||
// Implementation helpers
|
||||
//
|
||||
@ -375,8 +383,58 @@ protected:
|
||||
nsIContent* aContextNode,
|
||||
PRBool aIsBegin);
|
||||
void ClearBeginOrEndSpecs(PRBool aIsBegin);
|
||||
void RewindTiming();
|
||||
void RewindInstanceTimes(InstanceTimeList& aList);
|
||||
void DoSampleAt(nsSMILTime aContainerTime, PRBool aEndOnly);
|
||||
|
||||
/**
|
||||
* Helper function to check for an early end and, if necessary, update the
|
||||
* current interval accordingly.
|
||||
*
|
||||
* See SMIL 3.0, section 5.4.5, Element life cycle, "Active Time - Playing an
|
||||
* interval" for a description of ending early.
|
||||
*
|
||||
* @param aSampleTime The current sample time. Early ends should only be
|
||||
* applied at the last possible moment (i.e. if they are at
|
||||
* or before the current sample time) and only if the
|
||||
* current interval is not already ending.
|
||||
*/
|
||||
void ApplyEarlyEnd(const nsSMILTimeValue& aSampleTime);
|
||||
|
||||
/**
|
||||
* Clears certain state in response to the element restarting.
|
||||
*
|
||||
* This state is described in SMIL 3.0, section 5.4.3, Resetting element state
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* Completes a seek operation by sending appropriate events and, in the case
|
||||
* of a backwards seek, updating the state of timing information that was
|
||||
* previously considered historical.
|
||||
*/
|
||||
void DoPostSeek();
|
||||
|
||||
/**
|
||||
* Unmarks instance times that were previously preserved because they were
|
||||
* considered important historical milestones but are no longer such because
|
||||
* a backwards seek has been performed.
|
||||
*/
|
||||
void UnpreserveInstanceTimes(InstanceTimeList& aList);
|
||||
|
||||
/**
|
||||
* Helper function to iterate through this element's accumulated timing
|
||||
* information (specifically old nsSMILIntervals and nsSMILTimeInstanceTimes)
|
||||
* and discard items that are no longer needed or exceed some threshold of
|
||||
* accumulated state.
|
||||
*/
|
||||
void FilterHistory();
|
||||
|
||||
// Helper functions for FilterHistory to clear old nsSMILIntervals and
|
||||
// nsSMILInstanceTimes respectively.
|
||||
void FilterIntervals();
|
||||
void FilterInstanceTimes(InstanceTimeList& aList);
|
||||
|
||||
/**
|
||||
* Calculates the next acceptable interval for this element after the
|
||||
* specified interval, or, if no previous interval is specified, it will be
|
||||
@ -483,6 +541,8 @@ protected:
|
||||
IntervalList mOldIntervals;
|
||||
nsSMILMilestone mPrevRegisteredMilestone;
|
||||
static const nsSMILMilestone sMaxMilestone;
|
||||
static const PRUint8 sMaxNumIntervals;
|
||||
static const PRUint8 sMaxNumInstanceTimes;
|
||||
|
||||
// Set of dependent time value specs to be notified when establishing a new
|
||||
// current interval. Change notifications and delete notifications are handled
|
||||
@ -504,6 +564,16 @@ protected:
|
||||
STATE_POSTACTIVE
|
||||
};
|
||||
nsSMILElementState mElementState;
|
||||
|
||||
enum nsSMILSeekState
|
||||
{
|
||||
SEEK_NOT_SEEKING,
|
||||
SEEK_FORWARD_FROM_ACTIVE,
|
||||
SEEK_FORWARD_FROM_INACTIVE,
|
||||
SEEK_BACKWARD_FROM_ACTIVE,
|
||||
SEEK_BACKWARD_FROM_INACTIVE
|
||||
};
|
||||
nsSMILSeekState mSeekState;
|
||||
};
|
||||
|
||||
#endif // NS_SMILTIMEDELEMENT_H_
|
||||
|
@ -57,6 +57,7 @@ _TEST_FILES = \
|
||||
test_smilAnimateMotion.xhtml \
|
||||
test_smilAnimateMotionInvalidValues.xhtml \
|
||||
test_smilAnimateMotionOverrideRules.xhtml \
|
||||
test_smilBackwardsSeeking.xhtml \
|
||||
test_smilChangeAfterFrozen.xhtml \
|
||||
test_smilContainerBinding.xhtml \
|
||||
test_smilCrossContainer.xhtml \
|
||||
|
191
content/smil/test/test_smilBackwardsSeeking.xhtml
Normal file
191
content/smil/test/test_smilBackwardsSeeking.xhtml
Normal file
@ -0,0 +1,191 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Test for backwards seeking behavior </title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" />
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
/** Test for backwards seeking behavior **/
|
||||
|
||||
var gSvg = document.getElementById("svg");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function main()
|
||||
{
|
||||
// Pause our document, so that the setCurrentTime calls are the only
|
||||
// thing affecting document time
|
||||
gSvg.pauseAnimations();
|
||||
|
||||
// We define a series of scenarios, sample times, and expected return values
|
||||
// from getStartTime.
|
||||
//
|
||||
// Each scenario is basically a variation on the following arrangement:
|
||||
//
|
||||
// <svg>
|
||||
// <set ... dur="1s" begin="<A-BEGIN>"/>
|
||||
// <set ... dur="1s" begin="<B-BEGIN>"/>
|
||||
// </svg>
|
||||
//
|
||||
// Each test then consists of the following:
|
||||
// animA: attributes to be applied to a
|
||||
// animB: attributes to be applied to b
|
||||
// times: a series of triples which consist of:
|
||||
// <sample time, a's expected start time, b's expected start time>
|
||||
// * The sample time is the time passed to setCurrentTime and so is
|
||||
// in seconds.
|
||||
// * The expected start times are compared with the return value of
|
||||
// getStartTime. To check for an unresolved start time where
|
||||
// getStartTime would normally throw an exception use
|
||||
// 'unresolved'.
|
||||
// * We also allow the special notation to indicate a call to
|
||||
// beginElement
|
||||
// <'beginElementAt', id of animation element, offset>
|
||||
//
|
||||
// In the diagrams below '^' means the time before the seek and '*' is the
|
||||
// seek time.
|
||||
var testCases = Array();
|
||||
|
||||
// 0: Simple case
|
||||
//
|
||||
// A: +-------
|
||||
// B: +------- begin: a.begin
|
||||
// * ^
|
||||
testCases[0] = {
|
||||
'animA': {'begin':'1s', 'id':'a'},
|
||||
'animB': {'begin':'a.begin'},
|
||||
'times': [ [0, 1, 1],
|
||||
[1, 1, 1],
|
||||
[2, 'unresolved', 'unresolved'],
|
||||
[0, 1, 1],
|
||||
[1.5, 1, 1],
|
||||
[1, 1, 1],
|
||||
[2, 'unresolved', 'unresolved'] ]
|
||||
};
|
||||
|
||||
// 1: Restored times should be live
|
||||
//
|
||||
// When we restore times they should be live. So we have the following
|
||||
// scenario.
|
||||
//
|
||||
// A: +-------
|
||||
// B: +------- begin: a.begin
|
||||
// * ^
|
||||
//
|
||||
// Then we call beginElement at an earlier time which should give us the
|
||||
// following.
|
||||
//
|
||||
// A: +-------
|
||||
// B: +-------
|
||||
// * ^
|
||||
//
|
||||
// If the times are not live however we'll end up with this
|
||||
//
|
||||
// A: +-------
|
||||
// B: +-+-------
|
||||
// * ^
|
||||
testCases[1] = {
|
||||
'animA': {'begin':'1s', 'id':'a', 'restart':'whenNotActive'},
|
||||
'animB': {'begin':'a.begin', 'restart':'always'},
|
||||
'times': [ [0, 1, 1],
|
||||
[2, 'unresolved', 'unresolved'],
|
||||
[0.25, 1, 1],
|
||||
['beginElementAt', 'a', 0.25], // = start time of 0.5
|
||||
[0.25, 0.5, 0.5],
|
||||
[1, 0.5, 0.5],
|
||||
[1.5, 'unresolved', 'unresolved'] ]
|
||||
};
|
||||
|
||||
// 2: Multiple intervals A
|
||||
//
|
||||
// A: +- +-
|
||||
// B: +- +- begin: a.begin+4s
|
||||
// * ^
|
||||
testCases[2] = {
|
||||
'animA': {'begin':'1s; 3s', 'id':'a'},
|
||||
'animB': {'begin':'a.begin+4s'},
|
||||
'times': [ [0, 1, 5],
|
||||
[3, 3, 5],
|
||||
[6.5, 'unresolved', 7],
|
||||
[4, 'unresolved', 5],
|
||||
[6, 'unresolved', 7],
|
||||
[2, 3, 5],
|
||||
['beginElementAt', 'a', 0],
|
||||
[2, 2, 5],
|
||||
[5, 'unresolved', 5],
|
||||
[6, 'unresolved', 6],
|
||||
[7, 'unresolved', 7],
|
||||
[8, 'unresolved', 'unresolved'] ]
|
||||
};
|
||||
|
||||
for (var i = 0; i < testCases.length; i++) {
|
||||
gSvg.setCurrentTime(0);
|
||||
var test = testCases[i];
|
||||
|
||||
// Create animation elements
|
||||
var animA = createAnim(test.animA);
|
||||
var animB = createAnim(test.animB);
|
||||
|
||||
// Run samples
|
||||
for (var j = 0; j < test.times.length; j++) {
|
||||
var times = test.times[j];
|
||||
if (times[0] == 'beginElementAt') {
|
||||
var anim = getElement(times[1]);
|
||||
anim.beginElementAt(times[2]);
|
||||
} else {
|
||||
gSvg.setCurrentTime(times[0]);
|
||||
checkStartTime(animA, times[1], times[0], i, 'a');
|
||||
checkStartTime(animB, times[2], times[0], i, 'b');
|
||||
}
|
||||
}
|
||||
|
||||
// Tidy up
|
||||
removeElement(animA);
|
||||
removeElement(animB);
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function createAnim(attr)
|
||||
{
|
||||
const svgns = "http://www.w3.org/2000/svg";
|
||||
var anim = document.createElementNS(svgns, 'set');
|
||||
anim.setAttribute('attributeName','x');
|
||||
anim.setAttribute('to','10');
|
||||
anim.setAttribute('dur','1s');
|
||||
for (name in attr) {
|
||||
anim.setAttribute(name, attr[name]);
|
||||
}
|
||||
return gSvg.appendChild(anim);
|
||||
}
|
||||
|
||||
function checkStartTime(anim, expectedStartTime, sampleTime, caseNum, id)
|
||||
{
|
||||
var startTime = 'unresolved';
|
||||
try {
|
||||
startTime = anim.getStartTime();
|
||||
} catch (e) {
|
||||
if (e.code != DOMException.INVALID_STATE_ERR)
|
||||
throw e;
|
||||
}
|
||||
|
||||
var msg = "Test case " + caseNum + ", t=" + sampleTime + " animation '" +
|
||||
id + "': Unexpected getStartTime:";
|
||||
is(startTime, expectedStartTime, msg);
|
||||
}
|
||||
|
||||
window.addEventListener("load", main, false);
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -60,11 +60,11 @@ function main() {
|
||||
is(anim.getStartTime(), 6);
|
||||
|
||||
// Rebind
|
||||
// At this point all the old intervals should be re-added to anim. If they're
|
||||
// not and only the current interval is added to anim we'll get a start time
|
||||
// of 4s instead of 2s.
|
||||
// At this point only the current interval will be re-added to anim (this is
|
||||
// for consistency since old intervals may or may not have been filtered).
|
||||
// Therefore the start time should be 4s instead of 2s.
|
||||
circle.appendChild(anim);
|
||||
is(anim.getStartTime(), 2);
|
||||
is(anim.getStartTime(), 4);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
@ -31,7 +31,8 @@ function main() {
|
||||
// Test that seeking takes effect immediately
|
||||
for (var i = 0; i < gTimes.length; i++) {
|
||||
gSvg.setCurrentTime(gTimes[i]);
|
||||
assertFloatsEqual(gSvg.getCurrentTime(), gTimes[i]);
|
||||
// We adopt the SVGT1.2 behavior of clamping negative times to 0
|
||||
assertFloatsEqual(gSvg.getCurrentTime(), Math.max(gTimes[i], 0.0));
|
||||
}
|
||||
|
||||
// Test that seeking isn't messed up by timeouts
|
||||
@ -56,7 +57,7 @@ function checkTimesAfterIndex(index) {
|
||||
|
||||
gSvg.setCurrentTime(gTimes[index]);
|
||||
var func = function() {
|
||||
assertFloatsEqual(gSvg.getCurrentTime(), gTimes[index]);
|
||||
assertFloatsEqual(gSvg.getCurrentTime(), Math.max(gTimes[index], 0.0));
|
||||
checkTimesAfterIndex(index + 1);
|
||||
}
|
||||
setTimeout(func, gWaitTime);
|
||||
|
@ -169,29 +169,35 @@ nsSVGPointList::SetValueString(const nsAString& aValue)
|
||||
nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
|
||||
nsCOMArray<nsIDOMSVGPoint> points;
|
||||
|
||||
PRBool parseError = PR_FALSE;
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
// Parse 2 tokens
|
||||
NS_ConvertUTF16toUTF8 utf8String1(tokenizer.nextToken());
|
||||
const char *token1 = utf8String1.get();
|
||||
if (!tokenizer.hasMoreTokens() || // No 2nd token.
|
||||
*token1 == '\0') { // 1st token is empty string.
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
parseError = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
NS_ConvertUTF16toUTF8 utf8String2(tokenizer.nextToken());
|
||||
const char *token2 = utf8String2.get();
|
||||
if (*token2 == '\0') { // 2nd token is empty string.
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
parseError = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Convert parsed tokens to float values.
|
||||
char *end;
|
||||
float x = float(PR_strtod(token1, &end));
|
||||
if (*end != '\0' || !NS_FloatIsFinite(x)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
parseError = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
float y = float(PR_strtod(token2, &end));
|
||||
if (*end != '\0' || !NS_FloatIsFinite(y)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
parseError = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Build a point from our parsed float values.
|
||||
@ -201,7 +207,11 @@ nsSVGPointList::SetValueString(const nsAString& aValue)
|
||||
}
|
||||
|
||||
if (tokenizer.lastTokenEndedWithSeparator()) { // Reject trailing comma
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
parseError = PR_TRUE;
|
||||
}
|
||||
|
||||
if (parseError) {
|
||||
// XXX nsSVGUtils::ReportToConsole()
|
||||
}
|
||||
|
||||
WillModify();
|
||||
|
@ -71,8 +71,7 @@ NS_NewXBLContentSink(nsIXMLContentSink** aResult,
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
nsXBLContentSink* it;
|
||||
NS_NEWXPCOM(it, nsXBLContentSink);
|
||||
nsXBLContentSink* it = new nsXBLContentSink();
|
||||
NS_ENSURE_TRUE(it, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
|
||||
|
@ -124,8 +124,7 @@ NS_NewXMLContentSink(nsIXMLContentSink** aResult,
|
||||
if (nsnull == aResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
nsXMLContentSink* it;
|
||||
NS_NEWXPCOM(it, nsXMLContentSink);
|
||||
nsXMLContentSink* it = new nsXMLContentSink();
|
||||
if (nsnull == it) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -36,10 +36,8 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIServiceManager.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIModule.h"
|
||||
#include "nsIGenericFactory.h"
|
||||
#include "nsMorkCID.h"
|
||||
#include "nsIMdbFactoryFactory.h"
|
||||
#include "mdb.h"
|
||||
@ -59,16 +57,25 @@ protected:
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMorkFactoryService)
|
||||
|
||||
static const nsModuleComponentInfo components[] =
|
||||
{
|
||||
{ "Mork Factory Service",
|
||||
NS_MORK_CID,
|
||||
NS_MORK_CONTRACTID,
|
||||
nsMorkFactoryServiceConstructor
|
||||
}
|
||||
NS_DEFINE_NAMED_CID(NS_MORK_CID);
|
||||
|
||||
const mozilla::Module::CIDEntry kMorkCIDs[] = {
|
||||
{ &kNS_MORK_CID, false, NULL, nsMorkFactoryServiceConstructor },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
NS_IMPL_NSGETMODULE(nsMorkModule, components)
|
||||
const mozilla::Module::ContractIDEntry kMorkContracts[] = {
|
||||
{ NS_MORK_CONTRACTID, &kNS_MORK_CID },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module kMorkModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kMorkCIDs,
|
||||
kMorkContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(nsMorkModule) = &kMorkModule;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsMorkFactoryService, nsIMdbFactoryService)
|
||||
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsIURI;
|
||||
class nsString;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -52,7 +51,7 @@ namespace mozilla {
|
||||
}
|
||||
|
||||
#define IHISTORY_IID \
|
||||
{0x6f736049, 0x6370, 0x4376, {0xb7, 0x17, 0xfa, 0xfc, 0x0b, 0x4f, 0xd0, 0xf1}}
|
||||
{0xaf27265d, 0x5672, 0x4d23, {0xa0, 0x75, 0x34, 0x8e, 0xb9, 0x73, 0x5a, 0x9a}}
|
||||
|
||||
class IHistory : public nsISupports
|
||||
{
|
||||
@ -97,50 +96,6 @@ public:
|
||||
*/
|
||||
NS_IMETHOD UnregisterVisitedCallback(nsIURI *aURI, dom::Link *aLink) = 0;
|
||||
|
||||
enum VisitFlags {
|
||||
/**
|
||||
* Indicates whether the URI was loaded in a top-level window.
|
||||
*/
|
||||
TOP_LEVEL = 1 << 0,
|
||||
/**
|
||||
* Indicates whether the URI was loaded as part of a permanent redirect.
|
||||
*/
|
||||
REDIRECT_PERMANENT = 1 << 1,
|
||||
/**
|
||||
* Indicates whether the URI was loaded as part of a temporary redirect.
|
||||
*/
|
||||
REDIRECT_TEMPORARY = 1 << 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a history visit for the URI.
|
||||
*
|
||||
* @pre aURI must not be null.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI of the page being visited.
|
||||
* @param aLastVisitedURI
|
||||
* The URI of the last visit in the chain.
|
||||
* @param aFlags
|
||||
* The VisitFlags describing this visit.
|
||||
*/
|
||||
NS_IMETHOD VisitURI(
|
||||
nsIURI *aURI,
|
||||
nsIURI *aLastVisitedURI,
|
||||
PRUint32 aFlags
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Set the title of the URI.
|
||||
*
|
||||
* @pre aURI must not be null.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI to set the title for.
|
||||
* @param aTitle
|
||||
* The title string.
|
||||
*/
|
||||
NS_IMETHOD SetURITitle(nsIURI* aURI, const nsAString& aTitle) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(IHistory, IHISTORY_IID)
|
||||
@ -149,11 +104,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(IHistory, IHISTORY_IID)
|
||||
NS_IMETHOD RegisterVisitedCallback(nsIURI *aURI, \
|
||||
mozilla::dom::Link *aContent); \
|
||||
NS_IMETHOD UnregisterVisitedCallback(nsIURI *aURI, \
|
||||
mozilla::dom::Link *aContent); \
|
||||
NS_IMETHOD VisitURI(nsIURI *aURI, \
|
||||
nsIURI *aLastVisitedURI, \
|
||||
PRUint32 aFlags); \
|
||||
NS_IMETHOD SetURITitle(nsIURI* aURI, const nsAString& aTitle);
|
||||
mozilla::dom::Link *aContent);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -112,8 +112,6 @@
|
||||
#include "nsIOfflineCacheUpdate.h"
|
||||
#include "nsCPrefetchService.h"
|
||||
#include "nsJSON.h"
|
||||
#include "IHistory.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
// we want to explore making the document own the load group
|
||||
// so we can associate the document URI with the load group.
|
||||
@ -4704,16 +4702,11 @@ nsDocShell::SetTitle(const PRUnichar * aTitle)
|
||||
treeOwnerAsWin->SetTitle(aTitle);
|
||||
}
|
||||
|
||||
if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
|
||||
nsCOMPtr<IHistory> history = services::GetHistoryService();
|
||||
if (history) {
|
||||
history->SetURITitle(mCurrentURI, mTitle);
|
||||
}
|
||||
else if (mGlobalHistory) {
|
||||
mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
|
||||
}
|
||||
if (mGlobalHistory && mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
|
||||
mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
|
||||
}
|
||||
|
||||
|
||||
// Update SessionHistory with the document's title.
|
||||
if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
|
||||
mLoadType != LOAD_ERROR_PAGE) {
|
||||
@ -5679,53 +5672,32 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
|
||||
if (!(aStateFlags & STATE_IS_DOCUMENT))
|
||||
return; // not a toplevel document
|
||||
|
||||
nsCOMPtr<nsIURI> oldURI, newURI;
|
||||
aOldChannel->GetURI(getter_AddRefs(oldURI));
|
||||
aNewChannel->GetURI(getter_AddRefs(newURI));
|
||||
if (!oldURI || !newURI) {
|
||||
return;
|
||||
nsCOMPtr<nsIGlobalHistory3> history3(do_QueryInterface(mGlobalHistory));
|
||||
nsresult result = NS_ERROR_NOT_IMPLEMENTED;
|
||||
if (history3) {
|
||||
// notify global history of this redirect
|
||||
result = history3->AddDocumentRedirect(aOldChannel, aNewChannel,
|
||||
aRedirectFlags, !IsFrame());
|
||||
}
|
||||
|
||||
// Below a URI visit is saved (see AddURIVisit method doc).
|
||||
// The visit chain looks something like:
|
||||
// ...
|
||||
// Site N - 1
|
||||
// => Site N
|
||||
// (redirect to =>) Site N + 1 (we are here!)
|
||||
|
||||
// Get N - 1 and transition type
|
||||
nsCOMPtr<nsIURI> previousURI;
|
||||
PRUint32 previousFlags = 0;
|
||||
ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
|
||||
|
||||
if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
|
||||
ChannelIsPost(aOldChannel)) {
|
||||
// 1. Internal redirects are ignored because they are specific to the
|
||||
// channel implementation.
|
||||
// 2. POSTs are not saved by global history.
|
||||
//
|
||||
// Regardless, we need to propagate the previous visit to the new
|
||||
// channel.
|
||||
SaveLastVisit(aNewChannel, previousURI, previousFlags);
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIURI> referrer;
|
||||
// Treat referrer as null if there is an error getting it.
|
||||
(void)NS_GetReferrerFromChannel(aOldChannel,
|
||||
getter_AddRefs(referrer));
|
||||
|
||||
// Add visit N -1 => N
|
||||
AddURIVisit(oldURI, referrer, previousURI, previousFlags);
|
||||
|
||||
// Since N + 1 could be the final destination, we will not save N => N + 1
|
||||
// here. OnNewURI will do that, so we will cache it.
|
||||
SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
|
||||
if (result == NS_ERROR_NOT_IMPLEMENTED) {
|
||||
// when there is no GlobalHistory3, or it doesn't implement
|
||||
// AddToplevelRedirect, we fall back to GlobalHistory2. Just notify
|
||||
// that the redirecting page was a rePdirect so it will be link colored
|
||||
// but not visible.
|
||||
nsCOMPtr<nsIURI> oldURI;
|
||||
aOldChannel->GetURI(getter_AddRefs(oldURI));
|
||||
if (! oldURI)
|
||||
return; // nothing to tell anybody about
|
||||
AddToGlobalHistory(oldURI, PR_TRUE, aOldChannel);
|
||||
}
|
||||
|
||||
// check if the new load should go through the application cache.
|
||||
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
|
||||
do_QueryInterface(aNewChannel);
|
||||
if (appCacheChannel) {
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
aNewChannel->GetURI(getter_AddRefs(newURI));
|
||||
appCacheChannel->SetChooseApplicationCache(ShouldCheckAppCache(newURI));
|
||||
}
|
||||
|
||||
@ -8965,7 +8937,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
if (aChannel) {
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
|
||||
|
||||
|
||||
// Check if the HTTPChannel is hiding under a multiPartChannel
|
||||
if (!httpChannel) {
|
||||
GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
|
||||
@ -9055,8 +9027,8 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
|
||||
|
||||
nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
|
||||
nsCOMPtr<nsISupports> cacheKey;
|
||||
// Get the Cache Key and store it in SH.
|
||||
if (cacheChannel)
|
||||
// Get the Cache Key and store it in SH.
|
||||
if (cacheChannel)
|
||||
cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
|
||||
// If we already have a loading history entry, store the new cache key
|
||||
// in it. Otherwise, since we're doing a reload and won't be updating
|
||||
@ -9078,22 +9050,10 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
|
||||
getter_AddRefs(mLSHE));
|
||||
}
|
||||
|
||||
// Update Global history
|
||||
if (aAddToGlobalHistory) {
|
||||
// If this is a POST request, we do not want to include this in global
|
||||
// history.
|
||||
if (!ChannelIsPost(aChannel)) {
|
||||
nsCOMPtr<nsIURI> previousURI;
|
||||
PRUint32 previousFlags = 0;
|
||||
ExtractLastVisit(aChannel, getter_AddRefs(previousURI),
|
||||
&previousFlags);
|
||||
|
||||
nsCOMPtr<nsIURI> referrer;
|
||||
// Treat referrer as null if there is an error getting it.
|
||||
(void)NS_GetReferrerFromChannel(aChannel,
|
||||
getter_AddRefs(referrer));
|
||||
|
||||
AddURIVisit(aURI, referrer, previousURI, previousFlags);
|
||||
}
|
||||
// Get the referrer uri from the channel
|
||||
AddToGlobalHistory(aURI, PR_FALSE, aChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9412,7 +9372,7 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
|
||||
SetCurrentURI(newURI, nsnull, PR_TRUE);
|
||||
document->SetDocumentURI(newURI);
|
||||
|
||||
AddURIVisit(newURI, oldURI, oldURI, 0);
|
||||
AddToGlobalHistory(newURI, PR_FALSE, oldURI);
|
||||
}
|
||||
else {
|
||||
FireOnLocationChange(this, nsnull, mCurrentURI);
|
||||
@ -10108,109 +10068,53 @@ NS_IMETHODIMP nsDocShell::MakeEditable(PRBool inWaitForUriLoad)
|
||||
return mEditorData->MakeEditable(inWaitForUriLoad);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocShell::ChannelIsPost(nsIChannel* aChannel)
|
||||
nsresult
|
||||
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||
nsIChannel * aChannel)
|
||||
{
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
|
||||
if (!httpChannel) {
|
||||
return false;
|
||||
// If this is a POST request, we do not want to include this in global
|
||||
// history, so return early.
|
||||
nsCOMPtr<nsIHttpChannel> hchan(do_QueryInterface(aChannel));
|
||||
if (hchan) {
|
||||
nsCAutoString type;
|
||||
nsresult rv = hchan->GetRequestMethod(type);
|
||||
if (NS_SUCCEEDED(rv) && type.EqualsLiteral("POST"))
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCAutoString method;
|
||||
httpChannel->GetRequestMethod(method);
|
||||
return method.Equals("POST");
|
||||
nsCOMPtr<nsIURI> referrer;
|
||||
if (aChannel)
|
||||
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
|
||||
|
||||
return AddToGlobalHistory(aURI, aRedirect, referrer);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
|
||||
nsIURI** aURI,
|
||||
PRUint32* aChannelRedirectFlags)
|
||||
nsresult
|
||||
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||
nsIURI * aReferrer)
|
||||
{
|
||||
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
|
||||
if (!props) {
|
||||
return;
|
||||
}
|
||||
if (mItemType != typeContent || !mGlobalHistory)
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv = props->GetPropertyAsInterface(
|
||||
NS_LITERAL_STRING("docshell.previousURI"),
|
||||
NS_GET_IID(nsIURI),
|
||||
reinterpret_cast<void**>(aURI)
|
||||
);
|
||||
PRBool visited;
|
||||
nsresult rv = mGlobalHistory->IsVisited(aURI, &visited);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// There is no last visit for this channel, so this must be the first
|
||||
// link. Link the visit to the referrer of this request, if any.
|
||||
// Treat referrer as null if there is an error getting it.
|
||||
(void)NS_GetReferrerFromChannel(aChannel, aURI);
|
||||
}
|
||||
else {
|
||||
rv = props->GetPropertyAsUint32(
|
||||
NS_LITERAL_STRING("docshell.previousFlags"),
|
||||
aChannelRedirectFlags
|
||||
);
|
||||
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), aReferrer);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_WARN_IF_FALSE(
|
||||
NS_FAILED(rv),
|
||||
"Could not fetch previous flags, URI will be treated like referrer"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::SaveLastVisit(nsIChannel* aChannel,
|
||||
nsIURI* aURI,
|
||||
PRUint32 aChannelRedirectFlags)
|
||||
{
|
||||
nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
|
||||
if (!props || !aURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
|
||||
aURI);
|
||||
props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
|
||||
aChannelRedirectFlags);
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::AddURIVisit(nsIURI* aURI,
|
||||
nsIURI* aReferrerURI,
|
||||
nsIURI* aPreviousURI,
|
||||
PRUint32 aChannelRedirectFlags)
|
||||
{
|
||||
NS_ASSERTION(aURI, "Visited URI is null!");
|
||||
|
||||
// Only content-type docshells save URI visits.
|
||||
if (mItemType != typeContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<IHistory> history = services::GetHistoryService();
|
||||
|
||||
if (history) {
|
||||
PRUint32 visitURIFlags = 0;
|
||||
|
||||
if (!IsFrame()) {
|
||||
visitURIFlags |= IHistory::TOP_LEVEL;
|
||||
if (!visited) {
|
||||
nsCOMPtr<nsIObserverService> obsService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (obsService) {
|
||||
obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nsnull);
|
||||
}
|
||||
|
||||
if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
|
||||
visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
|
||||
}
|
||||
else if (aChannelRedirectFlags &
|
||||
nsIChannelEventSink::REDIRECT_PERMANENT) {
|
||||
visitURIFlags |= IHistory::REDIRECT_PERMANENT;
|
||||
}
|
||||
|
||||
(void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
|
||||
}
|
||||
else if (mGlobalHistory) {
|
||||
// Falls back to sync global history interface.
|
||||
(void)mGlobalHistory->AddURI(aURI,
|
||||
!!aChannelRedirectFlags,
|
||||
!IsFrame(),
|
||||
aReferrerURI);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
|
@ -433,77 +433,12 @@ protected:
|
||||
PRUint32 aRedirectFlags,
|
||||
PRUint32 aStateFlags);
|
||||
|
||||
/**
|
||||
* Helper function that determines if channel is an HTTP POST.
|
||||
*
|
||||
* @param aChannel
|
||||
* The channel to test
|
||||
*
|
||||
* @return True iff channel is an HTTP post.
|
||||
*/
|
||||
bool ChannelIsPost(nsIChannel* aChannel);
|
||||
// Global History
|
||||
|
||||
/**
|
||||
* Helper function that finds the last URI and its transition flags for a
|
||||
* channel.
|
||||
*
|
||||
* This method first checks the channel's property bag to see if previous
|
||||
* info has been saved. If not, it gives back the referrer of the channel.
|
||||
*
|
||||
* @param aChannel
|
||||
* The channel we are transitioning to
|
||||
* @param aURI
|
||||
* Output parameter with the previous URI, not addref'd
|
||||
* @param aChannelRedirectFlags
|
||||
* If a redirect, output parameter with the previous redirect flags
|
||||
* from nsIChannelEventSink
|
||||
*/
|
||||
void ExtractLastVisit(nsIChannel* aChannel,
|
||||
nsIURI** aURI,
|
||||
PRUint32* aChannelRedirectFlags);
|
||||
|
||||
/**
|
||||
* Helper function that caches a URI and a transition for saving later.
|
||||
*
|
||||
* @param aChannel
|
||||
* Channel that will have these properties saved
|
||||
* @param aURI
|
||||
* The URI to save for later
|
||||
* @param aChannelRedirectFlags
|
||||
* The nsIChannelEventSink redirect flags to save for later
|
||||
*/
|
||||
void SaveLastVisit(nsIChannel* aChannel,
|
||||
nsIURI* aURI,
|
||||
PRUint32 aChannelRedirectFlags);
|
||||
|
||||
/**
|
||||
* Helper function for adding a URI visit using IHistory. If IHistory is
|
||||
* not available, the method tries nsIGlobalHistory2.
|
||||
*
|
||||
* The IHistory API maintains chains of visits, tracking both HTTP referrers
|
||||
* and redirects for a user session. VisitURI requires the current URI and
|
||||
* the previous URI in the chain.
|
||||
*
|
||||
* Visits can be saved either during a redirect or when the request has
|
||||
* reached its final destination. The previous URI in the visit may be
|
||||
* from another redirect or it may be the referrer.
|
||||
*
|
||||
* @pre aURI is not null.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI that was just visited
|
||||
* @param aReferrerURI
|
||||
* The referrer URI of this request
|
||||
* @param aPreviousURI
|
||||
* The previous URI of this visit (may be the same as aReferrerURI)
|
||||
* @param aChannelRedirectFlags
|
||||
* For redirects, the redirect flags from nsIChannelEventSink
|
||||
* (0 otherwise)
|
||||
*/
|
||||
void AddURIVisit(nsIURI* aURI,
|
||||
nsIURI* aReferrerURI,
|
||||
nsIURI* aPreviousURI,
|
||||
PRUint32 aChannelRedirectFlags);
|
||||
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||
nsIChannel * aChannel);
|
||||
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
|
||||
nsIURI * aReferrer);
|
||||
|
||||
// Helper Routines
|
||||
nsresult ConfirmRepost(PRBool * aRepost);
|
||||
@ -765,9 +700,6 @@ protected:
|
||||
|
||||
PRInt32 mMarginWidth;
|
||||
PRInt32 mMarginHeight;
|
||||
|
||||
// This can either be a content docshell or a chrome docshell. After
|
||||
// Create() is called, the type is not expected to change.
|
||||
PRInt32 mItemType;
|
||||
|
||||
// Index into the SHTransaction list, indicating the previous and current
|
||||
|
@ -909,8 +909,7 @@ nsClipboardDragDropHookCommand::GetCommandStateParams(const char *aCommandName,
|
||||
|
||||
#define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName) \
|
||||
{ \
|
||||
_cmdClass* theCmd; \
|
||||
NS_NEWXPCOM(theCmd, _cmdClass); \
|
||||
_cmdClass* theCmd = new _cmdClass(); \
|
||||
if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \
|
||||
rv = inCommandTable->RegisterCommand(_cmdName, \
|
||||
static_cast<nsIControllerCommand *>(theCmd)); \
|
||||
@ -918,8 +917,7 @@ nsClipboardDragDropHookCommand::GetCommandStateParams(const char *aCommandName,
|
||||
|
||||
#define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName) \
|
||||
{ \
|
||||
_cmdClass* theCmd; \
|
||||
NS_NEWXPCOM(theCmd, _cmdClass); \
|
||||
_cmdClass* theCmd = new _cmdClass(); \
|
||||
if (!theCmd) return NS_ERROR_OUT_OF_MEMORY; \
|
||||
rv = inCommandTable->RegisterCommand(_cmdName, \
|
||||
static_cast<nsIControllerCommand *>(theCmd));
|
||||
|
@ -580,7 +580,6 @@ interface nsICanvasRenderingContextWebGL : nsISupports
|
||||
// METHODS
|
||||
//
|
||||
void present();
|
||||
long sizeInBytes(in WebGLenum type);
|
||||
|
||||
void activeTexture(in WebGLenum texture);
|
||||
void attachShader(in nsIWebGLProgram program, in nsIWebGLShader shader);
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
#include "nsIDOMSVGCSS2Properties.idl"
|
||||
|
||||
[scriptable, uuid(649B0B41-C5F7-4EA2-B6DF-CFFF6B6DD30A)]
|
||||
[scriptable, uuid(29B6104D-933F-4DD0-8FC8-BDEC0514469D)]
|
||||
interface nsIDOMNSCSS2Properties : nsIDOMSVGCSS2Properties
|
||||
{
|
||||
/* Non-DOM 2 extensions */
|
||||
@ -282,6 +282,6 @@ interface nsIDOMNSCSS2Properties : nsIDOMSVGCSS2Properties
|
||||
attribute DOMString MozTabSize;
|
||||
// raises(DOMException) on setting
|
||||
|
||||
attribute DOMString MozResize;
|
||||
attribute DOMString resize;
|
||||
// raises(DOMException) on setting
|
||||
};
|
||||
|
@ -311,6 +311,7 @@ TabChild::GetInterface(const nsIID & aIID, void **aSink)
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabChild::ProvideWindow(nsIDOMWindow* aParent, PRUint32 aChromeFlags,
|
||||
PRBool aCalledFromJS,
|
||||
PRBool aPositionSpecified, PRBool aSizeSpecified,
|
||||
nsIURI* aURI, const nsAString& aName,
|
||||
const nsACString& aFeatures, PRBool* aWindowIsNew,
|
||||
|
@ -44,8 +44,7 @@
|
||||
|
||||
#define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName) \
|
||||
{ \
|
||||
_cmdClass* theCmd; \
|
||||
NS_NEWXPCOM(theCmd, _cmdClass); \
|
||||
_cmdClass* theCmd = new _cmdClass(); \
|
||||
NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY); \
|
||||
rv = inCommandTable->RegisterCommand(_cmdName, \
|
||||
static_cast<nsIControllerCommand *>(theCmd)); \
|
||||
@ -53,8 +52,7 @@
|
||||
|
||||
#define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName) \
|
||||
{ \
|
||||
_cmdClass* theCmd; \
|
||||
NS_NEWXPCOM(theCmd, _cmdClass); \
|
||||
_cmdClass* theCmd = new _cmdClass(); \
|
||||
NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY); \
|
||||
rv = inCommandTable->RegisterCommand(_cmdName, \
|
||||
static_cast<nsIControllerCommand *>(theCmd));
|
||||
|
@ -84,8 +84,7 @@ nsComposeTxtSrvFilterConstructor(nsISupports *aOuter, REFNSIID aIID,
|
||||
{
|
||||
return NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
nsComposeTxtSrvFilter * inst;
|
||||
NS_NEWXPCOM(inst, nsComposeTxtSrvFilter);
|
||||
nsComposeTxtSrvFilter * inst = new nsComposeTxtSrvFilter();
|
||||
if (NULL == inst)
|
||||
{
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -47,8 +47,7 @@
|
||||
|
||||
#define NS_REGISTER_ONE_COMMAND(_cmdClass, _cmdName) \
|
||||
{ \
|
||||
_cmdClass* theCmd; \
|
||||
NS_NEWXPCOM(theCmd, _cmdClass); \
|
||||
_cmdClass* theCmd = new _cmdClass(); \
|
||||
NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY); \
|
||||
rv = inCommandTable->RegisterCommand(_cmdName, \
|
||||
static_cast<nsIControllerCommand *>(theCmd)); \
|
||||
@ -56,8 +55,7 @@
|
||||
|
||||
#define NS_REGISTER_FIRST_COMMAND(_cmdClass, _cmdName) \
|
||||
{ \
|
||||
_cmdClass* theCmd; \
|
||||
NS_NEWXPCOM(theCmd, _cmdClass); \
|
||||
_cmdClass* theCmd = new _cmdClass(); \
|
||||
NS_ENSURE_TRUE(theCmd, NS_ERROR_OUT_OF_MEMORY); \
|
||||
rv = inCommandTable->RegisterCommand(_cmdName, \
|
||||
static_cast<nsIControllerCommand *>(theCmd));
|
||||
|
@ -70,7 +70,7 @@ nsrefcnt nsEditorTxnLog::Release(void)
|
||||
{
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
if (--mRefCnt == 0) {
|
||||
NS_DELETEXPCOM(this);
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
|
@ -56,7 +56,7 @@ interface nsIURI;
|
||||
* or the provider does not provide a window, the window watcher will proceed
|
||||
* to actually open a new window.
|
||||
*/
|
||||
[scriptable, uuid(5119ac7f-81dd-4061-96a7-71f2cf5efee4)]
|
||||
[scriptable, uuid(f607bd66-08e5-4d2e-ad83-9f9f3ca17658)]
|
||||
interface nsIWindowProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -114,6 +114,7 @@ interface nsIWindowProvider : nsISupports
|
||||
*/
|
||||
nsIDOMWindow provideWindow(in nsIDOMWindow aParent,
|
||||
in unsigned long aChromeFlags,
|
||||
in boolean aCalledFromJS,
|
||||
in boolean aPositionSpecified,
|
||||
in boolean aSizeSpecified,
|
||||
in nsIURI aURI,
|
||||
|
@ -153,7 +153,7 @@ NS_IMETHODIMP nsWebBrowser::InternalDestroy()
|
||||
if (mListenerArray) {
|
||||
for (PRUint32 i = 0, end = mListenerArray->Length(); i < end; i++) {
|
||||
nsWebBrowserListenerState *state = mListenerArray->ElementAt(i);
|
||||
NS_DELETEXPCOM(state);
|
||||
delete state;
|
||||
}
|
||||
delete mListenerArray;
|
||||
mListenerArray = nsnull;
|
||||
@ -237,14 +237,14 @@ NS_IMETHODIMP nsWebBrowser::AddWebBrowserListener(nsIWeakReference *aListener, c
|
||||
// The window hasn't been created yet, so queue up the listener. They'll be
|
||||
// registered when the window gets created.
|
||||
nsAutoPtr<nsWebBrowserListenerState> state;
|
||||
NS_NEWXPCOM(state, nsWebBrowserListenerState);
|
||||
state = new nsWebBrowserListenerState();
|
||||
if (!state) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
state->mWeakPtr = aListener;
|
||||
state->mID = aIID;
|
||||
|
||||
if (!mListenerArray) {
|
||||
NS_NEWXPCOM(mListenerArray, nsTArray<nsWebBrowserListenerState*>);
|
||||
mListenerArray = new nsTArray<nsWebBrowserListenerState*>();
|
||||
if (!mListenerArray) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -315,9 +315,9 @@ NS_IMETHODIMP nsWebBrowser::RemoveWebBrowserListener(nsIWeakReference *aListener
|
||||
if (0 >= mListenerArray->Length()) {
|
||||
for (PRUint32 i = 0, end = mListenerArray->Length(); i < end; i++) {
|
||||
nsWebBrowserListenerState *state = mListenerArray->ElementAt(i);
|
||||
NS_DELETEXPCOM(state);
|
||||
delete state;
|
||||
}
|
||||
NS_DELETEXPCOM(mListenerArray);
|
||||
delete mListenerArray;
|
||||
mListenerArray = nsnull;
|
||||
}
|
||||
|
||||
@ -1172,9 +1172,9 @@ NS_IMETHODIMP nsWebBrowser::Create()
|
||||
}
|
||||
for (PRUint32 i = 0, end = mListenerArray->Length(); i < end; i++) {
|
||||
nsWebBrowserListenerState *state = mListenerArray->ElementAt(i);
|
||||
NS_DELETEXPCOM(state);
|
||||
delete state;
|
||||
}
|
||||
NS_DELETEXPCOM(mListenerArray);
|
||||
delete mListenerArray;
|
||||
mListenerArray = nsnull;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ NS_IMETHODIMP_(nsrefcnt) nsPrintProgress::Release(void)
|
||||
mRefCnt = 1; /* stabilize */
|
||||
/* enable this to find non-threadsafe destructors: */
|
||||
/* NS_ASSERT_OWNINGTHREAD(nsPrintProgress); */
|
||||
NS_DELETEXPCOM(this);
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
|
@ -623,7 +623,7 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
|
||||
NS_ASSERTION(aParent, "We've _got_ to have a parent here!");
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> newWindow;
|
||||
rv = provider->ProvideWindow(aParent, chromeFlags,
|
||||
rv = provider->ProvideWindow(aParent, chromeFlags, aCalledFromJS,
|
||||
sizeSpec.PositionSpecified(),
|
||||
sizeSpec.SizeSpecified(),
|
||||
uriToLoad, name, features, &windowIsNew,
|
||||
|
@ -58,6 +58,10 @@ _TEST_FILES = \
|
||||
image1.png^headers^ \
|
||||
image2.png \
|
||||
image2.png^headers^ \
|
||||
beltzner.jpg \
|
||||
beltzner.jpg^headers^ \
|
||||
damonbowling.jpg \
|
||||
damonbowling.jpg^headers^ \
|
||||
test1.css \
|
||||
test1.css^headers^ \
|
||||
test2.css \
|
||||
|
BIN
extensions/cookie/test/beltzner.jpg
Normal file
BIN
extensions/cookie/test/beltzner.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.8 KiB |
3
extensions/cookie/test/beltzner.jpg^headers^
Normal file
3
extensions/cookie/test/beltzner.jpg^headers^
Normal file
@ -0,0 +1,3 @@
|
||||
Cache-Control: no-store
|
||||
Set-Cookie: mike=beltzer
|
||||
|
@ -29,5 +29,5 @@ function test() {
|
||||
}, "cookie-rejected", false);
|
||||
|
||||
// kick off a favicon load
|
||||
PageProxySetIcon("http://example.org/tests/extensions/cookie/test/image1.png");
|
||||
PageProxySetIcon("http://example.org/tests/extensions/cookie/test/damonbowling.jpg");
|
||||
}
|
||||
|
BIN
extensions/cookie/test/damonbowling.jpg
Normal file
BIN
extensions/cookie/test/damonbowling.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
2
extensions/cookie/test/damonbowling.jpg^headers^
Normal file
2
extensions/cookie/test/damonbowling.jpg^headers^
Normal file
@ -0,0 +1,2 @@
|
||||
Cache-Control: no-store
|
||||
Set-Cookie: damon=bowling
|
@ -12,6 +12,6 @@
|
||||
</script>
|
||||
</head>
|
||||
<body onload="window.opener.postMessage('f_lf_i msg data page', 'http://mochi.test:8888');">
|
||||
<img src="http://example.org/tests/extensions/cookie/test/image1.png" onload="runTest()" />
|
||||
<img src="http://example.org/tests/extensions/cookie/test/beltzner.jpg" onload="runTest()" />
|
||||
</body>
|
||||
</html>
|
||||
|
@ -7,9 +7,9 @@
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<!--
|
||||
*5 cookies: 1+1 from file_testloadflags.js, 2 from file_loadflags_inner.html + 1 from image1.png^headers^.
|
||||
*5 cookies: 1+1 from file_testloadflags.js, 2 from file_loadflags_inner.html + 1 from beltzner.jpg.
|
||||
*1 load: file_loadflags_inner.html.
|
||||
*2 headers: 1 for file_loadflags_inner.html + 1 for image1.png.
|
||||
*2 headers: 1 for file_loadflags_inner.html + 1 for beltzner.jpg.
|
||||
-->
|
||||
<body onload="setupTest('http://example.org/tests/extensions/cookie/test/file_loadflags_inner.html', 'example.org', 5, 2, 2)">
|
||||
<p id="display"></p>
|
||||
|
@ -86,15 +86,13 @@ mozInlineSpellCheckerConstructor(nsISupports *aOuter, REFNSIID aIID,
|
||||
|
||||
nsresult rv;
|
||||
|
||||
mozInlineSpellChecker* inst;
|
||||
|
||||
*aResult = NULL;
|
||||
if (NULL != aOuter) {
|
||||
rv = NS_ERROR_NO_AGGREGATION;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_NEWXPCOM(inst, mozInlineSpellChecker);
|
||||
mozInlineSpellChecker* inst = new mozInlineSpellChecker();
|
||||
if (NULL == inst) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
return rv;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -74,8 +74,7 @@ nsScriptableRegionConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr <nsIRegion> rgn;
|
||||
NS_NEWXPCOM(rgn, nsThebesRegion);
|
||||
nsCOMPtr <nsIRegion> rgn = new nsThebesRegion();
|
||||
nsCOMPtr<nsIScriptableRegion> scriptableRgn;
|
||||
if (rgn != nsnull)
|
||||
{
|
||||
|
@ -3025,6 +3025,8 @@ typedef ptrdiff_t GLintptr;
|
||||
|
||||
#define LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
|
||||
#define LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
|
||||
#define LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
|
||||
#define LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
|
||||
|
||||
#define LOCAL_WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
|
||||
#define LOCAL_WGL_DRAW_TO_WINDOW_ARB 0x2001
|
||||
|
@ -104,7 +104,7 @@ public: \
|
||||
NS_LOG_RELEASE(this, count, #_class); \
|
||||
if (count == 0) { \
|
||||
mRefCnt = 1; /* stabilize */ \
|
||||
NS_DELETEXPCOM(this); \
|
||||
delete this; \
|
||||
return 0; \
|
||||
} \
|
||||
return count; \
|
||||
|
@ -57,9 +57,7 @@ EXPORTS = \
|
||||
nsICharsetDetectionAdaptor.h \
|
||||
nsICharsetDetectionObserver.h \
|
||||
nsICharsetDetector.h \
|
||||
nsIMetaCharsetService.h \
|
||||
nsIStringCharsetDetector.h \
|
||||
nsIXMLEncodingService.h \
|
||||
nsMetaCharsetCID.h \
|
||||
nsXMLEncodingCID.h \
|
||||
$(NULL)
|
||||
|
@ -1,58 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsIMetaCharsetService_h__
|
||||
#define nsIMetaCharsetService_h__
|
||||
#include "nsISupports.h"
|
||||
|
||||
|
||||
// {218F2AC1-0A48-11d3-B3BA-00805F8A6670}
|
||||
#define NS_IMETA_CHARSET_SERVICE_IID \
|
||||
{ 0x218f2ac1, 0xa48, 0x11d3, { 0xb3, 0xba, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70 } }
|
||||
|
||||
class nsIMetaCharsetService : public nsISupports {
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMETA_CHARSET_SERVICE_IID)
|
||||
|
||||
NS_IMETHOD Start() = 0;
|
||||
NS_IMETHOD End() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMetaCharsetService,
|
||||
NS_IMETA_CHARSET_SERVICE_IID)
|
||||
|
||||
#endif // nsIMetaCharsetService_h__
|
@ -1,59 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsIXMLEncodingService_h__
|
||||
#define nsIXMLEncodingService_h__
|
||||
#include "nsISupports.h"
|
||||
|
||||
|
||||
// {12BB8F11-2389-11d3-B3BF-00805F8A6670}
|
||||
#define NS_IXML_ENCODING_SERVICE_IID \
|
||||
{ 0x12bb8f11, 0x2389, 0x11d3, { 0xb3, 0xbf, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70 } }
|
||||
|
||||
|
||||
class nsIXMLEncodingService : public nsISupports {
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXML_ENCODING_SERVICE_IID)
|
||||
|
||||
NS_IMETHOD Start() = 0;
|
||||
NS_IMETHOD End() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIXMLEncodingService,
|
||||
NS_IXML_ENCODING_SERVICE_IID)
|
||||
|
||||
#endif // nsIXMLEncodingService_h__
|
@ -53,9 +53,6 @@ LIBXUL_LIBRARY = 1
|
||||
|
||||
CPPSRCS = \
|
||||
nsObserverBase.cpp \
|
||||
nsXMLEncodingObserver.cpp \
|
||||
nsMetaCharsetObserver.cpp \
|
||||
nsDetectionAdaptor.cpp \
|
||||
nsDebugDetector.cpp \
|
||||
nsCyrillicDetector.cpp \
|
||||
nsDocumentCharsetInfo.cpp \
|
||||
|
@ -49,22 +49,16 @@
|
||||
#include "nsMetaCharsetCID.h"
|
||||
#include "nsICharsetDetector.h"
|
||||
#include "nsICharsetAlias.h"
|
||||
#include "nsMetaCharsetObserver.h"
|
||||
#include "nsDocumentCharsetInfo.h"
|
||||
#include "nsXMLEncodingObserver.h"
|
||||
#include "nsICharsetDetectionAdaptor.h"
|
||||
#include "nsICharsetDetectionObserver.h"
|
||||
#include "nsDetectionAdaptor.h"
|
||||
#include "nsIStringCharsetDetector.h"
|
||||
#include "nsCyrillicDetector.h"
|
||||
#include "nsDocumentCharsetInfoCID.h"
|
||||
#include "nsXMLEncodingCID.h"
|
||||
#include "nsCharsetDetectionAdaptorCID.h"
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMetaCharsetObserver)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDocumentCharsetInfo)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsXMLEncodingObserver)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDetectionAdaptor)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsRUProbDetector)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUKProbDetector)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsRUStringProbDetector)
|
||||
|
@ -42,10 +42,7 @@
|
||||
|
||||
#include "nsCharDetConstructors.h"
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_META_CHARSET_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_DOCUMENTCHARSETINFO_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_XML_ENCODING_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_CHARSET_DETECTION_ADAPTOR_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_RU_PROBDETECTOR_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_UK_PROBDETECTOR_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_RU_STRING_PROBDETECTOR_CID);
|
||||
@ -57,10 +54,7 @@ NS_DEFINE_NAMED_CID(NS_LASTBLKDBG_DETECTOR_CID);
|
||||
#endif /* INCLUDE_DBGDETECTOR */
|
||||
|
||||
static const mozilla::Module::CIDEntry kChardetCIDs[] = {
|
||||
{ &kNS_META_CHARSET_CID, false, NULL, nsMetaCharsetObserverConstructor },
|
||||
{ &kNS_DOCUMENTCHARSETINFO_CID, false, NULL, nsDocumentCharsetInfoConstructor },
|
||||
{ &kNS_XML_ENCODING_CID, false, NULL, nsXMLEncodingObserverConstructor },
|
||||
{ &kNS_CHARSET_DETECTION_ADAPTOR_CID, false, NULL, nsDetectionAdaptorConstructor },
|
||||
{ &kNS_RU_PROBDETECTOR_CID, false, NULL, nsRUProbDetectorConstructor },
|
||||
{ &kNS_UK_PROBDETECTOR_CID, false, NULL, nsUKProbDetectorConstructor },
|
||||
{ &kNS_RU_STRING_PROBDETECTOR_CID, false, NULL, nsRUStringProbDetectorConstructor },
|
||||
@ -74,10 +68,7 @@ static const mozilla::Module::CIDEntry kChardetCIDs[] = {
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kChardetContracts[] = {
|
||||
{ NS_META_CHARSET_CONTRACTID, &kNS_META_CHARSET_CID },
|
||||
{ NS_DOCUMENTCHARSETINFO_CONTRACTID, &kNS_DOCUMENTCHARSETINFO_CID },
|
||||
{ NS_XML_ENCODING_CONTRACTID, &kNS_XML_ENCODING_CID },
|
||||
{ NS_CHARSET_DETECTION_ADAPTOR_CONTRACTID, &kNS_CHARSET_DETECTION_ADAPTOR_CID },
|
||||
{ NS_CHARSET_DETECTOR_CONTRACTID_BASE "ruprob", &kNS_RU_PROBDETECTOR_CID },
|
||||
{ NS_CHARSET_DETECTOR_CONTRACTID_BASE "ukprob", &kNS_UK_PROBDETECTOR_CID },
|
||||
{ NS_STRCDETECTOR_CONTRACTID_BASE "ruprob", &kNS_RU_STRING_PROBDETECTOR_CID },
|
||||
|
@ -1,171 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsString.h"
|
||||
#include "plstr.h"
|
||||
#include "pratom.h"
|
||||
#include "nsCharDetDll.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsDetectionAdaptor.h"
|
||||
#include "nsIContentSink.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------
|
||||
NS_IMETHODIMP nsMyObserver::Notify(
|
||||
const char* aCharset, nsDetectionConfident aConf)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if(mWeakRefParser) {
|
||||
nsCAutoString existingCharset;
|
||||
PRInt32 existingSource;
|
||||
mWeakRefParser->GetDocumentCharset(existingCharset, existingSource);
|
||||
if (existingSource >= kCharsetFromAutoDetection)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if(!mCharset.Equals(aCharset)) {
|
||||
if(mNotifyByReload) {
|
||||
rv = mWebShellSvc->StopDocumentLoad();
|
||||
rv = mWebShellSvc->ReloadDocument(aCharset, kCharsetFromAutoDetection);
|
||||
} else {
|
||||
nsDependentCString newcharset(aCharset);
|
||||
if (mWeakRefParser) {
|
||||
mWeakRefParser->SetDocumentCharset(newcharset, kCharsetFromAutoDetection);
|
||||
nsCOMPtr<nsIContentSink> contentSink = mWeakRefParser->GetContentSink();
|
||||
if (contentSink)
|
||||
contentSink->SetDocumentCharset(newcharset);
|
||||
}
|
||||
if(mWeakRefDocument)
|
||||
mWeakRefDocument->SetDocumentCharacterSet(newcharset);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
NS_IMETHODIMP nsMyObserver::Init( nsIWebShellServices* aWebShellSvc,
|
||||
nsIDocument* aDocument,
|
||||
nsIParser* aParser,
|
||||
const char* aCharset,
|
||||
const char* aCommand)
|
||||
{
|
||||
if(aCommand) {
|
||||
mCommand = aCommand;
|
||||
}
|
||||
if(aCharset) {
|
||||
mCharset = aCharset;
|
||||
}
|
||||
if(aDocument) {
|
||||
mWeakRefDocument = aDocument;
|
||||
}
|
||||
if(aParser) {
|
||||
mWeakRefParser = aParser;
|
||||
}
|
||||
if(nsnull != aWebShellSvc)
|
||||
{
|
||||
mWebShellSvc = aWebShellSvc;
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
NS_IMPL_ISUPPORTS1 ( nsMyObserver ,nsICharsetDetectionObserver)
|
||||
|
||||
//--------------------------------------------------------------
|
||||
nsDetectionAdaptor::nsDetectionAdaptor( void )
|
||||
{
|
||||
mDontFeedToDetector = PR_TRUE;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
nsDetectionAdaptor::~nsDetectionAdaptor()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
NS_IMPL_ISUPPORTS2 (nsDetectionAdaptor, nsIParserFilter, nsICharsetDetectionAdaptor)
|
||||
|
||||
//--------------------------------------------------------------
|
||||
NS_IMETHODIMP nsDetectionAdaptor::Init(
|
||||
nsIWebShellServices* aWebShellSvc, nsICharsetDetector *aDetector,
|
||||
nsIDocument* aDocument, nsIParser* aParser, const char* aCharset,
|
||||
const char* aCommand)
|
||||
{
|
||||
if((nsnull != aWebShellSvc) && (nsnull != aDetector) && (nsnull != aCharset))
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
mObserver = new nsMyObserver();
|
||||
if(!mObserver)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = mObserver->Init(aWebShellSvc, aDocument, aParser, aCharset, aCommand);
|
||||
if(NS_SUCCEEDED(rv)) {
|
||||
rv = aDetector->Init(mObserver.get());
|
||||
if(NS_SUCCEEDED(rv)) {
|
||||
mDetector = aDetector;
|
||||
mDontFeedToDetector = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
NS_IMETHODIMP nsDetectionAdaptor::RawBuffer
|
||||
(const char * buffer, PRUint32 * buffer_length)
|
||||
{
|
||||
if((mDontFeedToDetector) || (!mDetector))
|
||||
return NS_OK;
|
||||
nsresult rv = NS_OK;
|
||||
rv = mDetector->DoIt((const char*)buffer, *buffer_length, &mDontFeedToDetector);
|
||||
if(mObserver)
|
||||
mObserver->SetNotifyByReload(PR_TRUE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
NS_IMETHODIMP nsDetectionAdaptor::Finish()
|
||||
{
|
||||
if((mDontFeedToDetector) || (!mDetector))
|
||||
return NS_OK;
|
||||
nsresult rv = NS_OK;
|
||||
rv = mDetector->Done();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1,131 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifndef nsDetectionAdaptor_h__
|
||||
#define nsDetectionAdaptor_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIWebShellServices.h"
|
||||
|
||||
#include "nsIParserFilter.h"
|
||||
static NS_DEFINE_IID(kIParserFilterIID, NS_IPARSERFILTER_IID);
|
||||
|
||||
class nsIDocument;
|
||||
class CToken;
|
||||
|
||||
//--------------------------------------------------------------
|
||||
class nsMyObserver : public nsICharsetDetectionObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
public:
|
||||
nsMyObserver( void )
|
||||
{
|
||||
mWebShellSvc = nsnull;
|
||||
mNotifyByReload = PR_FALSE;
|
||||
mWeakRefDocument = nsnull;
|
||||
mWeakRefParser = nsnull;
|
||||
}
|
||||
virtual ~nsMyObserver( void )
|
||||
{
|
||||
// do not release nor delete mWeakRefDocument
|
||||
// do not release nor delete mWeakRefParser
|
||||
}
|
||||
|
||||
|
||||
// Methods to support nsICharsetDetectionAdaptor
|
||||
NS_IMETHOD Init(nsIWebShellServices* aWebShellSvc,
|
||||
nsIDocument* aDocument,
|
||||
nsIParser* aParser,
|
||||
const char* aCharset,
|
||||
const char* aCommand);
|
||||
|
||||
// Methods to support nsICharsetDetectionObserver
|
||||
NS_IMETHOD Notify(const char* aCharset, nsDetectionConfident aConf);
|
||||
void SetNotifyByReload(PRBool aByReload) { mNotifyByReload = aByReload; }
|
||||
private:
|
||||
nsCOMPtr<nsIWebShellServices> mWebShellSvc;
|
||||
PRBool mNotifyByReload;
|
||||
|
||||
//The adaptor is owned by parser as filter, and adaptor owns detector,
|
||||
//which in turn owns observer. Parser also live within the lifespan of
|
||||
//document. The ownership tree is like:
|
||||
// document->parser->adaptor->detector->observer
|
||||
//We do not want to own Document & Parser to avoid ownership loop. That
|
||||
//will cause memory leakage.
|
||||
//If in future this chain got changed, ie. parser outlives document, or
|
||||
//detector outlives parser, we might want to change weak reference here.
|
||||
nsIDocument* mWeakRefDocument;
|
||||
nsIParser* mWeakRefParser;
|
||||
nsCAutoString mCharset;
|
||||
nsCAutoString mCommand;
|
||||
};
|
||||
|
||||
class nsDetectionAdaptor :
|
||||
public nsIParserFilter,
|
||||
public nsICharsetDetectionAdaptor
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
public:
|
||||
nsDetectionAdaptor( void );
|
||||
virtual ~nsDetectionAdaptor( void );
|
||||
|
||||
// Methods to support nsICharsetDetectionAdaptor
|
||||
NS_IMETHOD Init(nsIWebShellServices* aWebShellSvc, nsICharsetDetector *aDetector,
|
||||
nsIDocument* aDocument,
|
||||
nsIParser* aParser,
|
||||
const char* aCharset,
|
||||
const char* aCommand=nsnull);
|
||||
|
||||
// Methode to suppor nsIParserFilter
|
||||
NS_IMETHOD RawBuffer(const char * buffer, PRUint32 * buffer_length) ;
|
||||
NS_IMETHOD Finish();
|
||||
|
||||
// really don't care the following two, only because they are defined
|
||||
// in nsIParserFilter.h
|
||||
NS_IMETHOD WillAddToken(CToken & token) { return NS_OK; }
|
||||
NS_IMETHOD ProcessTokens( void ) {return NS_OK;}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsICharsetDetector> mDetector;
|
||||
PRBool mDontFeedToDetector;
|
||||
nsCOMPtr<nsMyObserver> mObserver;
|
||||
};
|
||||
|
||||
#endif /* nsDetectionAdaptor_h__ */
|
@ -1,440 +0,0 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#include "nsDeque.h"
|
||||
#include "nsICharsetAlias.h"
|
||||
#include "nsMetaCharsetObserver.h"
|
||||
#include "nsIMetaCharsetService.h"
|
||||
#include "nsIElementObserver.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIParser.h"
|
||||
#include "pratom.h"
|
||||
#include "nsCharDetDll.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsObserverBase.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIParserService.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsMetaCharsetCID.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
|
||||
static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID);
|
||||
|
||||
static const eHTMLTags gWatchTags[] =
|
||||
{ eHTMLTag_meta,
|
||||
eHTMLTag_unknown
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
nsMetaCharsetObserver::nsMetaCharsetObserver()
|
||||
{
|
||||
bMetaCharsetObserverStarted = PR_FALSE;
|
||||
nsresult res;
|
||||
mAlias = nsnull;
|
||||
nsCOMPtr<nsICharsetAlias> calias(do_GetService(kCharsetAliasCID, &res));
|
||||
if(NS_SUCCEEDED(res)) {
|
||||
mAlias = calias;
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
nsMetaCharsetObserver::~nsMetaCharsetObserver()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMPL_ADDREF ( nsMetaCharsetObserver )
|
||||
NS_IMPL_RELEASE ( nsMetaCharsetObserver )
|
||||
|
||||
// Use the new scheme
|
||||
NS_IMPL_QUERY_INTERFACE4(nsMetaCharsetObserver,
|
||||
nsIElementObserver,
|
||||
nsIObserver,
|
||||
nsIMetaCharsetService,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::Notify(
|
||||
PRUint32 aDocumentID,
|
||||
const PRUnichar* aTag,
|
||||
PRUint32 numOfAttributes,
|
||||
const PRUnichar* nameArray[],
|
||||
const PRUnichar* valueArray[])
|
||||
{
|
||||
|
||||
if(!nsDependentString(aTag).LowerCaseEqualsLiteral("meta"))
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
else
|
||||
return Notify(aDocumentID, numOfAttributes, nameArray, valueArray);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::Notify(
|
||||
PRUint32 aDocumentID,
|
||||
eHTMLTags aTag,
|
||||
PRUint32 numOfAttributes,
|
||||
const PRUnichar* nameArray[],
|
||||
const PRUnichar* valueArray[])
|
||||
{
|
||||
if(eHTMLTag_meta != aTag)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
else
|
||||
return Notify(aDocumentID, numOfAttributes, nameArray, valueArray);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::Notify(
|
||||
PRUint32 aDocumentID,
|
||||
PRUint32 numOfAttributes,
|
||||
const PRUnichar* nameArray[],
|
||||
const PRUnichar* valueArray[])
|
||||
{
|
||||
nsDeque keys(0);
|
||||
nsDeque values(0);
|
||||
PRUint32 i;
|
||||
for(i=0;i<numOfAttributes;i++)
|
||||
{
|
||||
keys.Push((void*)nameArray[i]);
|
||||
values.Push((void*)valueArray[i]);
|
||||
}
|
||||
return NS_OK;//Notify((nsISupports*)aDocumentID, &keys, &values);
|
||||
}
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::Notify(
|
||||
nsISupports* aDocShell,
|
||||
nsISupports* aChannel,
|
||||
const PRUnichar* aTag,
|
||||
const nsTArray<nsString>* keys,
|
||||
const nsTArray<nsString>* values,
|
||||
const PRUint32 aFlags)
|
||||
{
|
||||
nsresult result = NS_OK;
|
||||
// bug 125317 - document.write content is already an unicode content.
|
||||
if (!(aFlags & nsIElementObserver::IS_DOCUMENT_WRITE)) {
|
||||
if(!nsDependentString(aTag).LowerCaseEqualsLiteral("meta")) {
|
||||
result = NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
else {
|
||||
result = Notify(aDocShell, aChannel, keys, values);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define IS_SPACE_CHARS(ch) (ch == ' ' || ch == '\b' || ch == '\r' || ch == '\n')
|
||||
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::Notify(
|
||||
nsISupports* aDocShell,
|
||||
nsISupports* aChannel,
|
||||
const nsTArray<nsString>* keys,
|
||||
const nsTArray<nsString>* values)
|
||||
{
|
||||
NS_PRECONDITION(keys!=nsnull && values!=nsnull,"Need key-value pair");
|
||||
|
||||
PRUint32 numOfAttributes = keys->Length();
|
||||
NS_ASSERTION( numOfAttributes == values->Length(), "size mismatch");
|
||||
nsresult res=NS_OK;
|
||||
#ifdef DEBUG
|
||||
|
||||
PRUnichar Uxcommand[]={'X','_','C','O','M','M','A','N','D','\0'};
|
||||
PRUnichar UcharsetSource[]={'c','h','a','r','s','e','t','S','o','u','r','c','e','\0'};
|
||||
PRUnichar Ucharset[]={'c','h','a','r','s','e','t','\0'};
|
||||
|
||||
NS_ASSERTION(numOfAttributes >= 3, "should have at least 3 private attribute");
|
||||
NS_ASSERTION(0==nsCRT::strcmp(Uxcommand,(keys->ElementAt(numOfAttributes-1)).get()),"last name should be 'X_COMMAND'" );
|
||||
NS_ASSERTION(0==nsCRT::strcmp(UcharsetSource,(keys->ElementAt(numOfAttributes-2)).get()),"2nd last name should be 'charsetSource'" );
|
||||
NS_ASSERTION(0==nsCRT::strcmp(Ucharset,(keys->ElementAt(numOfAttributes-3)).get()),"3rd last name should be 'charset'" );
|
||||
|
||||
#endif
|
||||
NS_ASSERTION(mAlias, "Didn't get nsICharsetAlias in constructor");
|
||||
|
||||
if(nsnull == mAlias)
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
// we need at least 5 - HTTP-EQUIV, CONTENT and 3 private
|
||||
if(numOfAttributes >= 5 )
|
||||
{
|
||||
const nsString& srcStr = values->ElementAt(numOfAttributes-2);
|
||||
PRInt32 err;
|
||||
PRInt32 src = srcStr.ToInteger(&err);
|
||||
// if we cannot convert the string into PRInt32, return error
|
||||
NS_ASSERTION(NS_SUCCEEDED(err), "cannot get charset source");
|
||||
if(NS_FAILED(err))
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
if(kCharsetFromMetaTag <= src)
|
||||
return NS_OK; // current charset has higher priority. don't bother to do the following
|
||||
|
||||
const PRUnichar *httpEquivValue=nsnull;
|
||||
const PRUnichar *contentValue=nsnull;
|
||||
const PRUnichar *charsetValue=nsnull;
|
||||
|
||||
for (PRUint32 i = 0; i < numOfAttributes - 3; i++)
|
||||
{
|
||||
const PRUnichar *keyStr;
|
||||
keyStr = keys->ElementAt(i).get();
|
||||
|
||||
//Change 3.190 in nsHTMLTokens.cpp allow ws/tab/cr/lf exist before
|
||||
// and after text value, this need to be skipped before comparison
|
||||
while(IS_SPACE_CHARS(*keyStr))
|
||||
keyStr++;
|
||||
|
||||
if(Substring(keyStr, keyStr+10).LowerCaseEqualsLiteral("http-equiv"))
|
||||
httpEquivValue = values->ElementAt(i).get();
|
||||
else if(Substring(keyStr, keyStr+7).LowerCaseEqualsLiteral("content"))
|
||||
contentValue = values->ElementAt(i).get();
|
||||
else if (Substring(keyStr, keyStr+7).LowerCaseEqualsLiteral("charset"))
|
||||
charsetValue = values->ElementAt(i).get();
|
||||
}
|
||||
NS_NAMED_LITERAL_STRING(contenttype, "Content-Type");
|
||||
NS_NAMED_LITERAL_STRING(texthtml, "text/html");
|
||||
|
||||
if(nsnull == httpEquivValue || nsnull == contentValue)
|
||||
return NS_OK;
|
||||
|
||||
while(IS_SPACE_CHARS(*httpEquivValue))
|
||||
++httpEquivValue;
|
||||
// skip opening quote
|
||||
if (*httpEquivValue == '\'' || *httpEquivValue == '\"')
|
||||
++httpEquivValue;
|
||||
|
||||
while(IS_SPACE_CHARS(*contentValue))
|
||||
++contentValue;
|
||||
// skip opening quote
|
||||
if (*contentValue == '\'' || *contentValue == '\"')
|
||||
++contentValue;
|
||||
|
||||
if(
|
||||
Substring(httpEquivValue,
|
||||
httpEquivValue+contenttype.Length()).Equals(contenttype,
|
||||
nsCaseInsensitiveStringComparator())
|
||||
&&
|
||||
Substring(contentValue,
|
||||
contentValue+texthtml.Length()).Equals(texthtml,
|
||||
nsCaseInsensitiveStringComparator())
|
||||
)
|
||||
{
|
||||
|
||||
nsCAutoString newCharset;
|
||||
|
||||
if (nsnull == charsetValue)
|
||||
{
|
||||
nsAutoString contentPart1(contentValue+9); // after "text/html"
|
||||
PRInt32 start = contentPart1.RFind("charset=", PR_TRUE ) ;
|
||||
PRInt32 end = contentPart1.Length();
|
||||
if(kNotFound != start)
|
||||
{
|
||||
start += 8; // 8 = "charset=".length
|
||||
while (start < end && contentPart1.CharAt(start) == PRUnichar(' '))
|
||||
++start;
|
||||
if (start < end) {
|
||||
end = contentPart1.FindCharInSet("\'\"; ", start);
|
||||
if(kNotFound == end )
|
||||
end = contentPart1.Length();
|
||||
NS_ASSERTION(end>=start, "wrong index");
|
||||
LossyCopyUTF16toASCII(Substring(contentPart1, start, end-start),
|
||||
newCharset);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LossyCopyUTF16toASCII(nsDependentString(charsetValue), newCharset);
|
||||
}
|
||||
|
||||
nsCAutoString charsetString;
|
||||
charsetString.AssignWithConversion(values->ElementAt(numOfAttributes-3));
|
||||
|
||||
if (!newCharset.IsEmpty())
|
||||
{
|
||||
if(! newCharset.Equals(charsetString, nsCaseInsensitiveCStringComparator()))
|
||||
{
|
||||
PRBool same = PR_FALSE;
|
||||
nsresult res2 = mAlias->Equals( newCharset, charsetString , &same);
|
||||
if(NS_SUCCEEDED(res2) && (! same))
|
||||
{
|
||||
nsCAutoString preferred;
|
||||
res2 = mAlias->GetPreferred(newCharset, preferred);
|
||||
if(NS_SUCCEEDED(res2))
|
||||
{
|
||||
// following charset should have been detected by parser
|
||||
if (!preferred.EqualsLiteral("UTF-16") &&
|
||||
!preferred.EqualsLiteral("UTF-16BE") &&
|
||||
!preferred.EqualsLiteral("UTF-16LE") &&
|
||||
!preferred.EqualsLiteral("UTF-32") &&
|
||||
!preferred.EqualsLiteral("UTF-32BE") &&
|
||||
!preferred.EqualsLiteral("UTF-32LE")) {
|
||||
// Propagate the error message so that the parser can
|
||||
// shutdown correctly. - Ref. Bug 96440
|
||||
res = NotifyDocShell(aDocShell,
|
||||
aChannel,
|
||||
preferred.get(),
|
||||
kCharsetFromMetaTag);
|
||||
}
|
||||
} // if(NS_SUCCEEDED(res)
|
||||
}
|
||||
}
|
||||
else {
|
||||
res = NS_HTMLPARSER_VALID_META_CHARSET;
|
||||
} // if EqualIgnoreCase
|
||||
} // if !newCharset.IsEmpty()
|
||||
} // if
|
||||
}
|
||||
else
|
||||
{
|
||||
nsAutoString compatCharset;
|
||||
if (NS_SUCCEEDED(GetCharsetFromCompatibilityTag(keys, values, compatCharset)))
|
||||
{
|
||||
if (!compatCharset.IsEmpty()) {
|
||||
res = NotifyDocShell(aDocShell,
|
||||
aChannel,
|
||||
NS_ConvertUTF16toUTF8(compatCharset).get(),
|
||||
kCharsetFromMetaTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::GetCharsetFromCompatibilityTag(
|
||||
const nsTArray<nsString>* keys,
|
||||
const nsTArray<nsString>* values,
|
||||
nsAString& aCharset)
|
||||
{
|
||||
if (!mAlias)
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
aCharset.Truncate(0);
|
||||
nsresult res = NS_OK;
|
||||
|
||||
|
||||
// support for non standard case for compatibility
|
||||
// e.g. <META charset="ISO-8859-1">
|
||||
PRUint32 numOfAttributes = keys->Length();
|
||||
if ((numOfAttributes >= 3) &&
|
||||
(keys->ElementAt(0).LowerCaseEqualsLiteral("charset")))
|
||||
{
|
||||
const nsString& srcStr = values->ElementAt(numOfAttributes-2);
|
||||
PRInt32 err;
|
||||
PRInt32 src = srcStr.ToInteger(&err);
|
||||
// if we cannot convert the string into PRInt32, return error
|
||||
if (NS_FAILED(err))
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
// current charset have a lower priority
|
||||
if (kCharsetFromMetaTag > src)
|
||||
{
|
||||
nsCAutoString newCharset;
|
||||
newCharset.AssignWithConversion(values->ElementAt(0).get());
|
||||
|
||||
nsCAutoString preferred;
|
||||
res = mAlias->GetPreferred(newCharset,
|
||||
preferred);
|
||||
if (NS_SUCCEEDED(res))
|
||||
{
|
||||
// compare against the current charset,
|
||||
// also some charsets which should have been found in
|
||||
// the BOM detection.
|
||||
const nsString& currentCharset = values->ElementAt(numOfAttributes-3);
|
||||
if (!preferred.Equals(NS_LossyConvertUTF16toASCII(currentCharset)) &&
|
||||
!preferred.EqualsLiteral("UTF-16") &&
|
||||
!preferred.EqualsLiteral("UTF-16BE") &&
|
||||
!preferred.EqualsLiteral("UTF-16LE") &&
|
||||
!preferred.EqualsLiteral("UTF-32") &&
|
||||
!preferred.EqualsLiteral("UTF-32BE") &&
|
||||
!preferred.EqualsLiteral("UTF-32LE"))
|
||||
AppendASCIItoUTF16(preferred, aCharset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const PRUnichar *aData)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (!nsCRT::strcmp(aTopic, "parser-service-start")) {
|
||||
rv = Start();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::Start()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!bMetaCharsetObserverStarted) {
|
||||
bMetaCharsetObserverStarted = PR_TRUE;
|
||||
|
||||
nsCOMPtr<nsIParserService> parserService(do_GetService(NS_PARSERSERVICE_CONTRACTID, &rv));
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = parserService->RegisterObserver(this,
|
||||
NS_LITERAL_STRING("text/html"),
|
||||
gWatchTags);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsMetaCharsetObserver::End()
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (bMetaCharsetObserverStarted) {
|
||||
bMetaCharsetObserverStarted = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIParserService> parserService(do_GetService(NS_PARSERSERVICE_CONTRACTID, &rv));
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = parserService->UnregisterObserver(this, NS_LITERAL_STRING("text/html"));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
//==========================================================================
|
||||
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user