This commit is contained in:
Ehsan Akhgari 2011-03-29 14:32:11 -04:00
Родитель a3102e59d9 09dbfeb0c8
Коммит 434023cd79
501 изменённых файлов: 16202 добавлений и 18606 удалений

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

@ -1272,6 +1272,27 @@ nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
g_signal_emit(atkObj, id, 0);
} break;
case nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_MAXIMIZE\n"));
guint id = g_signal_lookup ("maximize", MAI_TYPE_ATK_OBJECT);
g_signal_emit(atkObj, id, 0);
} break;
case nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_MINIMIZE\n"));
guint id = g_signal_lookup ("minimize", MAI_TYPE_ATK_OBJECT);
g_signal_emit(atkObj, id, 0);
} break;
case nsIAccessibleEvent::EVENT_WINDOW_RESTORE:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_WINDOW_RESTORE\n"));
guint id = g_signal_lookup ("restore", MAI_TYPE_ATK_OBJECT);
g_signal_emit(atkObj, id, 0);
} break;
case nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_DOCUMENT_LOAD_COMPLETE\n"));

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

@ -218,6 +218,24 @@ mai_util_get_type(void)
return type;
}
static void
window_added (AtkObject *atk_obj,
guint index,
AtkObject *child)
{
guint id = g_signal_lookup ("create", MAI_TYPE_ATK_OBJECT);
g_signal_emit (child, id, 0);
}
static void
window_removed (AtkObject *atk_obj,
guint index,
AtkObject *child)
{
guint id = g_signal_lookup ("destroy", MAI_TYPE_ATK_OBJECT);
g_signal_emit (child, id, 0);
}
/* intialize the the atk interface (function pointers) with MAI implementation.
* When atk bridge get loaded, these interface can be used.
*/
@ -248,6 +266,10 @@ mai_util_class_init(MaiUtilClass *klass)
listener_list = g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
_listener_info_destroy);
// Keep track of added/removed windows.
AtkObject *root = atk_get_root ();
g_signal_connect (root, "children-changed::add", (GCallback) window_added, NULL);
g_signal_connect (root, "children-changed::remove", (GCallback) window_removed, NULL);
}
static guint

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

@ -304,10 +304,10 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
if (accEvent->mEventRule != AccEvent::eDoNotEmit) {
mDocument->ProcessPendingEvent(accEvent);
AccMutationEvent* showOrhideEvent = downcast_accEvent(accEvent);
if (showOrhideEvent) {
if (showOrhideEvent->mTextChangeEvent)
mDocument->ProcessPendingEvent(showOrhideEvent->mTextChangeEvent);
AccMutationEvent* showOrHideEvent = downcast_accEvent(accEvent);
if (showOrHideEvent) {
if (showOrHideEvent->mTextChangeEvent)
mDocument->ProcessPendingEvent(showOrHideEvent->mTextChangeEvent);
}
}
if (!mDocument)

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

@ -70,7 +70,10 @@ TextUpdater::DoUpdate(const nsAString& aNewText, const nsAString& aOldText,
PRUint32 aSkipStart)
{
nsAccessible* parent = mTextLeaf->GetParent();
NS_ASSERTION(parent, "No parent for text leaf!");
if (!parent) {
NS_ERROR("No parent for text leaf!");
return;
}
mHyperText = parent->AsHyperText();
if (!mHyperText) {

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

@ -374,16 +374,6 @@ public:
role != nsIAccessibleRole::ROLE_STATICTEXT;
}
/**
* Return true if the given accessible hasn't children.
*/
static inline PRBool IsLeaf(nsIAccessible *aAcc)
{
PRInt32 numChildren = 0;
aAcc->GetChildCount(&numChildren);
return numChildren == 0;
}
/**
* Return true if the given accessible can't have children. Used when exposing
* to platform accessibility APIs, should the children be pruned off?

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

@ -100,6 +100,7 @@
#endif
#include "mozilla/FunctionTimer.h"
#include "mozilla/dom/Element.h"
////////////////////////////////////////////////////////////////////////////////
// nsAccessibilityService
@ -275,7 +276,7 @@ nsAccessibilityService::CreateHTMLImageAccessible(nsIContent* aContent,
if (!mapElmName.IsEmpty()) {
if (mapElmName.CharAt(0) == '#')
mapElmName.Cut(0,1);
mapElm = htmlDoc->GetImageMap(mapElmName);
mapElm = do_QueryInterface(htmlDoc->GetImageMap(mapElmName));
}
}
@ -537,6 +538,22 @@ nsAccessibilityService::UpdateText(nsIPresShell* aPresShell,
document->UpdateText(aContent);
}
void
nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell,
nsIContent* aHTMLListItemContent,
bool aHasBullet)
{
nsDocAccessible* document = GetDocAccessible(aPresShell->GetDocument());
if (document) {
nsAccessible* accessible = document->GetAccessible(aHTMLListItemContent);
if (accessible) {
nsHTMLLIAccessible* listItem = accessible->AsHTMLListItem();
if (listItem)
listItem->UpdateBullet(aHasBullet);
}
}
}
void
nsAccessibilityService::PresShellDestroyed(nsIPresShell *aPresShell)
{

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

@ -120,6 +120,13 @@ public:
virtual void UpdateText(nsIPresShell* aPresShell, nsIContent* aContent);
/**
* Update list bullet accessible.
*/
virtual void UpdateListBullet(nsIPresShell* aPresShell,
nsIContent* aHTMLListItemContent,
bool aHasBullet);
virtual void NotifyOfAnchorJumpTo(nsIContent *aTarget);
virtual void PresShellDestroyed(nsIPresShell* aPresShell);

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

@ -765,24 +765,22 @@ nsAccessible::GetFocusedChild(nsIAccessible **aFocusedChild)
}
// nsAccessible::GetChildAtPoint()
nsresult
nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, PRBool aDeepestChild,
nsIAccessible **aChild)
nsAccessible*
nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild)
{
// If we can't find the point in a child, we will return the fallback answer:
// we return |this| if the point is within it, otherwise nsnull.
PRInt32 x = 0, y = 0, width = 0, height = 0;
nsresult rv = GetBounds(&x, &y, &width, &height);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, nsnull);
nsCOMPtr<nsIAccessible> fallbackAnswer;
nsAccessible* fallbackAnswer = nsnull;
if (aX >= x && aX < x + width && aY >= y && aY < y + height)
fallbackAnswer = this;
if (nsAccUtils::MustPrune(this)) { // Do not dig any further
NS_IF_ADDREF(*aChild = fallbackAnswer);
return NS_OK;
}
if (nsAccUtils::MustPrune(this)) // Do not dig any further
return fallbackAnswer;
// Search an accessible at the given point starting from accessible document
// because containing block (see CSS2) for out of flow element (for example,
@ -791,10 +789,10 @@ nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, PRBool aDeepestChild,
// for DOM parent but GetFrameForPoint() should be called for containing block
// to get an out of flow element.
nsDocAccessible *accDocument = GetDocAccessible();
NS_ENSURE_TRUE(accDocument, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(accDocument, nsnull);
nsIFrame *frame = accDocument->GetFrame();
NS_ENSURE_STATE(frame);
NS_ENSURE_TRUE(frame, nsnull);
nsPresContext *presContext = frame->PresContext();
@ -806,19 +804,15 @@ nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, PRBool aDeepestChild,
nsIFrame *foundFrame = presShell->GetFrameForPoint(frame, offset);
nsIContent* content = nsnull;
if (!foundFrame || !(content = foundFrame->GetContent())) {
NS_IF_ADDREF(*aChild = fallbackAnswer);
return NS_OK;
}
if (!foundFrame || !(content = foundFrame->GetContent()))
return fallbackAnswer;
// Get accessible for the node with the point or the first accessible in
// the DOM parent chain.
nsAccessible* accessible =
GetAccService()->GetAccessibleOrContainer(content, mWeakShell);
if (!accessible) {
NS_IF_ADDREF(*aChild = fallbackAnswer);
return NS_OK;
}
if (!accessible)
return fallbackAnswer;
if (accessible == this) {
// Manually walk through accessible children and see if the are within this
@ -836,40 +830,36 @@ nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY, PRBool aDeepestChild,
aY >= childY && aY < childY + childHeight &&
(nsAccUtils::State(child) & nsIAccessibleStates::STATE_INVISIBLE) == 0) {
if (aDeepestChild)
return child->GetDeepestChildAtPoint(aX, aY, aChild);
if (aWhichChild == eDeepestChild)
return child->GetChildAtPoint(aX, aY, eDeepestChild);
NS_IF_ADDREF(*aChild = child);
return NS_OK;
return child;
}
}
// The point is in this accessible but not in a child. We are allowed to
// return |this| as the answer.
NS_IF_ADDREF(*aChild = accessible);
return NS_OK;
return accessible;
}
// Since DOM node of obtained accessible may be out of flow then we should
// ensure obtained accessible is a child of this accessible.
nsCOMPtr<nsIAccessible> parent, child(accessible);
while (PR_TRUE) {
child->GetParent(getter_AddRefs(parent));
nsAccessible* child = accessible;
while (true) {
nsAccessible* parent = child->GetParent();
if (!parent) {
// Reached the top of the hierarchy. These bounds were inside an
// accessible that is not a descendant of this one.
NS_IF_ADDREF(*aChild = fallbackAnswer);
return NS_OK;
return fallbackAnswer;
}
if (parent == this) {
NS_ADDREF(*aChild = (aDeepestChild ? accessible : child));
return NS_OK;
}
child.swap(parent);
if (parent == this)
return aWhichChild == eDeepestChild ? accessible : child;
child = parent;
}
return NS_OK;
return nsnull;
}
// nsIAccessible getChildAtPoint(in long x, in long y)
@ -883,7 +873,8 @@ nsAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
if (IsDefunct())
return NS_ERROR_FAILURE;
return GetChildAtPoint(aX, aY, PR_FALSE, aAccessible);
NS_IF_ADDREF(*aAccessible = GetChildAtPoint(aX, aY, eDirectChild));
return NS_OK;
}
// nsIAccessible getDeepestChildAtPoint(in long x, in long y)
@ -897,7 +888,8 @@ nsAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY,
if (IsDefunct())
return NS_ERROR_FAILURE;
return GetChildAtPoint(aX, aY, PR_TRUE, aAccessible);
NS_IF_ADDREF(*aAccessible = GetChildAtPoint(aX, aY, eDeepestChild));
return NS_OK;
}
void nsAccessible::GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame)
@ -2716,7 +2708,7 @@ nsAccessible::BindToParent(nsAccessible* aParent, PRUint32 aIndexInParent)
if (mParent) {
if (mParent != aParent) {
NS_ERROR("Adopting child!");
mParent->InvalidateChildren();
mParent->RemoveChild(this);
} else {
NS_ERROR("Binding to the same parent!");
return;
@ -3228,15 +3220,37 @@ nsAccessible::GetSiblingAtOffset(PRInt32 aOffset, nsresult* aError)
nsAccessible *
nsAccessible::GetFirstAvailableAccessible(nsINode *aStartNode) const
{
nsAccessible *accessible =
nsAccessible* accessible =
GetAccService()->GetAccessibleInWeakShell(aStartNode, mWeakShell);
if (accessible)
return accessible;
nsIContent *content = nsCoreUtils::GetRoleContent(aStartNode);
nsAccTreeWalker walker(mWeakShell, content, PR_FALSE);
nsRefPtr<nsAccessible> childAccessible = walker.GetNextChild();
return childAccessible;
nsCOMPtr<nsIDOMDocumentTraversal> trav =
do_QueryInterface(aStartNode->GetOwnerDoc());
NS_ENSURE_TRUE(trav, nsnull);
nsCOMPtr<nsIDOMNode> currentNode = do_QueryInterface(aStartNode);
nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(GetNode()));
nsCOMPtr<nsIDOMTreeWalker> walker;
trav->CreateTreeWalker(rootNode,
nsIDOMNodeFilter::SHOW_ELEMENT | nsIDOMNodeFilter::SHOW_TEXT,
nsnull, PR_FALSE, getter_AddRefs(walker));
NS_ENSURE_TRUE(walker, nsnull);
walker->SetCurrentNode(currentNode);
while (true) {
walker->NextNode(getter_AddRefs(currentNode));
if (!currentNode)
return nsnull;
nsCOMPtr<nsINode> node(do_QueryInterface(currentNode));
nsAccessible* accessible =
GetAccService()->GetAccessibleInWeakShell(node, mWeakShell);
if (accessible)
return accessible;
}
return nsnull;
}
PRBool nsAccessible::CheckVisibilityInParentChain(nsIDocument* aDocument, nsIView* aView)

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

@ -58,6 +58,7 @@ class AccGroupInfo;
class EmbeddedObjCollector;
class nsAccessible;
class nsHyperTextAccessible;
class nsHTMLLIAccessible;
struct nsRoleMapEntry;
class nsTextAccessible;
@ -188,17 +189,24 @@ public:
*/
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
/**
* Used by GetChildAtPoint() method to get direct or deepest child at point.
*/
enum EWhichChildAtPoint {
eDirectChild,
eDeepestChild
};
/**
* Return direct or deepest child at the given point.
*
* @param aX [in] x coordinate relative screen
* @param aY [in] y coordinate relative screen
* @param aDeepestChild [in] flag points if deep child should be returned
* @param aChild [out] found child
* @param aX [in] x coordinate relative screen
* @param aY [in] y coordinate relative screen
* @param aWhichChild [in] flag points if deepest or direct child
* should be returned
*/
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild);
virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
/**
* Return calculated group level based on accessible hierarchy.
@ -364,6 +372,9 @@ public:
inline bool IsHyperText() const { return mFlags & eHyperTextAccessible; }
nsHyperTextAccessible* AsHyperText();
inline bool IsHTMLListItem() const { return mFlags & eHTMLListItemAccessible; }
nsHTMLLIAccessible* AsHTMLListItem();
inline bool IsRoot() const { return mFlags & eRootAccessible; }
nsRootAccessible* AsRoot();
@ -512,8 +523,9 @@ protected:
enum AccessibleTypes {
eApplicationAccessible = 1 << 2,
eHyperTextAccessible = 1 << 3,
eRootAccessible = 1 << 4,
eTextLeafAccessible = 1 << 5
eHTMLListItemAccessible = 1 << 4,
eRootAccessible = 1 << 5,
eTextLeafAccessible = 1 << 6
};
//////////////////////////////////////////////////////////////////////////////

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

@ -170,22 +170,11 @@ nsApplicationAccessible::GroupPosition(PRInt32 *aGroupLevel,
return NS_OK;
}
NS_IMETHODIMP
nsAccessible*
nsApplicationAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aChild)
EWhichChildAtPoint aWhichChild)
{
NS_ENSURE_ARG_POINTER(aChild);
*aChild = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsApplicationAccessible::GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY,
nsIAccessible **aChild)
{
NS_ENSURE_ARG_POINTER(aChild);
*aChild = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
return nsnull;
}
NS_IMETHODIMP

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

@ -98,8 +98,6 @@ public:
NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes);
NS_IMETHOD GroupPosition(PRInt32 *aGroupLevel, PRInt32 *aSimilarItemsInGroup,
PRInt32 *aPositionInGroup);
NS_IMETHOD GetChildAtPoint(PRInt32 aX, PRInt32 aY, nsIAccessible **aChild);
NS_IMETHOD GetDeepestChildAtPoint(PRInt32 aX, PRInt32 aY, nsIAccessible **aChild);
NS_IMETHOD GetRelationByType(PRUint32 aRelationType,
nsIAccessibleRelation **aRelation);
NS_IMETHOD GetRelationsCount(PRUint32 *aRelationsCount);
@ -128,6 +126,8 @@ public:
virtual nsresult GetARIAState(PRUint32 *aState, PRUint32 *aExtraState);
virtual PRUint32 NativeRole();
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
virtual void InvalidateChildren();

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

@ -67,14 +67,12 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsLeafAccessible, nsAccessible)
////////////////////////////////////////////////////////////////////////////////
// nsLeafAccessible: nsAccessible public
nsresult
nsAccessible*
nsLeafAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild)
EWhichChildAtPoint aWhichChild)
{
// Don't walk into leaf accessibles.
NS_ADDREF(*aChild = this);
return NS_OK;
return this;
}
////////////////////////////////////////////////////////////////////////////////

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

@ -63,9 +63,8 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// nsAccessible
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild);
virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
protected:

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

@ -650,6 +650,11 @@ nsDocAccessible::Shutdown()
RemoveEventListeners();
// Mark the document as shutdown before AT is notified about the document
// removal from its container (valid for root documents on ATK).
nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
mDocument = nsnull;
if (mParent) {
nsDocAccessible* parentDocument = mParent->GetDocAccessible();
if (parentDocument)
@ -672,9 +677,6 @@ nsDocAccessible::Shutdown()
mNodeToAccessibleMap.Clear();
ClearCache(mAccessibleCache);
nsCOMPtr<nsIDocument> kungFuDeathGripDoc = mDocument;
mDocument = nsnull;
nsHyperTextAccessibleWrap::Shutdown();
GetAccService()->NotifyOfDocumentShutdown(kungFuDeathGripDoc);
@ -1229,19 +1231,17 @@ void nsDocAccessible::ContentAppended(nsIDocument *aDocument,
{
}
void nsDocAccessible::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsEventStates aStateMask)
void nsDocAccessible::ContentStateChanged(nsIDocument* aDocument,
nsIContent* aContent,
nsEventStates aStateMask)
{
if (aStateMask.HasState(NS_EVENT_STATE_CHECKED)) {
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent1);
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent2);
nsHTMLSelectOptionAccessible::SelectionChangedIfOption(aContent);
}
if (aStateMask.HasState(NS_EVENT_STATE_INVALID)) {
nsRefPtr<AccEvent> event =
new AccStateChangeEvent(aContent1, nsIAccessibleStates::STATE_INVALID,
new AccStateChangeEvent(aContent, nsIAccessibleStates::STATE_INVALID,
PR_FALSE, PR_TRUE);
FireDelayedAccessibleEvent(event);
}
@ -1472,7 +1472,10 @@ nsDocAccessible::NotifyOfCachingEnd(nsAccessible* aAccessible)
// Make sure we keep children updated. While we're inside of caching
// loop then we must exist it with cached children.
nsAccessible* container = GetContainerAccessible(content);
container->UpdateChildren();
NS_ASSERTION(container,
"Got a referenced element that is not in document!");
if (container)
container->UpdateChildren();
}
}
mInvalidationList.Clear();
@ -1950,8 +1953,9 @@ nsDocAccessible::CacheChildrenInSubtree(nsAccessible* aRoot)
PRUint32 count = aRoot->GetChildCount();
for (PRUint32 idx = 0; idx < count; idx++) {
nsAccessible* child = aRoot->GetChildAt(idx);
NS_ASSERTION(child, "Illicit tree change while tree is created!");
// Don't cross document boundaries.
if (child->IsContent())
if (child && child->IsContent())
CacheChildrenInSubtree(child);
}
}

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

@ -76,32 +76,25 @@ nsOuterDocAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
return NS_OK;
}
nsresult
nsAccessible*
nsOuterDocAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild)
EWhichChildAtPoint aWhichChild)
{
PRInt32 docX = 0, docY = 0, docWidth = 0, docHeight = 0;
nsresult rv = GetBounds(&docX, &docY, &docWidth, &docHeight);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, nsnull);
if (aX < docX || aX >= docX + docWidth || aY < docY || aY >= docY + docHeight)
return NS_OK;
return nsnull;
// Always return the inner doc as direct child accessible unless bounds
// outside of it.
nsCOMPtr<nsIAccessible> childAcc;
rv = GetFirstChild(getter_AddRefs(childAcc));
NS_ENSURE_SUCCESS(rv, rv);
nsAccessible* child = GetChildAt(0);
NS_ENSURE_TRUE(child, nsnull);
if (!childAcc)
return NS_OK;
if (aDeepestChild)
return childAcc->GetDeepestChildAtPoint(aX, aY, aChild);
NS_ADDREF(*aChild = childAcc);
return NS_OK;
if (aWhichChild = eDeepestChild)
return child->GetChildAtPoint(aX, aY, eDeepestChild);
return child;
}
nsresult

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

@ -70,9 +70,8 @@ public:
virtual PRUint32 NativeRole();
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes);
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild);
virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
virtual void InvalidateChildren();
virtual PRBool AppendChild(nsAccessible *aAccessible);

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

@ -246,14 +246,12 @@ nsHTMLAreaAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
return nsHTMLLinkAccessible::GetStateInternal(aState, aExtraState);
}
nsresult
nsAccessible*
nsHTMLAreaAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild)
EWhichChildAtPoint aWhichChild)
{
// Don't walk into area accessibles.
NS_ADDREF(*aChild = this);
return NS_OK;
return this;
}
////////////////////////////////////////////////////////////////////////////////

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

@ -94,9 +94,8 @@ public:
// nsAccessible
virtual nsresult GetNameInternal(nsAString& aName);
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild);
virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
// HyperLinkAccessible
virtual PRUint32 StartOffset();

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

@ -254,12 +254,15 @@ nsHTMLOutputAccessible::GetAttributesInternal(nsIPersistentProperties* aAttribut
nsHTMLLIAccessible::
nsHTMLLIAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
nsHyperTextAccessibleWrap(aContent, aShell)
nsHyperTextAccessibleWrap(aContent, aShell), mBullet(nsnull)
{
mFlags |= eHTMLListItemAccessible;
nsBlockFrame* blockFrame = do_QueryFrame(GetFrame());
if (blockFrame && !blockFrame->BulletIsEmptyExternal()) {
mBulletAccessible = new nsHTMLListBulletAccessible(mContent, mWeakShell);
GetDocAccessible()->BindToDocument(mBulletAccessible, nsnull);
if (blockFrame && blockFrame->HasBullet()) {
mBullet = new nsHTMLListBulletAccessible(mContent, mWeakShell);
if (!GetDocAccessible()->BindToDocument(mBullet, nsnull))
mBullet = nsnull;
}
}
@ -268,13 +271,9 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLIAccessible, nsHyperTextAccessible)
void
nsHTMLLIAccessible::Shutdown()
{
if (mBulletAccessible) {
// Ensure that pointer to this is nulled out.
mBulletAccessible->Shutdown();
}
mBullet = nsnull;
nsHyperTextAccessibleWrap::Shutdown();
mBulletAccessible = nsnull;
}
PRUint32
@ -297,12 +296,11 @@ nsHTMLLIAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
NS_IMETHODIMP nsHTMLLIAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
{
nsresult rv = nsAccessibleWrap::GetBounds(x, y, width, height);
if (NS_FAILED(rv) || !mBulletAccessible) {
if (NS_FAILED(rv) || !mBullet)
return rv;
}
PRInt32 bulletX, bulletY, bulletWidth, bulletHeight;
rv = mBulletAccessible->GetBounds(&bulletX, &bulletY, &bulletWidth, &bulletHeight);
rv = mBullet->GetBounds(&bulletX, &bulletY, &bulletWidth, &bulletHeight);
NS_ENSURE_SUCCESS(rv, rv);
*x = bulletX; // Move x coordinate of list item over to cover bullet as well
@ -310,14 +308,41 @@ NS_IMETHODIMP nsHTMLLIAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *wid
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLLIAccessible: public
void
nsHTMLLIAccessible::UpdateBullet(bool aHasBullet)
{
if (aHasBullet == !!mBullet) {
NS_NOTREACHED("Bullet and accessible are in sync already!");
return;
}
nsDocAccessible* document = GetDocAccessible();
if (aHasBullet) {
mBullet = new nsHTMLListBulletAccessible(mContent, mWeakShell);
if (document->BindToDocument(mBullet, nsnull)) {
InsertChildAt(0, mBullet);
}
} else {
RemoveChild(mBullet);
document->UnbindFromDocument(mBullet);
mBullet = nsnull;
}
// XXXtodo: fire show/hide and reorder events. That's hard to make it
// right now because coalescence happens by DOM node.
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLLIAccessible: nsAccessible protected
void
nsHTMLLIAccessible::CacheChildren()
{
if (mBulletAccessible)
AppendChild(mBulletAccessible);
if (mBullet)
AppendChild(mBullet);
// Cache children from subtree.
nsAccessibleWrap::CacheChildren();
@ -331,19 +356,11 @@ nsHTMLListBulletAccessible::
nsHTMLListBulletAccessible(nsIContent* aContent, nsIWeakReference* aShell) :
nsLeafAccessible(aContent, aShell)
{
mBulletText += ' '; // Otherwise bullets are jammed up against list text
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLListBulletAccessible: nsAccessNode
void
nsHTMLListBulletAccessible::Shutdown()
{
mBulletText.Truncate();
nsLeafAccessible::Shutdown();
}
bool
nsHTMLListBulletAccessible::IsPrimaryForNode() const
{
@ -363,6 +380,7 @@ nsHTMLListBulletAccessible::GetName(nsAString &aName)
// Native anonymous content, ARIA can't be used. Get list bullet text.
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
NS_ASSERTION(blockFrame, "No frame for list item!");
if (blockFrame) {
blockFrame->GetBulletText(aName);
@ -394,17 +412,13 @@ void
nsHTMLListBulletAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
PRUint32 aLength)
{
nsAutoString bulletText;
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
if (blockFrame) {
nsAutoString bulletText;
NS_ASSERTION(blockFrame, "No frame for list item!");
if (blockFrame)
blockFrame->GetBulletText(bulletText);
PRUint32 maxLength = bulletText.Length() - aStartOffset;
if (aLength > maxLength)
aLength = maxLength;
aText += Substring(bulletText, aStartOffset, aLength);
}
aText.Append(Substring(bulletText, aStartOffset, aLength));
}
////////////////////////////////////////////////////////////////////////////////

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

@ -136,7 +136,6 @@ public:
NS_IMETHOD GetName(nsAString& aName);
// nsAccessNode
virtual void Shutdown();
virtual bool IsPrimaryForNode() const;
// nsAccessible
@ -144,15 +143,6 @@ public:
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0,
PRUint32 aLength = PR_UINT32_MAX);
protected:
// XXX: Ideally we'd get the bullet text directly from the bullet frame via
// nsBulletFrame::GetListItemText(), but we'd need an interface for getting
// text from contentless anonymous frames. Perhaps something like
// nsIAnonymousFrame::GetText() ? However, in practice storing the bullet text
// here should not be a problem if we invalidate the right parts of
// the accessibility cache when mutation events occur.
nsString mBulletText;
};
/**
@ -182,22 +172,32 @@ public:
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsIAccessible
NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
// nsAccessNode
virtual void Shutdown();
// nsIAccessible
NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
// nsAccessible
virtual PRUint32 NativeRole();
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
// nsHTMLLIAccessible
void UpdateBullet(bool aHasBullet);
protected:
// nsAccessible
virtual void CacheChildren();
private:
nsRefPtr<nsHTMLListBulletAccessible> mBulletAccessible;
nsRefPtr<nsHTMLListBulletAccessible> mBullet;
};
#endif
inline nsHTMLLIAccessible*
nsAccessible::AsHTMLListItem()
{
return mFlags & eHTMLListItemAccessible ?
static_cast<nsHTMLLIAccessible*>(this) : nsnull;
}
#endif

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

@ -195,11 +195,8 @@ nsHyperTextAccessible::GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState)
*aState |= nsIAccessibleStates::STATE_READONLY;
}
PRInt32 childCount;
GetChildCount(&childCount);
if (childCount > 0) {
if (GetChildCount() > 0)
*aExtraState |= nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT;
}
return NS_OK;
}

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

@ -308,7 +308,7 @@ STDMETHODIMP nsAccessNodeWrap::get_attributesForNames(
/* [length_is][size_is][retval] */ BSTR __RPC_FAR *aAttribValues)
{
__try {
if (IsDefunct() || IsDocument())
if (IsDefunct() || !IsElement())
return E_FAIL;
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(mContent));
@ -616,12 +616,7 @@ void nsAccessNodeWrap::InitAccessibility()
DoATSpecificProcessing();
// Register window class that'll be used for document accessibles associated
// with tabs.
if (nsWinUtils::IsWindowEmulationEnabled()) {
nsWinUtils::RegisterNativeWindow(kClassNameTabContent);
sHWNDCache.Init(4);
}
nsWinUtils::MaybeStartWindowEmulation();
nsAccessNode::InitXPAccessibility();
}
@ -631,10 +626,7 @@ void nsAccessNodeWrap::ShutdownAccessibility()
NS_IF_RELEASE(gTextEvent);
::DestroyCaret();
// Unregister window call that's used for document accessibles associated
// with tabs.
if (nsWinUtils::IsWindowEmulationEnabled())
::UnregisterClassW(kClassNameTabContent, GetModuleHandle(NULL));
nsWinUtils::ShutdownWindowEmulation();
nsAccessNode::ShutdownXPAccessibility();
}

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

@ -203,7 +203,7 @@ __try {
// Return window system accessible object for root document and tab document
// accessibles.
if (!doc->ParentDocument() ||
nsWinUtils::IsWindowEmulationEnabled() &&
nsWinUtils::IsWindowEmulationStarted() &&
nsWinUtils::IsTabDocument(doc->GetDocumentNode())) {
HWND hwnd = static_cast<HWND>(doc->GetNativeWindow());
if (hwnd && SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_WINDOW,
@ -236,9 +236,7 @@ __try {
if (nsAccUtils::MustPrune(this))
return NS_OK;
PRInt32 numChildren;
GetChildCount(&numChildren);
*pcountChildren = numChildren;
*pcountChildren = GetChildCount();
} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
return S_OK;
@ -1014,9 +1012,7 @@ __try {
mEnumVARIANTPosition += aNumElements;
PRInt32 numChildren;
GetChildCount(&numChildren);
PRInt32 numChildren = GetChildCount();
if (mEnumVARIANTPosition > numChildren)
{
mEnumVARIANTPosition = numChildren;

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

@ -255,10 +255,11 @@ STDMETHODIMP nsDocAccessibleWrap::get_accValue(
void
nsDocAccessibleWrap::Shutdown()
{
if (nsWinUtils::IsWindowEmulationEnabled()) {
// Do window emulation specific shutdown if emulation was started.
if (nsWinUtils::IsWindowEmulationStarted()) {
// Destroy window created for root document.
if (nsWinUtils::IsTabDocument(mDocument)) {
nsAccessibleWrap::sHWNDCache.Remove(mHWND);
sHWNDCache.Remove(mHWND);
::DestroyWindow(static_cast<HWND>(mHWND));
}
@ -285,14 +286,14 @@ nsDocAccessibleWrap::NotifyOfInitialUpdate()
{
nsDocAccessible::NotifyOfInitialUpdate();
if (nsWinUtils::IsWindowEmulationEnabled()) {
if (nsWinUtils::IsWindowEmulationStarted()) {
// Create window for tab document.
if (nsWinUtils::IsTabDocument(mDocument)) {
nsRootAccessible* rootDocument = RootAccessible();
PRBool isActive = PR_TRUE;
PRInt32 x = CW_USEDEFAULT, y = CW_USEDEFAULT, width = 0, height = 0;
if (nsWinUtils::IsWindowEmulationEnabled(kDolphinModuleHandle)) {
if (nsWinUtils::IsWindowEmulationFor(kDolphinModuleHandle)) {
GetBounds(&x, &y, &width, &height);
PRInt32 rootX = 0, rootY = 0, rootWidth = 0, rootHeight = 0;
rootDocument->GetBounds(&rootX, &rootY, &rootWidth, &rootHeight);
@ -308,7 +309,7 @@ nsDocAccessibleWrap::NotifyOfInitialUpdate()
mHWND = nsWinUtils::CreateNativeWindow(kClassNameTabContent, parentWnd,
x, y, width, height, isActive);
nsAccessibleWrap::sHWNDCache.Put(mHWND, this);
sHWNDCache.Put(mHWND, this);
} else {
nsDocAccessible* parentDocument = ParentDocument();

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

@ -63,7 +63,7 @@ nsRootAccessibleWrap::~nsRootAccessibleWrap()
void
nsRootAccessibleWrap::DocumentActivated(nsDocAccessible* aDocument)
{
if (nsWinUtils::IsWindowEmulationEnabled(kDolphinModuleHandle) &&
if (nsWinUtils::IsWindowEmulationFor(kDolphinModuleHandle) &&
nsWinUtils::IsTabDocument(aDocument->GetDocumentNode())) {
PRUint32 count = mChildDocuments.Length();
for (PRUint32 idx = 0; idx < count; idx++) {

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

@ -99,6 +99,34 @@ nsWinUtils::ConvertToIA2Array(nsIArray *aGeckoArray, IUnknown ***aIA2Array,
return S_OK;
}
bool
nsWinUtils::MaybeStartWindowEmulation()
{
// Register window class that'll be used for document accessibles associated
// with tabs.
if (IsWindowEmulationFor(0)) {
RegisterNativeWindow(kClassNameTabContent);
nsAccessNodeWrap::sHWNDCache.Init(4);
return true;
}
return false;
}
void
nsWinUtils::ShutdownWindowEmulation()
{
// Unregister window call that's used for document accessibles associated
// with tabs.
if (IsWindowEmulationFor(0))
::UnregisterClassW(kClassNameTabContent, GetModuleHandle(NULL));
}
bool
nsWinUtils::IsWindowEmulationStarted()
{
return nsAccessNodeWrap::sHWNDCache.IsInitialized();
}
void
nsWinUtils::RegisterNativeWindow(LPCWSTR aWindowClass)
{
@ -146,7 +174,7 @@ nsWinUtils::HideNativeWindow(HWND aWnd)
}
bool
nsWinUtils::IsWindowEmulationEnabled(LPCWSTR kModuleHandle)
nsWinUtils::IsWindowEmulationFor(LPCWSTR kModuleHandle)
{
return kModuleHandle ? ::GetModuleHandleW(kModuleHandle) :
::GetModuleHandleW(kJAWSModuleHandle) ||

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

@ -63,6 +63,21 @@ public:
static HRESULT ConvertToIA2Array(nsIArray *aCollection,
IUnknown ***aAccessibles, long *aCount);
/**
* Start window emulation if presence of specific AT is detected.
*/
static bool MaybeStartWindowEmulation();
/**
* Free resources used for window emulation.
*/
static void ShutdownWindowEmulation();
/**
* Return true if window emulation is started.
*/
static bool IsWindowEmulationStarted();
/**
* Helper to register window class.
*/
@ -88,7 +103,7 @@ public:
/**
* Return true if window emulation is enabled.
*/
static bool IsWindowEmulationEnabled(LPCWSTR kModuleHandle = 0);
static bool IsWindowEmulationFor(LPCWSTR kModuleHandle);
/**
* Return true if the given document node is for tab document accessible.

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

@ -228,20 +228,19 @@ nsXULTreeAccessible::GetFocusedChild(nsIAccessible **aFocusedChild)
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeAccessible: nsAccessible implementation (DON'T put methods here)
nsresult
nsAccessible*
nsXULTreeAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild)
EWhichChildAtPoint aWhichChild)
{
nsIFrame *frame = GetFrame();
if (!frame)
return NS_ERROR_FAILURE;
return nsnull;
nsPresContext *presContext = frame->PresContext();
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
nsIFrame *rootFrame = presShell->GetRootFrame();
NS_ENSURE_STATE(rootFrame);
NS_ENSURE_TRUE(rootFrame, nsnull);
nsIntRect rootRect = rootFrame->GetScreenRectExternal();
@ -257,10 +256,10 @@ nsXULTreeAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
// If we failed to find tree cell for the given point then it might be
// tree columns.
if (row == -1 || !column)
return nsAccessibleWrap::GetChildAtPoint(aX, aY, aDeepestChild, aChild);
return nsAccessibleWrap::GetChildAtPoint(aX, aY, aWhichChild);
nsAccessible *child = GetTreeItemAccessible(row);
if (aDeepestChild && child) {
if (aWhichChild == eDeepestChild && child) {
// Look for accessible cell for the found item accessible.
nsRefPtr<nsXULTreeItemAccessibleBase> treeitem = do_QueryObject(child);
@ -269,8 +268,7 @@ nsXULTreeAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
child = cell;
}
NS_IF_ADDREF(*aChild = child);
return NS_OK;
return child;
}
////////////////////////////////////////////////////////////////////////////////

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

@ -86,9 +86,8 @@ public:
// nsAccessible
virtual PRUint32 NativeRole();
virtual nsresult GetStateInternal(PRUint32 *aState, PRUint32 *aExtraState);
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild);
virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
virtual nsAccessible* GetChildAt(PRUint32 aIndex);
virtual PRInt32 GetChildCount();

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

@ -664,20 +664,19 @@ nsXULTreeGridRowAccessible::NativeRole()
return nsIAccessibleRole::ROLE_ROW;
}
nsresult
nsAccessible*
nsXULTreeGridRowAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild)
EWhichChildAtPoint aWhichChild)
{
nsIFrame *frame = GetFrame();
if (!frame)
return NS_ERROR_FAILURE;
return nsnull;
nsPresContext *presContext = frame->PresContext();
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
nsIFrame *rootFrame = presShell->GetRootFrame();
NS_ENSURE_STATE(rootFrame);
NS_ENSURE_TRUE(rootFrame, nsnull);
nsIntRect rootRect = rootFrame->GetScreenRectExternal();
@ -692,10 +691,9 @@ nsXULTreeGridRowAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
// Return if we failed to find tree cell in the row for the given point.
if (row != mRow || !column)
return NS_OK;
return nsnull;
NS_IF_ADDREF(*aChild = GetCellAccessible(column));
return NS_OK;
return GetCellAccessible(column);
}
nsAccessible*

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

@ -93,9 +93,8 @@ public:
// nsAccessible
virtual PRUint32 NativeRole();
virtual nsresult GetChildAtPoint(PRInt32 aX, PRInt32 aY,
PRBool aDeepestChild,
nsIAccessible **aChild);
virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
virtual nsAccessible* GetChildAt(PRUint32 aIndex);
virtual PRInt32 GetChildCount();

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

@ -64,6 +64,10 @@ const STATE_BUSY = nsIAccessibleStates.STATE_BUSY;
const kEmbedChar = String.fromCharCode(0xfffc);
const kDiscBulletText = String.fromCharCode(0x2022) + " ";
const kCircleBulletText = String.fromCharCode(0x25e6) + " ";
const kSquareBulletText = String.fromCharCode(0x25aa) + " ";
/**
* nsIAccessibleRetrieval, initialized when test is loaded.
*/

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

@ -54,6 +54,7 @@ _TEST_FILES =\
test_general.html \
test_general.xul \
test_link.html \
test_list.html \
test_markup.html \
test_nsRootAcc.xul \
markuprules.xml \

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

@ -0,0 +1,91 @@
<html>
<head>
<title>nsIAccessible::name calculation for HTML li</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../name.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
/**
* Alter list item numbering and change list style type.
*/
function bulletUpdate()
{
this.eventSeq = [
new invokerChecker(EVENT_REORDER, getNode("list"))
];
this.invoke = function bulletUpdate_invoke()
{
testName("li_end", "1. list end");
var li = document.createElement("li");
li.setAttribute("id", "li_start");
li.textContent = "list start";
getNode("list").insertBefore(li, getNode("li_end"));
}
this.finalCheck = function bulletUpdate_finalCheck()
{
testName("li_start", "1. list start");
testName("li_end", "2. list end");
// change list style type
var list = getNode("list");
list.setAttribute("style", "list-style-type: disc;");
getComputedStyle(list, "").color; // make style processing sync
testName("li_start", kDiscBulletText + "list start");
testName("li_end", kDiscBulletText + "list end");
}
this.getID = function bulletUpdate_getID()
{
return "Update bullet of list items";
}
}
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
gQueue.push(new bulletUpdate());
gQueue.invoke(); // SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=634200"
title="crash [@ nsIFrame::GetStyleVisibility() ]">
Mozilla Bug 634200
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<ol id="list">
<li id="li_end">list end</li>
</ol>
</body>
</html>

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

@ -5,6 +5,12 @@
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<style>
h6.gencontent:before {
content: "aga"
}
</style>
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
@ -40,6 +46,16 @@
testText(IDs, 10, 13, "e " + kEmbedChar);
testText(IDs, 0, 13, "hello " + kEmbedChar + " see " + kEmbedChar);
////////////////////////////////////////////////////////////////////////
// getTextAtOffset line boundary
testTextAtOffset(0, BOUNDARY_LINE_START, "line ", 0, 5,
"hypertext3", kOk, kOk, kOk);
// XXX: see bug 638684.
testTextAtOffset(0, BOUNDARY_LINE_START, "line ", 0, 5,
"hypertext4", kTodo, kOk, kTodo);
//////////////////////////////////////////////////////////////////////////
// list
//////////////////////////////////////////////////////////////////////////
@ -63,7 +79,14 @@
<a target="_blank"
title="Fix getText"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=630001">Mozilla Bug 630001, part3</a>
href="https://bugzilla.mozilla.org/show_bug.cgi?id=630001">
Bug 630001, part3
</a>
<a target="_blank"
title="getTextAtOffset line boundary may return more than one line"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=638326">
Bug 638326
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
@ -73,5 +96,17 @@
<div id="hypertext2">hello <a>friend</a> see <input></div>
<ol id="list"><li id="listitem">foo</li></ol>
<div id="hypertext3">line
<!-- haha -->
<!-- hahaha -->
<h6>heading</h6>
</div>
<div id="hypertext4">line
<!-- haha -->
<!-- hahaha -->
<h6 role="presentation" class="gencontent">heading</h6>
</div>
</body>
</html>

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

@ -40,17 +40,13 @@
function doTest()
{
const discBulletText = String.fromCharCode(0x2022) + " ";
const circleBulletText = String.fromCharCode(0x25e6) + " ";
const squareBulletText = String.fromCharCode(0x25aa) + " ";
// list1
var discAccTree = {
role: ROLE_LIST,
children: [
new listItemTree(discBulletText, "Oranges"),
new listItemTree(discBulletText, "Apples"),
new listItemTree(discBulletText, "Bananas")
new listItemTree(kDiscBulletText, "Oranges"),
new listItemTree(kDiscBulletText, "Apples"),
new listItemTree(kDiscBulletText, "Bananas")
]
};
@ -60,9 +56,9 @@
var circleAccTree = {
role: ROLE_LIST,
children: [
new listItemTree(circleBulletText, "Oranges"),
new listItemTree(circleBulletText, "Apples"),
new listItemTree(circleBulletText, "Bananas")
new listItemTree(kCircleBulletText, "Oranges"),
new listItemTree(kCircleBulletText, "Apples"),
new listItemTree(kCircleBulletText, "Bananas")
]
};
@ -72,9 +68,9 @@
var squareAccTree = {
role: ROLE_LIST,
children: [
new listItemTree(squareBulletText, "Oranges"),
new listItemTree(squareBulletText, "Apples"),
new listItemTree(squareBulletText, "Bananas")
new listItemTree(kSquareBulletText, "Oranges"),
new listItemTree(kSquareBulletText, "Apples"),
new listItemTree(kSquareBulletText, "Bananas")
]
};
@ -92,6 +88,43 @@
testAccessibleTree("list4", nestedAccTree);
// dl list
var tree =
{ LIST: [ // dl
{ LISTITEM: [ // dt
{ TEXT_LEAF: [] },
] },
{ PARAGRAPH: [ // dd
{ TEXT_LEAF: [] }
] },
{ LISTITEM: [ // dt
{ TEXT_LEAF: [] }
] },
{ PARAGRAPH: [ // dd
{ TEXT_LEAF: [] }
] }
] };
testAccessibleTree("list5", tree);
// dl list inside ordered list
tree =
{ LIST: [ // ol
{ LISTITEM: [ // li
{ STATICTEXT: [ ] },
{ LIST: [ // dl
{ LISTITEM: [ // dt
{ TEXT_LEAF: [] }
] },
{ PARAGRAPH: [ // dd
{ TEXT_LEAF: [] }
] }
] }
] }
] };
testAccessibleTree("list6", tree);
SimpleTest.finish();
}
@ -111,6 +144,11 @@
href="https://bugzilla.mozilla.org/show_bug.cgi?id=604587">
Mozilla Bug 604587
</a>
<a target="_blank"
title="Fix list bullets for DL list (crash [@ nsBulletFrame::GetListItemText])"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=629114">
Mozilla Bug 629114
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
@ -144,5 +182,18 @@
</ul>
</li>
</ol>
<dl id="list5">
<dt>item1</dt><dd>description</dd>
<dt>item2</td><dd>description</dd>
</dl>
<ol id="list6">
<li>
<dl id="dl">
<dt>item1</dt><dd>description</dd>
</dl>
</li>
</ol>
</body>
</html>

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

@ -48,8 +48,6 @@
#endif
#endif
pref("general.startup.browser", true);
pref("browser.chromeURL","chrome://browser/content/");
pref("browser.hiddenWindowChromeURL", "chrome://browser/content/hiddenWindow.xul");
@ -536,11 +534,6 @@ pref("mousewheel.withcontrolkey.action",3);
pref("mousewheel.withcontrolkey.sysnumlines",false);
pref("mousewheel.withcontrolkey.numlines",1);
pref("profile.allow_automigration", false); // setting to false bypasses automigration in the profile code
// Customizable toolbar stuff
pref("custtoolbar.personal_toolbar_folder", "");
// pref to control the alert notification
pref("alerts.slideIncrement", 1);
pref("alerts.slideIncrementTime", 10);

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

@ -5068,23 +5068,19 @@ var TabsInTitlebar = {
let titlebar = $("titlebar");
if (allowed) {
let availTop = screen.availTop;
function top(ele) ele.boxObject.screenY - availTop;
function bottom(ele) top(ele) + rect(ele).height;
function rect(ele) ele.getBoundingClientRect();
let tabsToolbar = $("TabsToolbar");
let appmenuButtonBox = $("appmenu-button-container");
let captionButtonsBox = $("titlebar-buttonbox");
this._sizePlaceholder("appmenu-button", rect(appmenuButtonBox).width);
this._sizePlaceholder("caption-buttons", rect(captionButtonsBox).width);
let maxMargin = top(gNavToolbox);
let tabsBottom = maxMargin + rect(tabsToolbar).height;
let titlebarBottom = Math.max(bottom(appmenuButtonBox), bottom(captionButtonsBox));
let distance = tabsBottom - titlebarBottom;
titlebar.style.marginBottom = - Math.min(distance, maxMargin) + "px";
let tabsToolbarRect = rect(tabsToolbar);
let titlebarTop = rect($("titlebar-content")).top;
titlebar.style.marginBottom = - Math.min(tabsToolbarRect.top - titlebarTop,
tabsToolbarRect.height) + "px";
docElement.setAttribute("tabsintitlebar", "true");

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

@ -84,6 +84,7 @@ function GroupItem(listOfEls, options) {
this.fadeAwayUndoButtonDuration = 300;
this.keepProportional = false;
this._frozenItemSizeData = {};
// Double click tracker
this._lastClick = 0;
@ -194,6 +195,7 @@ function GroupItem(listOfEls, options) {
gTabView.firstUseExperienced = true;
})
.focus(function() {
self._unfreezeItemSize();
if (!self._titleFocused) {
(self.$title)[0].select();
self._titleFocused = true;
@ -644,6 +646,9 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this.removeAll({dontClose: true});
GroupItems.unregister(this);
// remove unfreeze event handlers, if item size is frozen
this._unfreezeItemSize({dontArrange: true});
let self = this;
let destroyGroup = function () {
iQ(self.container).remove();
@ -677,6 +682,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// Closes the groupItem and all of its children.
closeAll: function GroupItem_closeAll() {
if (this._children.length > 0) {
this._unfreezeItemSize();
this._children.forEach(function(child) {
iQ(child.container).hide();
});
@ -878,8 +884,10 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
this.$undoContainer = iQ("<div/>")
.addClass("undo")
.attr("type", "button")
.text(tabviewString("groupItem.undoCloseGroup"))
.appendTo("body");
iQ("<span/>")
.text(tabviewString("groupItem.undoCloseGroup"))
.appendTo(this.$undoContainer);
let undoClose = iQ("<span/>")
.addClass("close")
.appendTo(this.$undoContainer);
@ -1007,8 +1015,13 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
item.groupItemData = {};
item.addSubscriber(this, "close", function() {
let count = self._children.length;
let dontArrange = self.expanded || !self.shouldStack(count);
let dontClose = !item.closedManually && gBrowser._numPinnedTabs > 0;
self.remove(item, { dontClose: dontClose });
self.remove(item, {dontArrange: dontArrange, dontClose: dontClose});
if (dontArrange)
self._freezeItemSize(count);
if (self._children.length > 0 && self._activeTab) {
GroupItems.setActiveGroupItem(self);
@ -1035,6 +1048,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
if (!options.dontArrange)
this.arrange({animate: !options.immediately});
this._unfreezeItemSize({dontArrange: true});
this._sendToSubscribers("childAdded",{ groupItemId: this.id, item: item });
UI.setReorderTabsOnHide(this);
@ -1105,8 +1119,10 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
let closed = options.dontClose ? false : this.closeIfEmpty();
if (closed)
this._makeClosestTabActive();
else if (!options.dontArrange)
else if (!options.dontArrange) {
this.arrange({animate: !options.immediately});
this._unfreezeItemSize({dontArrange: true});
}
this._sendToSubscribers("childRemoved",{ groupItemId: this.id, item: item });
} catch(e) {
@ -1237,6 +1253,66 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
return shouldStack;
},
// ----------
// Function: _freezeItemSize
// Freezes current item size (when removing a child).
//
// Parameters:
// itemCount - the number of children before the last one was removed
_freezeItemSize: function GroupItem__freezeItemSize(itemCount) {
let data = this._frozenItemSizeData;
if (!data.lastItemCount) {
let self = this;
data.lastItemCount = itemCount;
// unfreeze item size when tabview is hidden
data.onTabViewHidden = function () self._unfreezeItemSize();
window.addEventListener('tabviewhidden', data.onTabViewHidden, false);
// we don't need to observe mouse movement when expanded because the
// tray is closed when we leave it and collapse causes unfreezing
if (self.expanded)
return;
// unfreeze item size when cursor is moved out of group bounds
data.onMouseMove = function (e) {
let cursor = new Point(e.pageX, e.pageY);
if (!self.bounds.contains(cursor))
self._unfreezeItemSize();
}
iQ(window).mousemove(data.onMouseMove);
}
this.arrange({animate: true, count: data.lastItemCount});
},
// ----------
// Function: _unfreezeItemSize
// Unfreezes and updates item size.
//
// Parameters:
// options - various options (see below)
//
// Possible options:
// dontArrange - do not arrange items when unfreezing
_unfreezeItemSize: function GroupItem__unfreezeItemSize(options) {
let data = this._frozenItemSizeData;
if (!data.lastItemCount)
return;
if (!options || !options.dontArrange)
this.arrange({animate: true});
// unbind event listeners
window.removeEventListener('tabviewhidden', data.onTabViewHidden, false);
if (data.onMouseMove)
iQ(window).unbind('mousemove', data.onMouseMove);
// reset freeze status
this._frozenItemSizeData = {};
},
// ----------
// Function: arrange
// Lays out all of the children.
@ -1561,6 +1637,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
});
this.arrange({z: z + 2});
this._unfreezeItemSize({dontArrange: true});
}
},
@ -1688,8 +1765,11 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// Function: setResizable
// Sets whether the groupItem is resizable and updates the UI accordingly.
setResizable: function GroupItem_setResizable(value, immediately) {
var self = this;
this.resizeOptions.minWidth = GroupItems.minGroupWidth;
this.resizeOptions.minHeight = GroupItems.minGroupHeight;
this.resizeOptions.start = function () self._unfreezeItemSize();
if (value) {
immediately ? this.$resizer.show() : this.$resizer.fadeIn();

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

@ -23,6 +23,7 @@
* Aza Raskin <aza@mozilla.com>
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
* Sean Dunn <seanedunn@yahoo.com>
* Tim Taubert <tim.taubert@gmx.de>
*
* 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
@ -169,8 +170,10 @@ Item.prototype = {
this.dragOptions = {
cancelClass: 'close stackExpander',
start: function(e, ui) {
if (this.isAGroupItem)
if (this.isAGroupItem) {
GroupItems.setActiveGroupItem(this);
this._unfreezeItemSize();
}
// if we start dragging a tab within a group, start with dropSpace on.
else if (this.parent != null)
this.parent._dropSpaceActive = true;
@ -598,6 +601,35 @@ Item.prototype = {
var droppables;
var dropTarget;
// determine the best drop target based on the current mouse coordinates
let determineBestDropTarget = function (e, box) {
// drop events
var best = {
dropTarget: null,
score: 0
};
droppables.forEach(function(droppable) {
var intersection = box.intersection(droppable.bounds);
if (intersection && intersection.area() > best.score) {
var possibleDropTarget = droppable.item;
var accept = true;
if (possibleDropTarget != dropTarget) {
var dropOptions = possibleDropTarget.dropOptions;
if (dropOptions && typeof dropOptions.accept == "function")
accept = dropOptions.accept.apply(possibleDropTarget, [self]);
}
if (accept) {
best.dropTarget = possibleDropTarget;
best.score = intersection.area();
}
}
});
return best.dropTarget;
}
// ___ mousemove
var handleMouseMove = function(e) {
// global drag tracking
@ -624,31 +656,9 @@ Item.prototype = {
if (typeof self.dragOptions.drag == "function")
self.dragOptions.drag.apply(self, [e]);
// drop events
var best = {
dropTarget: null,
score: 0
};
let bestDropTarget = determineBestDropTarget(e, box);
droppables.forEach(function(droppable) {
var intersection = box.intersection(droppable.bounds);
if (intersection && intersection.area() > best.score) {
var possibleDropTarget = droppable.item;
var accept = true;
if (possibleDropTarget != dropTarget) {
var dropOptions = possibleDropTarget.dropOptions;
if (dropOptions && typeof dropOptions.accept == "function")
accept = dropOptions.accept.apply(possibleDropTarget, [self]);
}
if (accept) {
best.dropTarget = possibleDropTarget;
best.score = intersection.area();
}
}
});
if (best.dropTarget != dropTarget) {
if (bestDropTarget != dropTarget) {
var dropOptions;
if (dropTarget) {
dropOptions = dropTarget.dropOptions;
@ -656,7 +666,7 @@ Item.prototype = {
dropOptions.out.apply(dropTarget, [e]);
}
dropTarget = best.dropTarget;
dropTarget = bestDropTarget;
if (dropTarget) {
dropOptions = dropTarget.dropOptions;
@ -710,10 +720,10 @@ Item.prototype = {
}
startMouse = new Point(e.pageX, e.pageY);
startPos = self.getBounds().position();
let bounds = self.getBounds();
startPos = bounds.position();
startEvent = e;
startSent = false;
dropTarget = null;
droppables = [];
iQ('.iq-droppable').each(function(elem) {
@ -726,6 +736,8 @@ Item.prototype = {
}
});
dropTarget = determineBestDropTarget(e, bounds);
iQ(gWindow)
.mousemove(handleMouseMove)
.mouseup(handleMouseUp);

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

@ -21,6 +21,7 @@
* Aza Raskin <aza@mozilla.com>
* Ian Gilman <ian@iangilman.com>
* Michael Yoshitaka Erlewine <mitcho@mitcho.com>
* Tim Taubert <tim.taubert@gmx.de>
*
* This file incorporates work from:
* jQuery JavaScript Library v1.4.2: http://code.jquery.com/jquery-1.4.2.js
@ -170,16 +171,22 @@ Rect.prototype = {
// ----------
// Function: contains
// Returns a boolean denoting if the given <Rect> is contained within
// Returns a boolean denoting if the <Rect> or <Point> is contained inside
// this rectangle.
//
// Paramaters
// - A <Rect>
contains: function Rect_contains(rect) {
return (rect.left >= this.left &&
rect.right <= this.right &&
rect.top >= this.top &&
rect.bottom <= this.bottom);
// Parameters
// - A <Rect> or a <Point>
contains: function Rect_contains(a) {
if (Utils.isPoint(a))
return (a.x > this.left &&
a.x < this.right &&
a.y > this.top &&
a.y < this.bottom);
return (a.left >= this.left &&
a.right <= this.right &&
a.top >= this.top &&
a.bottom <= this.bottom);
},
// ----------

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

@ -721,6 +721,7 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
complete();
};
UI.setActiveTab(this);
TabItems._update(this.tab, {force: true});
$tab.addClass("front");

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

@ -112,11 +112,6 @@ body {
position: absolute;
}
.undo .close {
display: inline-block;
position: relative;
}
.info-item {
position: absolute;
}

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

@ -4,7 +4,7 @@ function test() {
waitForExplicitFinish();
is(getTopWin(), window, "got top window");
is(getBoolPref("general.startup.browser", false), true, "getBoolPref");
is(getBoolPref("browser.search.openintab", false), false, "getBoolPref");
is(getBoolPref("this.pref.doesnt.exist", true), true, "getBoolPref fallback");
is(getBoolPref("this.pref.doesnt.exist", false), false, "getBoolPref fallback #2");

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

@ -85,6 +85,7 @@ _BROWSER_FILES = \
browser_tabview_bug608184.js \
browser_tabview_bug608158.js \
browser_tabview_bug608405.js \
browser_tabview_bug610208.js \
browser_tabview_bug610242.js \
browser_tabview_bug612470.js \
browser_tabview_bug613541.js \

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

@ -4,10 +4,12 @@
function test() {
waitForExplicitFinish();
newWindowWithTabView(onTabViewShown);
newWindowWithTabView(part1);
}
function onTabViewShown(win) {
function part1(win) {
registerCleanupFunction(function() win.close());
let contentWindow = win.document.getElementById("tab-view").contentWindow;
is(contentWindow.GroupItems.groupItems.length, 1, "Has only one group");
@ -52,8 +54,32 @@ function onTabViewShown(win) {
checkActive(function() {
checkActive(function() {
win.close();
finish();
newWindowWithTabView(part2);
});
}, 490);
}, 10)
}
function part2(win) {
registerCleanupFunction(function() win.close());
let newTab = win.gBrowser.loadOneTab("about:blank", {inBackground: true});
hideTabView(function() {
let selectedTab = win.gBrowser.selectedTab;
isnot(selectedTab, newTab, "They are different tabs");
// switch the selected tab to new tab
win.gBrowser.selectedTab = newTab;
win.addEventListener("tabviewhidden", function () {
win.removeEventListener("tabviewhidden", arguments.callee, false);
is(win.gBrowser.selectedTab, newTab, "The seleted tab should be the same as before (new tab)");
win.close();
finish();
}, false);
// show tabview
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
// hide tabview
EventUtils.synthesizeKey("e", { accelKey: true, shiftKey: true }, win);
})
}

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

@ -15,8 +15,8 @@ function test() {
}
let testVeryQuickDragAndDrop = function () {
let sourceGroup = cw.GroupItems.groupItems[0];
let targetGroup = createGroupItem();
let sourceGroup = createGroupItem();
let targetGroup = cw.GroupItems.groupItems[0];
sourceGroup.pushAway(true);
targetGroup.pushAway(true);

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

@ -0,0 +1,231 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
let cw;
let win;
let groupItem;
let next = function () {
let test = tests.shift();
if (test) {
test();
return;
}
win.close();
finish();
}
let prepareTest = function (testName) {
let originalBounds = groupItem.getChild(0).getBounds();
let tabItem = groupItem.getChild(1);
let bounds = tabItem.getBounds();
tabItem.close();
ok(originalBounds.equals(groupItem.getChild(0).getBounds()), testName + ': tabs did not change their size');
ok(bounds.equals(groupItem.getChild(1).getBounds()), testName + ': third tab is now on second tab\'s previous position');
return originalBounds;
}
let cleanUpTest = function (testName, originalBounds, callback) {
// Use setTimeout here because the groupItem.arrange() call uses
// animation to re-arrange the tabItems.
win.setTimeout(function () {
ok(!originalBounds.equals(groupItem.getChild(0).getBounds()), testName + ': tabs changed their size');
// cleanup
cw.GroupItems.setActiveGroupItem(groupItem);
win.gBrowser.loadOneTab('about:blank', {inBackground: true});
afterAllTabsLoaded(callback, win);
}, 500);
}
let tests = [];
// focus group title's input field to cause item arrange
let testFocusTitle = function () {
let originalBounds = prepareTest('testFocusTitle');
let target = groupItem.$titleShield[0];
EventUtils.synthesizeMouseAtCenter(target, {}, cw);
cleanUpTest('testFocusTitle', originalBounds, next);
}
// hide tabview to cause item arrange
let testHideTabView = function () {
let originalBounds = prepareTest('testHideTabView');
hideTabView(function () {
cleanUpTest('testHideTabView', originalBounds, function () {
showTabView(next, win);
});
}, win);
}
// (undo) close a group to cause item arrange
let testCloseGroupUndo = function () {
let originalBounds = prepareTest('testCloseGroupUndo');
hideGroupItem(groupItem, function () {
unhideGroupItem(groupItem, function () {
cleanUpTest('testCloseGroupUndo', originalBounds, next);
});
});
}
// leave the group's container with the mouse to cause item arrange
let testMouseOut = function () {
let originalBounds = prepareTest('testMouseOut');
let doc = cw.document.documentElement;
let bounds = groupItem.getBounds();
EventUtils.synthesizeMouse(doc, bounds.right - 5, bounds.bottom - 5, {type: 'mousemove'}, cw);
ok(originalBounds.equals(groupItem.getChild(0).getBounds()), 'testMouseOut: tabs did not change their size');
EventUtils.synthesizeMouse(doc, bounds.right + 1, bounds.bottom + 1, {type: 'mousemove'}, cw);
cleanUpTest('testMouseOut', originalBounds, next);
}
// sort item (drag it around) in its group to cause item arrange
let testSortInGroup = function () {
let originalBounds = prepareTest('testSortInGroup');
let target = groupItem.getChild(0).container;
// simulate drag/drop sorting
EventUtils.synthesizeMouse(target, 20, 20, {type: 'mousedown'}, cw);
EventUtils.synthesizeMouse(target, 40, 20, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouse(target, 20, 20, {type: 'mouseup'}, cw);
cleanUpTest('testSortInGroup', originalBounds, next);
}
// arrange items when the containing group is resized
let testResizeGroup = function () {
let originalBounds = prepareTest('testResizeGroup');
let oldBounds = groupItem.getBounds();
let resizer = groupItem.$resizer[0];
// simulate drag/drop resizing
EventUtils.synthesizeMouse(resizer, 5, 5, {type: 'mousedown'}, cw);
EventUtils.synthesizeMouse(resizer, 40, 20, {type: 'mousemove'}, cw);
EventUtils.synthesizeMouse(resizer, 20, 20, {type: 'mouseup'}, cw);
// reset group size
groupItem.setBounds(oldBounds);
groupItem.setUserSize();
cleanUpTest('testResizeGroup', originalBounds, next);
}
// make sure we don't freeze item size when removing an item from a stack
let testRemoveWhileStacked = function () {
let oldBounds = groupItem.getBounds();
groupItem.setSize(150, 200, true);
groupItem.setUserSize();
let originalBounds = groupItem.getChild(0).getBounds();
ok(!groupItem._isStacked, 'testRemoveWhileStacked: group is not stacked');
// add a new tab to let the group stack
win.gBrowser.loadOneTab('about:blank', {inBackground: true});
ok(groupItem._isStacked, 'testRemoveWhileStacked: group is now stacked');
afterAllTabsLoaded(function () {
groupItem.getChild(0).close();
let bounds = groupItem.getChild(0).getBounds();
ok(originalBounds.equals(bounds), 'testRemoveWhileStacked: tabs did not change their size');
// reset group size
groupItem.setBounds(oldBounds);
groupItem.setUserSize();
next();
}, win);
}
// 1) make sure item size is frozen when removing an item in expanded mode
// 2) make sure item size stays frozen while moving the mouse in the expanded
// layer
let testExpandedMode = function () {
let oldBounds = groupItem.getBounds();
groupItem.setSize(100, 100, true);
groupItem.setUserSize();
ok(groupItem._isStacked, 'testExpandedMode: group is stacked');
groupItem.addSubscriber(groupItem, 'expanded', function () {
groupItem.removeSubscriber(groupItem, 'expanded');
onExpanded();
});
groupItem.addSubscriber(groupItem, 'collapsed', function () {
groupItem.removeSubscriber(groupItem, 'collapsed');
onCollapsed();
});
let onExpanded = function () {
let originalBounds = groupItem.getChild(0).getBounds();
let tabItem = groupItem.getChild(1);
let bounds = tabItem.getBounds();
for (let i=0; i<3; i++)
groupItem.getChild(1).close();
ok(originalBounds.equals(groupItem.getChild(0).getBounds()), 'testExpandedMode: tabs did not change their size');
// move the mouse over the expanded layer
let trayBounds = groupItem.expanded.bounds;
let target = groupItem.expanded.$tray[0];
EventUtils.synthesizeMouse(target, trayBounds.right - 5, trayBounds.bottom -5, {type: 'mousemove'}, cw);
ok(originalBounds.equals(groupItem.getChild(0).getBounds()), 'testExpandedMode: tabs did not change their size');
groupItem.collapse();
}
let onCollapsed = function () {
// reset group size
groupItem.setBounds(oldBounds);
groupItem.setUserSize();
next();
}
groupItem.expand();
}
tests.push(testFocusTitle);
tests.push(testHideTabView);
tests.push(testCloseGroupUndo);
tests.push(testMouseOut);
tests.push(testSortInGroup);
tests.push(testResizeGroup);
tests.push(testRemoveWhileStacked);
tests.push(testExpandedMode);
waitForExplicitFinish();
newWindowWithTabView(function (tvwin) {
win = tvwin;
registerCleanupFunction(function () {
if (!win.closed)
win.close();
});
cw = win.TabView.getContentWindow();
groupItem = cw.GroupItems.groupItems[0];
groupItem.setSize(400, 200, true);
groupItem.setUserSize();
for (let i=0; i<3; i++)
win.gBrowser.loadOneTab('about:blank', {inBackground: true});
afterAllTabsLoaded(next, win);
});
}

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

@ -127,9 +127,6 @@
<preference id="security.disable_button.openDeviceManager"
name="security.disable_button.openDeviceManager"
type="bool"/>
<preference id="privacy.donottrackheader.enabled"
name="privacy.donottrackheader.enabled"
type="bool"/>
</preferences>
#ifdef HAVE_SHELL_SERVICE
@ -194,10 +191,6 @@
onsyncfrompreference="return gAdvancedPane.readCheckSpelling();"
onsynctopreference="return gAdvancedPane.writeCheckSpelling();"
preference="layout.spellcheckDefault"/>
<checkbox id="privacyDoNotTrackPrefs"
label="&doNotTrack.label;"
accesskey="&doNotTrack.accesskey;"
preference="privacy.donottrackheader.enabled"/>
</groupbox>
#ifdef HAVE_SHELL_SERVICE

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

@ -57,6 +57,11 @@
helpTopic="prefs-privacy">
<preferences id="privacyPreferences">
<!-- Tracking -->
<preference id="privacy.donottrackheader.enabled"
name="privacy.donottrackheader.enabled"
type="bool"/>
<!-- XXX button prefs -->
<preference id="pref.privacy.disable_button.cookie_exceptions"
@ -116,6 +121,16 @@
<script type="application/javascript" src="chrome://browser/content/preferences/privacy.js"/>
<!-- Tracking -->
<groupbox id="trackingGroup">
<caption label="&tracking.label;"/>
<checkbox id="privacyDoNotTrackPrefs"
label="&doNotTrack.label;"
accesskey="&doNotTrack.accesskey;"
preference="privacy.donottrackheader.enabled"/>
</groupbox>
<!-- History -->
<groupbox id="historyGroup">
<caption label="&history.label;"/>

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

@ -81,8 +81,7 @@
<stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences/preferences.properties"/>
<!-- addons, forgery (phishing) UI -->
<groupbox id="addonsPhishingGroup"
xmlns:aaa="http://www.w3.org/2005/07/aaa">
<groupbox id="addonsPhishingGroup">
<hbox id="addonInstallBox">
<checkbox id="warnAddonInstall" flex="1"
label="&warnAddonInstall.label;"

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

@ -467,7 +467,7 @@ PrivateBrowsingService.prototype = {
handle: function PBS_handle(aCmdLine) {
if (aCmdLine.handleFlag("private", false))
; // It has already been handled
aCmdLine.preventDefault = true; // It has already been handled
else if (aCmdLine.handleFlag("private-toggle", false)) {
if (this._autoStarted) {
throw Cr.NS_ERROR_ABORT;

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

@ -640,6 +640,12 @@
]]></body>
</method>
<!--
This method overrides the autocomplete binding's openPopup (essentially
duplicating the logic from the autocomplete popup binding's
openAutocompletePopup method), modifying it so that the popup is aligned with
the inner textbox, but sized to not extend beyond the search bar border.
-->
<method name="openPopup">
<body><![CDATA[
var popup = this.popup;
@ -662,18 +668,26 @@
document.popupNode = null;
const isRTL = getComputedStyle(this, "").direction == "rtl";
var outerRect = this.getBoundingClientRect();
var innerRect = this.inputField.getBoundingClientRect();
var width = outerRect.right - innerRect.left;
if (isRTL) {
var width = innerRect.right - outerRect.left;
} else {
var width = outerRect.right - innerRect.left;
}
popup.setAttribute("width", width > 100 ? width : 100);
var yOffset = outerRect.bottom - innerRect.bottom;
// setConsumeRollupEvent() before we call openPopup(),
// see bug #404438 for more details
popup.popupBoxObject.setConsumeRollupEvent(
this.consumeRollupEvent ?
Ci.nsIPopupBoxObject.ROLLUP_CONSUME :
Ci.nsIPopupBoxObject.ROLLUP_NO_CONSUME);
popup.openPopup(null, "", innerRect.left, outerRect.bottom, false, false);
popup.openPopup(this.inputField, "after_start", 0, yOffset, false, false);
}
]]></body>
</method>

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

@ -21,8 +21,6 @@
<!ENTITY allowHWAccel.accesskey "h">
<!ENTITY checkSpelling.label "Check my spelling as I type">
<!ENTITY checkSpelling.accesskey "t">
<!ENTITY doNotTrack.label "Tell web sites I do not want to be tracked">
<!ENTITY doNotTrack.accesskey "d">
<!ENTITY systemDefaults.label "System Defaults">
<!ENTITY alwaysCheckDefault.label "Always check to see if &brandShortName; is the default browser on startup"><!--XXX-->

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

@ -1,3 +1,8 @@
<!ENTITY tracking.label "Tracking">
<!ENTITY doNotTrack.label "Tell web sites I do not want to be tracked">
<!ENTITY doNotTrack.accesskey "d">
<!ENTITY history.label "History">
<!ENTITY locationBar.label "Location Bar">
@ -30,7 +35,6 @@
<!ENTITY showCookies.label "Show Cookies…">
<!ENTITY showCookies.accesskey "S">
<!ENTITY historyHeader.pre.label "&brandShortName; will:">
<!ENTITY historyHeader.pre.accesskey "w">
<!ENTITY historyHeader.remember.label "Remember history">

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

@ -299,9 +299,12 @@ html[dir=rtl] .appTabTrayContainer {
.undo {
background-color: rgba(0,0,0,.2);
width: 150px;
height: 30px;
line-height: 30px;
padding-top: 3px;
padding-bottom: 3px;
-moz-padding-start: 5px;
-moz-padding-end: 20px;
width: 135px;
line-height: 25px;
box-shadow: 0 1px 0 rgba(255,255,255,.4), 0 1px 0 rgba(0,0,0,.3) inset;
text-shadow: 0 1px 0 rgba(255,255,255,.2);
color: WindowText;
@ -316,14 +319,14 @@ html[dir=rtl] .appTabTrayContainer {
}
.undo .close {
top: 4px;
left: 4px;
top: 7px;
right: 7px;
opacity: 0.5;
}
html[dir=rtl] .undo .close {
left: auto;
right: 4px;
right: auto;
left: 7px;
}
.undo .close:hover{

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

@ -293,9 +293,12 @@ html[dir=rtl] .appTabTrayContainer {
.undo {
background-color: #A0A0A0;
width: 150px;
height: 30px;
line-height: 30px;
padding-top: 3px;
padding-bottom: 3px;
-moz-padding-start: 5px;
-moz-padding-end: 20px;
width: 135px;
line-height: 25px;
box-shadow: 0px 1px 0px rgba(255,255,255,.5), 0px -1px 0px rgba(0,0,0,.24);
text-shadow: 0px -1px 0px rgba(255,255,255,.2);
color: rgba( 0,0,0, .8);
@ -310,14 +313,14 @@ html[dir=rtl] .appTabTrayContainer {
}
.undo .close {
top: 4px;
left: 4px;
top: 7px;
right: 7px;
opacity: 0.5;
}
html[dir=rtl] .undo .close {
left: auto;
right: 4px;
right: auto;
left: 7px;
}
.undo .close:hover{

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

@ -318,9 +318,12 @@ html[dir=rtl] .appTabTrayContainer {
.undo {
background-color: #A0A0A0;
width: 150px;
height: 30px;
line-height: 30px;
padding-top: 3px;
padding-bottom: 3px;
-moz-padding-start: 5px;
-moz-padding-end: 20px;
width: 135px;
line-height: 25px;
box-shadow: 0px 1px 0px rgba(255,255,255,.5), 0px -1px 0px rgba(0,0,0,.24);
text-shadow: 0px -1px 0px rgba(255,255,255,.2);
color: rgba( 0,0,0, .8);
@ -335,14 +338,14 @@ html[dir=rtl] .appTabTrayContainer {
}
.undo .close {
top: 4px;
left: 4px;
top: 7px;
right: 7px;
opacity: 0.5;
}
html[dir=rtl] .undo .close {
left: auto;
right: 4px;
right: auto;
left: 7px;
}
.undo .close:hover{

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

@ -57,7 +57,7 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
/**
* Check that the script currently running in context "cx" can load "uri".
*
* Will return error code NS_ERROR_DOM_BAD_URI if the load request
* Will return error code NS_ERROR_DOM_BAD_URI if the load request
* should be denied.
*
* @param cx the JSContext of the script causing the load
@ -105,7 +105,7 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
/**
* Check that content with principal aPrincipal can load "uri".
*
* Will return error code NS_ERROR_DOM_BAD_URI if the load request
* Will return error code NS_ERROR_DOM_BAD_URI if the load request
* should be denied.
*
* @param aPrincipal the principal identifying the actor causing the load
@ -113,13 +113,13 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
* @param flags the permission set, see above
*/
void checkLoadURIWithPrincipal(in nsIPrincipal aPrincipal,
in nsIURI uri,
in nsIURI uri,
in unsigned long flags);
/**
* Check that content from "from" can load "uri".
*
* Will return error code NS_ERROR_DOM_BAD_URI if the load request
* Will return error code NS_ERROR_DOM_BAD_URI if the load request
* should be denied.
*
* @param from the URI causing the load
@ -128,8 +128,8 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
*
* @deprecated Use checkLoadURIWithPrincipal instead of this function.
*/
void checkLoadURI(in nsIURI from, in nsIURI uri,
in unsigned long flags);
[deprecated] void checkLoadURI(in nsIURI from, in nsIURI uri,
in unsigned long flags);
/**
* Similar to checkLoadURIWithPrincipal but there are two differences:
@ -141,17 +141,17 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
* function will return error code NS_ERROR_DOM_BAD_URI.
*/
void checkLoadURIStrWithPrincipal(in nsIPrincipal aPrincipal,
in AUTF8String uri,
in unsigned long flags);
in AUTF8String uri,
in unsigned long flags);
/**
* Same as CheckLoadURI but takes string arguments for ease of use
* by scripts
*
* @deprecated Use checkLoadURIStrWithPrincipal instead of this function.
*/
void checkLoadURIStr(in AUTF8String from, in AUTF8String uri,
in unsigned long flags);
[deprecated] void checkLoadURIStr(in AUTF8String from, in AUTF8String uri,
in unsigned long flags);
/**
* Check that the function 'funObj' is allowed to run on 'targetObj'
@ -173,10 +173,10 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
[noscript] boolean canExecuteScripts(in JSContextPtr cx,
in nsIPrincipal principal);
///////////////// Principals ///////////////////////
///////////////// Principals ///////////////////////
/**
* Return the principal of the innermost frame of the currently
* executing script. Will return null if there is no script
* Return the principal of the innermost frame of the currently
* executing script. Will return null if there is no script
* currently executing.
*/
[noscript] nsIPrincipal getSubjectPrincipal();
@ -215,12 +215,12 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
*/
[noscript] short requestCapability(in nsIPrincipal principal,
in string capability);
/**
* Return true if the currently executing script has 'capability' enabled.
*/
boolean isCapabilityEnabled(in string capability);
/**
* Enable 'capability' in the innermost frame of the currently executing
* script.
@ -249,7 +249,7 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
// XXXbz ideally we'd pass a subjectName here too, and the nsISupports
// cert we're enabling for...
void setCanEnableCapability(in AUTF8String certificateFingerprint,
in string capability,
in string capability,
in short canEnable);
///////////////////////

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

@ -66,7 +66,7 @@ NS_IMETHODIMP_(nsrefcnt)
nsNullPrincipal::AddRef()
{
NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
nsrefcnt count = PR_AtomicIncrement((PRInt32 *)&mJSPrincipals.refcount);
nsrefcnt count = PR_ATOMIC_INCREMENT(&mJSPrincipals.refcount);
NS_LOG_ADDREF(this, count, "nsNullPrincipal", sizeof(*this));
return count;
}
@ -75,7 +75,7 @@ NS_IMETHODIMP_(nsrefcnt)
nsNullPrincipal::Release()
{
NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
nsrefcnt count = PR_ATOMIC_DECREMENT(&mJSPrincipals.refcount);
NS_LOG_RELEASE(this, count, "nsNullPrincipal");
if (count == 0) {
delete this;

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

@ -154,7 +154,7 @@ nsPrincipal::AddRef()
{
NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
// XXXcaa does this need to be threadsafe? See bug 143559.
nsrefcnt count = PR_AtomicIncrement((PRInt32 *)&mJSPrincipals.refcount);
nsrefcnt count = PR_ATOMIC_INCREMENT(&mJSPrincipals.refcount);
NS_LOG_ADDREF(this, count, "nsPrincipal", sizeof(*this));
return count;
}
@ -163,7 +163,7 @@ NS_IMETHODIMP_(nsrefcnt)
nsPrincipal::Release()
{
NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
nsrefcnt count = PR_ATOMIC_DECREMENT(&mJSPrincipals.refcount);
NS_LOG_RELEASE(this, count, "nsPrincipal");
if (count == 0) {
delete this;

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

@ -63,7 +63,7 @@ NS_IMETHODIMP_(nsrefcnt)
nsSystemPrincipal::AddRef()
{
NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
nsrefcnt count = PR_AtomicIncrement((PRInt32 *)&mJSPrincipals.refcount);
nsrefcnt count = PR_ATOMIC_INCREMENT(&mJSPrincipals.refcount);
NS_LOG_ADDREF(this, count, "nsSystemPrincipal", sizeof(*this));
return count;
}
@ -72,7 +72,7 @@ NS_IMETHODIMP_(nsrefcnt)
nsSystemPrincipal::Release()
{
NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
nsrefcnt count = PR_AtomicDecrement((PRInt32 *)&mJSPrincipals.refcount);
nsrefcnt count = PR_ATOMIC_DECREMENT(&mJSPrincipals.refcount);
NS_LOG_RELEASE(this, count, "nsSystemPrincipal");
if (count == 0) {
delete this;

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

@ -385,6 +385,7 @@ GNU_LD = @GNU_LD@
GNU_CC = @GNU_CC@
GNU_CXX = @GNU_CXX@
HAVE_GCC3_ABI = @HAVE_GCC3_ABI@
HAVE_OLD_CLANG = @HAVE_OLD_CLANG@
INTEL_CC = @INTEL_CC@
INTEL_CXX = @INTEL_CXX@

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

@ -1167,6 +1167,28 @@ fi
fi # COMPILE_ENVIRONMENT
dnl clang prior to 2.9 (including Xcode 4) does not support all the
dnl constructs required by the libtheora inline asm. This is used to
dnl detect and disable it
AC_LANG_SAVE
AC_LANG_C
AC_TRY_COMPILE([
#if defined(__clang__)
# if __clang_major__<2 || (__clang_major__==2 && __clang_minor__<9)
# error "clang older than 2.9 detected"
# endif
#endif
],
[],
result="yes",
result="no")
if test "$result" = "no"; then
AC_DEFINE(HAVE_OLD_CLANG)
HAVE_OLD_CLANG=1
fi
AC_LANG_RESTORE
AC_SUBST(HAVE_OLD_CLANG)
if test -n "$MAKE"; then
if test `echo $MAKE | grep -c make.py` != 1; then
NOT_PYMAKE=$MAKE
@ -5052,13 +5074,18 @@ if test -z "$XULRUNNER_STUB_NAME"; then
fi
AC_SUBST(XULRUNNER_STUB_NAME)
AC_MSG_CHECKING([for application to build])
if test -z "$MOZ_BUILD_APP"; then
AC_MSG_ERROR([--enable-application=APP was not specified and is required.])
AC_MSG_RESULT([browser])
MOZ_BUILD_APP=browser
else
# We have a valid application only if it has a build.mk file in its top
# directory.
if test ! -f "${srcdir}/${MOZ_BUILD_APP}/build.mk" ; then
AC_MSG_RESULT([none])
AC_MSG_ERROR([--enable-application value not recognized (${MOZ_BUILD_APP}/build.mk does not exist).])
else
AC_MSG_RESULT([$MOZ_BUILD_APP])
fi
fi

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

@ -76,8 +76,8 @@ enum nsLinkState {
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0x8331ca9f, 0x8717, 0x4ab4, \
{ 0xad, 0x17, 0xb4, 0x9d, 0xdc, 0xe8, 0xb6, 0x77 } }
{ 0x5788c9eb, 0x646a, 0x4285, \
{ 0xa2, 0x8c, 0xde, 0x0d, 0x43, 0x6b, 0x47, 0x72 } }
/**
* A node of content in a document's content model. This interface
@ -906,15 +906,15 @@ public:
*/
virtual nsISMILAttr* GetAnimatedAttr(PRInt32 aNamespaceID, nsIAtom* aName) = 0;
/**
* Get the SMIL override style for this content node. This is a style
* declaration that is applied *after* the inline style, and it can be used
* e.g. to store animated style values.
*
* Note: This method is analogous to the 'GetStyle' method in
* nsGenericHTMLElement and nsStyledElement.
*/
virtual nsresult GetSMILOverrideStyle(nsIDOMCSSStyleDeclaration** aStyle) = 0;
/**
* Get the SMIL override style for this content node. This is a style
* declaration that is applied *after* the inline style, and it can be used
* e.g. to store animated style values.
*
* Note: This method is analogous to the 'GetStyle' method in
* nsGenericHTMLElement and nsStyledElement.
*/
virtual nsIDOMCSSStyleDeclaration* GetSMILOverrideStyle() = 0;
/**
* Get the SMIL override style rule for this content node. If the rule

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

@ -35,8 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef _nsIContentSerializer_h__
#define _nsIContentSerializer_h__
#ifndef nsIContentSerializer_h
#define nsIContentSerializer_h
#include "nsISupports.h"
@ -44,7 +44,11 @@ class nsIContent;
class nsIDocument;
class nsAString;
/* starting interface: nsIContentSerializer */
namespace mozilla {
namespace dom {
class Element;
} // namespace dom
} // namespace mozilla
#define NS_ICONTENTSERIALIZER_IID \
{ 0xb1ee32f2, 0xb8c4, 0x49b9, \
@ -77,11 +81,11 @@ class nsIContentSerializer : public nsISupports {
NS_IMETHOD AppendDoctype(nsIContent *aDoctype,
nsAString& aStr) = 0;
NS_IMETHOD AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
mozilla::dom::Element* aOriginalElement,
nsAString& aStr) = 0;
NS_IMETHOD AppendElementEnd(nsIContent *aElement,
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
nsAString& aStr) = 0;
NS_IMETHOD Flush(nsAString& aStr) = 0;
@ -100,4 +104,4 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentSerializer, NS_ICONTENTSERIALIZER_IID)
#define NS_CONTENTSERIALIZER_CONTRACTID_PREFIX \
"@mozilla.org/layout/contentserializer;1?mimetype="
#endif /* __gen_nsIContentSerializer_h__ */
#endif /* nsIContentSerializer_h */

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

@ -123,8 +123,8 @@ class Element;
#define NS_IDOCUMENT_IID \
{ 0xc38a7935, 0xc854, 0x4df7, \
{ 0x8f, 0xd4, 0xa2, 0x6f, 0x0d, 0x27, 0x9f, 0x31 } }
{ 0x2c6ad63f, 0xb7b9, 0x42f8, \
{ 0xbd, 0xde, 0x76, 0x0a, 0x83, 0xe3, 0xb0, 0x49 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -757,11 +757,9 @@ public:
virtual void SetReadyStateInternal(ReadyState rs) = 0;
virtual ReadyState GetReadyStateEnum() = 0;
// notify that one or two content nodes changed state
// either may be nsnull, but not both
virtual void ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2,
nsEventStates aStateMask) = 0;
// notify that a content node changed state
virtual void ContentStateChanged(nsIContent* aContent,
nsEventStates aStateMask) = 0;
// Notify that a document state has changed.
// This should only be called by callers whose state is also reflected in the

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

@ -49,8 +49,8 @@ class nsString;
class nsIDocument;
#define NS_IDOCUMENT_OBSERVER_IID \
{ 0x3d005225, 0x210f, 0x4b07, \
{ 0xb1, 0xd9, 0x96, 0x02, 0x05, 0x74, 0xc4, 0x37 } }
{ 0x900bc4bc, 0x8b6c, 0x4cba, \
{ 0x82, 0xfa, 0x56, 0x8a, 0x80, 0xff, 0xfd, 0x3e } }
typedef PRUint32 nsUpdateType;
@ -103,20 +103,12 @@ public:
* added/removed from the document or the content itself changed
* (the other notifications are used for that).
*
* The optional second content node is to allow optimization
* of the case where state moves from one node to another
* (as is likely for :focus and :hover)
*
* Either content node may be nsnull, but not both
*
* @param aDocument The document being observed
* @param aContent1 the piece of content that changed
* @param aContent2 optional second piece of content that changed
* @param aContent the piece of content that changed
*/
virtual void ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
nsEventStates aStateMask) = 0;
virtual void ContentStateChanged(nsIDocument* aDocument,
nsIContent* aContent,
nsEventStates aStateMask) = 0;
/**
* Notification that the state of the document has changed.
@ -247,11 +239,10 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
#define NS_DECL_NSIDOCUMENTOBSERVER_ENDLOAD \
virtual void EndLoad(nsIDocument* aDocument);
#define NS_DECL_NSIDOCUMENTOBSERVER_CONTENTSTATESCHANGED \
virtual void ContentStatesChanged(nsIDocument* aDocument, \
nsIContent* aContent1, \
nsIContent* aContent2, \
nsEventStates aStateMask);
#define NS_DECL_NSIDOCUMENTOBSERVER_CONTENTSTATECHANGED \
virtual void ContentStateChanged(nsIDocument* aDocument, \
nsIContent* aContent, \
nsEventStates aStateMask);
#define NS_DECL_NSIDOCUMENTOBSERVER_DOCUMENTSTATESCHANGED \
virtual void DocumentStatesChanged(nsIDocument* aDocument, \
@ -293,7 +284,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE \
NS_DECL_NSIDOCUMENTOBSERVER_BEGINLOAD \
NS_DECL_NSIDOCUMENTOBSERVER_ENDLOAD \
NS_DECL_NSIDOCUMENTOBSERVER_CONTENTSTATESCHANGED \
NS_DECL_NSIDOCUMENTOBSERVER_CONTENTSTATECHANGED \
NS_DECL_NSIDOCUMENTOBSERVER_DOCUMENTSTATESCHANGED \
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED \
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED \
@ -327,9 +318,8 @@ _class::EndLoad(nsIDocument* aDocument) \
#define NS_IMPL_NSIDOCUMENTOBSERVER_STATE_STUB(_class) \
void \
_class::ContentStatesChanged(nsIDocument* aDocument, \
nsIContent* aContent1, \
nsIContent* aContent2, \
_class::ContentStateChanged(nsIDocument* aDocument, \
nsIContent* aContent, \
nsEventStates aStateMask) \
{ \
} \

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

@ -109,7 +109,7 @@ interface nsIXMLHttpRequestUpload : nsIXMLHttpRequestEventTarget {
* you're aware of all the security implications. And then think twice about
* it.
*/
[scriptable, uuid(6bb91106-85f0-4d93-8cb4-e57b3d0624f2)]
[scriptable, uuid(af62a870-820c-4981-96a3-28ab17b779e1)]
interface nsIXMLHttpRequest : nsISupports
{
/**
@ -187,42 +187,19 @@ interface nsIXMLHttpRequest : nsISupports
*/
ACString getResponseHeader(in AUTF8String header);
/**
* Native (non-script) method to initialize a request. Note that
* the request is not sent until the <code>send</code> method
* is invoked.
*
* If there is an "active" request (that is, if open() or openRequest() has
* been called already), this is equivalent to calling abort().
*
* @param method The HTTP method, for example "POST" or "GET". Ignored
* if the URL is not a HTTP(S) URL.
* @param url The URL to which to send the request.
* @param async Whether the request is synchronous or asynchronous
* i.e. whether send returns only after the response
* is received or if it returns immediately after
* sending the request. In the latter case, notification
* of completion is sent through the event listeners.
* This argument must be true if the multipart
* attribute has been set to true, or an exception will
* be thrown.
* @param user A username for authentication if necessary.
* @param password A password for authentication if necessary.
*/
[noscript] void openRequest(in AUTF8String method,
in AUTF8String url,
in boolean async,
in AString user,
in AString password);
%{C++
// note this is NOT virtual so this won't muck with the vtable!
inline nsresult Open(const nsACString& method, const nsACString& url,
PRBool async, const nsAString& user,
const nsAString& password) {
return Open(method, url, async, user, password, 3);
}
%}
/**
* Meant to be a script-only method for initializing a request.
* The parameters are similar to the ones detailed in the
* description of <code>openRequest</code>, but the last
* 3 are optional.
*
* If there is an "active" request (that is, if open() or openRequest() has
* been called already), this is equivalent to calling abort().
* If there is an "active" request (that is, if open() has been called
* already), this is equivalent to calling abort() and then open().
*
* @param method The HTTP method - either "POST" or "GET". Ignored
* if the URL is not a HTTP URL.

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

@ -102,7 +102,7 @@ Link::SetLinkState(nsLinkState aState)
newLinkState == NS_EVENT_STATE_UNVISITED,
"Unexpected state obtained from LinkState()!");
mozAutoDocUpdate update(doc, UPDATE_CONTENT_STATE, PR_TRUE);
doc->ContentStatesChanged(content, nsnull, oldLinkState ^ newLinkState);
doc->ContentStateChanged(content, oldLinkState ^ newLinkState);
}
nsEventStates
@ -493,7 +493,7 @@ Link::ResetLinkState(bool aNotify)
if (aNotify && doc) {
nsEventStates changedState = NS_EVENT_STATE_VISITED ^ NS_EVENT_STATE_UNVISITED;
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, aNotify);
doc->ContentStatesChanged(content, nsnull, changedState);
doc->ContentStateChanged(content, changedState);
}
}

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

@ -151,6 +151,20 @@ CPPSRCS = \
ThirdPartyUtil.cpp \
$(NULL)
# Are we targeting x86-32 or x86-64? If so, we want to include SSE2 code for
# nsTextFragment.cpp
ifneq (,$(INTEL_ARCHITECTURE))
CPPSRCS += nsTextFragmentSSE2.cpp
# gcc requires -msse2 for this file since it uses SSE2 intrinsics. (See bug
# 585538 comment 12.)
ifdef GNU_CC
nsTextFragmentSSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
endif
endif
GQI_SRCS = contentbase.gqi
# we don't want the shared lib, but we want to force the creation of a

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

@ -63,8 +63,9 @@
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsEscape.h"
#include "mozilla/dom/Element.h"
//#define DEBUG_BenB
using namespace mozilla::dom;
static inline PRUnichar* escape(const nsString& source)
{
@ -241,8 +242,8 @@ mozSanitizingHTMLSerializer::AppendText(nsIContent* aText,
}
NS_IMETHODIMP
mozSanitizingHTMLSerializer::AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
mozSanitizingHTMLSerializer::AppendElementStart(Element* aElement,
Element* aOriginalElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);
@ -270,7 +271,7 @@ mozSanitizingHTMLSerializer::AppendElementStart(nsIContent *aElement,
}
NS_IMETHODIMP
mozSanitizingHTMLSerializer::AppendElementEnd(nsIContent *aElement,
mozSanitizingHTMLSerializer::AppendElementEnd(Element* aElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);

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

@ -89,10 +89,11 @@ public:
{ return NS_OK; }
NS_IMETHOD AppendDoctype(nsIContent *aDoctype, nsAString& aStr)
{ return NS_OK; }
NS_IMETHOD AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
nsAString& aStr);
NS_IMETHOD AppendElementEnd(nsIContent *aElement, nsAString& aStr);
NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
mozilla::dom::Element* aOriginalElement,
nsAString& aStr);
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
nsAString& aStr);
NS_IMETHOD Flush(nsAString& aStr);
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
@ -150,7 +151,7 @@ protected:
PRUint32 mSkipLevel;
nsHashtable mAllowedTags;
nsCOMPtr<nsIContent> mContent;
nsRefPtr<mozilla::dom::Element> mContent;
nsAString* mOutputString;
nsIParserNode* mParserNode;
nsCOMPtr<nsIParserService> mParserService;

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

@ -448,6 +448,14 @@ nsContentList::nsContentList(nsINode* aRootNode,
{
NS_ASSERTION(mRootNode, "Must have root");
mRootNode->AddMutationObserver(this);
// We only need to flush if we're in an non-HTML document, since the
// HTML5 parser doesn't need flushing. Further, if we're not in a
// document at all right now (in the GetCurrentDoc() sense), we're
// not parser-created and don't need to be flushing stuff under us
// to get our kids right.
nsIDocument* doc = mRootNode->GetCurrentDoc();
mFlushesNeeded = doc && !doc->IsHTML();
}
nsContentList::~nsContentList()

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

@ -54,52 +54,337 @@
#include "nsIChannelEventSink.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsXMLHttpRequest.h"
#include "nsAsyncRedirectVerifyHelper.h"
#include "prclist.h"
#include "prtime.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#define PREFLIGHT_CACHE_SIZE 100
static PRBool gDisableCORS = PR_FALSE;
static PRBool gDisableCORSPrivateData = PR_FALSE;
class nsChannelCanceller
//////////////////////////////////////////////////////////////////////////
// Preflight cache
class nsPreflightCache
{
public:
nsChannelCanceller(nsIChannel* aChannel)
: mChannel(aChannel)
struct TokenTime
{
nsCString token;
PRTime expirationTime;
};
struct CacheEntry : public PRCList
{
CacheEntry(nsCString& aKey)
: mKey(aKey)
{
MOZ_COUNT_CTOR(nsPreflightCache::CacheEntry);
}
~CacheEntry()
{
MOZ_COUNT_DTOR(nsPreflightCache::CacheEntry);
}
void PurgeExpired(PRTime now);
PRBool CheckRequest(const nsCString& aMethod,
const nsTArray<nsCString>& aCustomHeaders);
nsCString mKey;
nsTArray<TokenTime> mMethods;
nsTArray<TokenTime> mHeaders;
};
nsPreflightCache()
{
MOZ_COUNT_CTOR(nsPreflightCache);
PR_INIT_CLIST(&mList);
}
~nsChannelCanceller()
~nsPreflightCache()
{
if (mChannel) {
mChannel->Cancel(NS_ERROR_DOM_BAD_URI);
Clear();
MOZ_COUNT_DTOR(nsPreflightCache);
}
PRBool Initialize()
{
return mTable.Init();
}
CacheEntry* GetEntry(nsIURI* aURI, nsIPrincipal* aPrincipal,
PRBool aWithCredentials, PRBool aCreate);
void RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal);
void Clear();
private:
static PLDHashOperator
RemoveExpiredEntries(const nsACString& aKey, nsAutoPtr<CacheEntry>& aValue,
void* aUserData);
static PRBool GetCacheKey(nsIURI* aURI, nsIPrincipal* aPrincipal,
PRBool aWithCredentials, nsACString& _retval);
nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
PRCList mList;
};
// Will be initialized in EnsurePreflightCache.
static nsPreflightCache* sPreflightCache = nsnull;
static PRBool EnsurePreflightCache()
{
if (sPreflightCache)
return PR_TRUE;
nsAutoPtr<nsPreflightCache> newCache(new nsPreflightCache());
if (newCache->Initialize()) {
sPreflightCache = newCache.forget();
return PR_TRUE;
}
return PR_FALSE;
}
void
nsPreflightCache::CacheEntry::PurgeExpired(PRTime now)
{
PRUint32 i;
for (i = 0; i < mMethods.Length(); ++i) {
if (now >= mMethods[i].expirationTime) {
mMethods.RemoveElementAt(i--);
}
}
for (i = 0; i < mHeaders.Length(); ++i) {
if (now >= mHeaders[i].expirationTime) {
mHeaders.RemoveElementAt(i--);
}
}
}
PRBool
nsPreflightCache::CacheEntry::CheckRequest(const nsCString& aMethod,
const nsTArray<nsCString>& aHeaders)
{
PurgeExpired(PR_Now());
if (!aMethod.EqualsLiteral("GET") && !aMethod.EqualsLiteral("POST")) {
PRUint32 i;
for (i = 0; i < mMethods.Length(); ++i) {
if (aMethod.Equals(mMethods[i].token))
break;
}
if (i == mMethods.Length()) {
return PR_FALSE;
}
}
void DontCancel()
{
mChannel = nsnull;
for (PRUint32 i = 0; i < aHeaders.Length(); ++i) {
PRUint32 j;
for (j = 0; j < mHeaders.Length(); ++j) {
if (aHeaders[i].Equals(mHeaders[j].token,
nsCaseInsensitiveCStringComparator())) {
break;
}
}
if (j == mHeaders.Length()) {
return PR_FALSE;
}
}
private:
nsIChannel* mChannel;
};
return PR_TRUE;
}
NS_IMPL_ISUPPORTS5(nsCrossSiteListenerProxy, nsIStreamListener,
nsPreflightCache::CacheEntry*
nsPreflightCache::GetEntry(nsIURI* aURI,
nsIPrincipal* aPrincipal,
PRBool aWithCredentials,
PRBool aCreate)
{
nsCString key;
if (!GetCacheKey(aURI, aPrincipal, aWithCredentials, key)) {
NS_WARNING("Invalid cache key!");
return nsnull;
}
CacheEntry* entry;
if (mTable.Get(key, &entry)) {
// Entry already existed so just return it. Also update the LRU list.
// Move to the head of the list.
PR_REMOVE_LINK(entry);
PR_INSERT_LINK(entry, &mList);
return entry;
}
if (!aCreate) {
return nsnull;
}
// This is a new entry, allocate and insert into the table now so that any
// failures don't cause items to be removed from a full cache.
entry = new CacheEntry(key);
if (!entry) {
NS_WARNING("Failed to allocate new cache entry!");
return nsnull;
}
NS_ASSERTION(mTable.Count() <= PREFLIGHT_CACHE_SIZE,
"Something is borked, too many entries in the cache!");
// Now enforce the max count.
if (mTable.Count() == PREFLIGHT_CACHE_SIZE) {
// Try to kick out all the expired entries.
PRTime now = PR_Now();
mTable.Enumerate(RemoveExpiredEntries, &now);
// If that didn't remove anything then kick out the least recently used
// entry.
if (mTable.Count() == PREFLIGHT_CACHE_SIZE) {
CacheEntry* lruEntry = static_cast<CacheEntry*>(PR_LIST_TAIL(&mList));
PR_REMOVE_LINK(lruEntry);
// This will delete 'lruEntry'.
mTable.Remove(lruEntry->mKey);
NS_ASSERTION(mTable.Count() == PREFLIGHT_CACHE_SIZE - 1,
"Somehow tried to remove an entry that was never added!");
}
}
if (!mTable.Put(key, entry)) {
// Failed, clean up the new entry.
delete entry;
NS_WARNING("Failed to add entry to the CORS preflight cache!");
return nsnull;
}
PR_INSERT_LINK(entry, &mList);
return entry;
}
void
nsPreflightCache::RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal)
{
CacheEntry* entry;
nsCString key;
if (GetCacheKey(aURI, aPrincipal, PR_TRUE, key) &&
mTable.Get(key, &entry)) {
PR_REMOVE_LINK(entry);
mTable.Remove(key);
}
if (GetCacheKey(aURI, aPrincipal, PR_FALSE, key) &&
mTable.Get(key, &entry)) {
PR_REMOVE_LINK(entry);
mTable.Remove(key);
}
}
void
nsPreflightCache::Clear()
{
PR_INIT_CLIST(&mList);
mTable.Clear();
}
/* static */ PLDHashOperator
nsPreflightCache::RemoveExpiredEntries(const nsACString& aKey,
nsAutoPtr<CacheEntry>& aValue,
void* aUserData)
{
PRTime* now = static_cast<PRTime*>(aUserData);
aValue->PurgeExpired(*now);
if (aValue->mHeaders.IsEmpty() &&
aValue->mMethods.IsEmpty()) {
// Expired, remove from the list as well as the hash table.
PR_REMOVE_LINK(aValue);
return PL_DHASH_REMOVE;
}
return PL_DHASH_NEXT;
}
/* static */ PRBool
nsPreflightCache::GetCacheKey(nsIURI* aURI,
nsIPrincipal* aPrincipal,
PRBool aWithCredentials,
nsACString& _retval)
{
NS_ASSERTION(aURI, "Null uri!");
NS_ASSERTION(aPrincipal, "Null principal!");
NS_NAMED_LITERAL_CSTRING(space, " ");
nsCOMPtr<nsIURI> uri;
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, PR_FALSE);
nsCAutoString scheme, host, port;
if (uri) {
uri->GetScheme(scheme);
uri->GetHost(host);
port.AppendInt(NS_GetRealPort(uri));
}
nsCAutoString cred;
if (aWithCredentials) {
_retval.AssignLiteral("cred");
}
else {
_retval.AssignLiteral("nocred");
}
nsCAutoString spec;
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
_retval.Assign(cred + space + scheme + space + host + space + port + space +
spec);
return PR_TRUE;
}
//////////////////////////////////////////////////////////////////////////
// nsCORSListenerProxy
NS_IMPL_ISUPPORTS5(nsCORSListenerProxy, nsIStreamListener,
nsIRequestObserver, nsIChannelEventSink,
nsIInterfaceRequestor, nsIAsyncVerifyRedirectCallback)
/* static */
void
nsCrossSiteListenerProxy::Startup()
nsCORSListenerProxy::Startup()
{
nsContentUtils::AddBoolPrefVarCache("content.cors.disable", &gDisableCORS);
nsContentUtils::AddBoolPrefVarCache("content.cors.no_private_data", &gDisableCORSPrivateData);
}
nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
PRBool aWithCredentials,
nsresult* aResult)
/* static */
void
nsCORSListenerProxy::Shutdown()
{
delete sPreflightCache;
sPreflightCache = nsnull;
}
nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
PRBool aWithCredentials,
nsresult* aResult)
: mOuterListener(aOuter),
mRequestingPrincipal(aRequestingPrincipal),
mWithCredentials(aWithCredentials && !gDisableCORSPrivateData),
@ -118,14 +403,13 @@ nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
}
}
nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
PRBool aWithCredentials,
const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders,
nsresult* aResult)
nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
PRBool aWithCredentials,
const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders,
nsresult* aResult)
: mOuterListener(aOuter),
mRequestingPrincipal(aRequestingPrincipal),
mWithCredentials(aWithCredentials && !gDisableCORSPrivateData),
@ -152,19 +436,18 @@ nsCrossSiteListenerProxy::nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
}
NS_IMETHODIMP
nsCrossSiteListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsISupports* aContext)
nsCORSListenerProxy::OnStartRequest(nsIRequest* aRequest,
nsISupports* aContext)
{
mRequestApproved = NS_SUCCEEDED(CheckRequestApproved(aRequest));
if (!mRequestApproved) {
if (nsXMLHttpRequest::sAccessControlCache) {
if (sPreflightCache) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
if (channel) {
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIURI> uri;
NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
if (uri) {
nsXMLHttpRequest::sAccessControlCache->
RemoveEntries(uri, mRequestingPrincipal);
sPreflightCache->RemoveEntries(uri, mRequestingPrincipal);
}
}
}
@ -219,7 +502,7 @@ IsValidHTTPToken(const nsCSubstring& aToken)
}
nsresult
nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
{
// Check if this was actually a cross domain request
if (!mHasBeenCrossSite) {
@ -326,19 +609,19 @@ nsCrossSiteListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
}
NS_IMETHODIMP
nsCrossSiteListenerProxy::OnStopRequest(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aStatusCode)
nsCORSListenerProxy::OnStopRequest(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aStatusCode)
{
return mOuterListener->OnStopRequest(aRequest, aContext, aStatusCode);
}
NS_IMETHODIMP
nsCrossSiteListenerProxy::OnDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInputStream,
PRUint32 aOffset,
PRUint32 aCount)
nsCORSListenerProxy::OnDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInputStream,
PRUint32 aOffset,
PRUint32 aCount)
{
if (!mRequestApproved) {
return NS_ERROR_DOM_BAD_URI;
@ -348,7 +631,7 @@ nsCrossSiteListenerProxy::OnDataAvailable(nsIRequest* aRequest,
}
NS_IMETHODIMP
nsCrossSiteListenerProxy::GetInterface(const nsIID & aIID, void **aResult)
nsCORSListenerProxy::GetInterface(const nsIID & aIID, void **aResult)
{
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
*aResult = static_cast<nsIChannelEventSink*>(this);
@ -363,21 +646,20 @@ nsCrossSiteListenerProxy::GetInterface(const nsIID & aIID, void **aResult)
}
NS_IMETHODIMP
nsCrossSiteListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags,
nsIAsyncVerifyRedirectCallback *cb)
nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags,
nsIAsyncVerifyRedirectCallback *cb)
{
nsresult rv;
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags)) {
rv = CheckRequestApproved(aOldChannel);
if (NS_FAILED(rv)) {
if (nsXMLHttpRequest::sAccessControlCache) {
if (sPreflightCache) {
nsCOMPtr<nsIURI> oldURI;
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));
if (oldURI) {
nsXMLHttpRequest::sAccessControlCache->
RemoveEntries(oldURI, mRequestingPrincipal);
sPreflightCache->RemoveEntries(oldURI, mRequestingPrincipal);
}
}
aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
@ -408,7 +690,7 @@ nsCrossSiteListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
}
NS_IMETHODIMP
nsCrossSiteListenerProxy::OnRedirectVerifyCallback(nsresult result)
nsCORSListenerProxy::OnRedirectVerifyCallback(nsresult result)
{
NS_ASSERTION(mRedirectCallback, "mRedirectCallback not set in callback");
NS_ASSERTION(mOldRedirectChannel, "mOldRedirectChannel not set in callback");
@ -417,7 +699,7 @@ nsCrossSiteListenerProxy::OnRedirectVerifyCallback(nsresult result)
if (NS_SUCCEEDED(result)) {
nsresult rv = UpdateChannel(mNewRedirectChannel);
if (NS_FAILED(rv)) {
NS_WARNING("nsCrossSiteListenerProxy::OnRedirectVerifyCallback: "
NS_WARNING("nsCORSListenerProxy::OnRedirectVerifyCallback: "
"UpdateChannel() returned failure");
}
result = rv;
@ -435,7 +717,7 @@ nsCrossSiteListenerProxy::OnRedirectVerifyCallback(nsresult result)
}
nsresult
nsCrossSiteListenerProxy::UpdateChannel(nsIChannel* aChannel)
nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel)
{
nsCOMPtr<nsIURI> uri, originalURI;
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
@ -517,3 +799,304 @@ nsCrossSiteListenerProxy::UpdateChannel(nsIChannel* aChannel)
return NS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Preflight proxy
// Class used as streamlistener and notification callback when
// doing the initial OPTIONS request for a CORS check
class nsCORSPreflightListener : public nsIStreamListener,
public nsIInterfaceRequestor,
public nsIChannelEventSink
{
public:
nsCORSPreflightListener(nsIChannel* aOuterChannel,
nsIStreamListener* aOuterListener,
nsISupports* aOuterContext,
nsIPrincipal* aReferrerPrincipal,
const nsACString& aRequestMethod,
PRBool aWithCredentials)
: mOuterChannel(aOuterChannel), mOuterListener(aOuterListener),
mOuterContext(aOuterContext), mReferrerPrincipal(aReferrerPrincipal),
mRequestMethod(aRequestMethod), mWithCredentials(aWithCredentials)
{ }
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
private:
void AddResultToCache(nsIRequest* aRequest);
nsCOMPtr<nsIChannel> mOuterChannel;
nsCOMPtr<nsIStreamListener> mOuterListener;
nsCOMPtr<nsISupports> mOuterContext;
nsCOMPtr<nsIPrincipal> mReferrerPrincipal;
nsCString mRequestMethod;
PRBool mWithCredentials;
};
NS_IMPL_ISUPPORTS4(nsCORSPreflightListener, nsIStreamListener,
nsIRequestObserver, nsIInterfaceRequestor,
nsIChannelEventSink)
void
nsCORSPreflightListener::AddResultToCache(nsIRequest *aRequest)
{
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
NS_ASSERTION(http, "Request was not http");
// The "Access-Control-Max-Age" header should return an age in seconds.
nsCAutoString headerVal;
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Max-Age"),
headerVal);
if (headerVal.IsEmpty()) {
return;
}
// Sanitize the string. We only allow 'delta-seconds' as specified by
// http://dev.w3.org/2006/waf/access-control (digits 0-9 with no leading or
// trailing non-whitespace characters).
PRUint32 age = 0;
nsCSubstring::const_char_iterator iter, end;
headerVal.BeginReading(iter);
headerVal.EndReading(end);
while (iter != end) {
if (*iter < '0' || *iter > '9') {
return;
}
age = age * 10 + (*iter - '0');
// Cap at 24 hours. This also avoids overflow
age = NS_MIN(age, 86400U);
++iter;
}
if (!age || !EnsurePreflightCache()) {
return;
}
// String seems fine, go ahead and cache.
// Note that we have already checked that these headers follow the correct
// syntax.
nsCOMPtr<nsIURI> uri;
NS_GetFinalChannelURI(http, getter_AddRefs(uri));
// PR_Now gives microseconds
PRTime expirationTime = PR_Now() + (PRUint64)age * PR_USEC_PER_SEC;
nsPreflightCache::CacheEntry* entry =
sPreflightCache->GetEntry(uri, mReferrerPrincipal, mWithCredentials,
PR_TRUE);
if (!entry) {
return;
}
// The "Access-Control-Allow-Methods" header contains a comma separated
// list of method names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Methods"),
headerVal);
nsCCharSeparatedTokenizer methods(headerVal, ',');
while(methods.hasMoreTokens()) {
const nsDependentCSubstring& method = methods.nextToken();
if (method.IsEmpty()) {
continue;
}
PRUint32 i;
for (i = 0; i < entry->mMethods.Length(); ++i) {
if (entry->mMethods[i].token.Equals(method)) {
entry->mMethods[i].expirationTime = expirationTime;
break;
}
}
if (i == entry->mMethods.Length()) {
nsPreflightCache::TokenTime* newMethod =
entry->mMethods.AppendElement();
if (!newMethod) {
return;
}
newMethod->token = method;
newMethod->expirationTime = expirationTime;
}
}
// The "Access-Control-Allow-Headers" header contains a comma separated
// list of method names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Headers"),
headerVal);
nsCCharSeparatedTokenizer headers(headerVal, ',');
while(headers.hasMoreTokens()) {
const nsDependentCSubstring& header = headers.nextToken();
if (header.IsEmpty()) {
continue;
}
PRUint32 i;
for (i = 0; i < entry->mHeaders.Length(); ++i) {
if (entry->mHeaders[i].token.Equals(header)) {
entry->mHeaders[i].expirationTime = expirationTime;
break;
}
}
if (i == entry->mHeaders.Length()) {
nsPreflightCache::TokenTime* newHeader =
entry->mHeaders.AppendElement();
if (!newHeader) {
return;
}
newHeader->token = header;
newHeader->expirationTime = expirationTime;
}
}
}
NS_IMETHODIMP
nsCORSPreflightListener::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
nsresult status;
nsresult rv = aRequest->GetStatus(&status);
if (NS_SUCCEEDED(rv)) {
rv = status;
}
if (NS_SUCCEEDED(rv)) {
// Everything worked, try to cache and then fire off the actual request.
AddResultToCache(aRequest);
rv = mOuterChannel->AsyncOpen(mOuterListener, mOuterContext);
}
if (NS_FAILED(rv)) {
mOuterChannel->Cancel(rv);
mOuterListener->OnStartRequest(mOuterChannel, mOuterContext);
mOuterListener->OnStopRequest(mOuterChannel, mOuterContext, rv);
return rv;
}
return NS_OK;
}
NS_IMETHODIMP
nsCORSPreflightListener::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatus)
{
return NS_OK;
}
/** nsIStreamListener methods **/
NS_IMETHODIMP
nsCORSPreflightListener::OnDataAvailable(nsIRequest *aRequest,
nsISupports *ctxt,
nsIInputStream *inStr,
PRUint32 sourceOffset,
PRUint32 count)
{
return NS_OK;
}
NS_IMETHODIMP
nsCORSPreflightListener::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags,
nsIAsyncVerifyRedirectCallback *callback)
{
// Only internal redirects allowed for now.
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags))
return NS_ERROR_DOM_BAD_URI;
callback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
NS_IMETHODIMP
nsCORSPreflightListener::GetInterface(const nsIID & aIID, void **aResult)
{
return QueryInterface(aIID, aResult);
}
nsresult
NS_StartCORSPreflight(nsIChannel* aRequestChannel,
nsIStreamListener* aListener,
nsIPrincipal* aPrincipal,
PRBool aWithCredentials,
nsTArray<nsCString>& aUnsafeHeaders,
nsIChannel** aPreflightChannel)
{
*aPreflightChannel = nsnull;
nsCAutoString method;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequestChannel));
NS_ENSURE_TRUE(httpChannel, NS_ERROR_UNEXPECTED);
httpChannel->GetRequestMethod(method);
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsPreflightCache::CacheEntry* entry =
sPreflightCache ?
sPreflightCache->GetEntry(uri, aPrincipal, aWithCredentials, PR_FALSE) :
nsnull;
if (entry && entry->CheckRequest(method, aUnsafeHeaders)) {
// We have a cached preflight result, just start the original channel
return aRequestChannel->AsyncOpen(aListener, nsnull);
}
// Either it wasn't cached or the cached result has expired. Build a
// channel for the OPTIONS request.
nsCOMPtr<nsILoadGroup> loadGroup;
rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup));
NS_ENSURE_SUCCESS(rv, rv);
nsLoadFlags loadFlags;
rv = aRequestChannel->GetLoadFlags(&loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIChannel> preflightChannel;
rv = NS_NewChannel(getter_AddRefs(preflightChannel), uri, nsnull,
loadGroup, nsnull, loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHttpChannel> preHttp = do_QueryInterface(preflightChannel);
NS_ASSERTION(preHttp, "Failed to QI to nsIHttpChannel!");
rv = preHttp->SetRequestMethod(NS_LITERAL_CSTRING("OPTIONS"));
NS_ENSURE_SUCCESS(rv, rv);
// Set up listener which will start the original channel
nsCOMPtr<nsIStreamListener> preflightListener =
new nsCORSPreflightListener(aRequestChannel, aListener, nsnull, aPrincipal,
method, aWithCredentials);
NS_ENSURE_TRUE(preflightListener, NS_ERROR_OUT_OF_MEMORY);
preflightListener =
new nsCORSListenerProxy(preflightListener, aPrincipal,
preflightChannel, aWithCredentials,
method, aUnsafeHeaders, &rv);
NS_ENSURE_TRUE(preflightListener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
// Start preflight
rv = preflightChannel->AsyncOpen(preflightListener, nsnull);
NS_ENSURE_SUCCESS(rv, rv);
// Return newly created preflight channel
preflightChannel.forget(aPreflightChannel);
return NS_OK;
}

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

@ -35,8 +35,8 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsCrossSiteListenerProxy_h__
#define nsCrossSiteListenerProxy_h__
#ifndef nsCORSListenerProxy_h__
#define nsCORSListenerProxy_h__
#include "nsIStreamListener.h"
#include "nsIInterfaceRequestor.h"
@ -55,24 +55,32 @@ class nsIPrincipal;
extern PRBool
IsValidHTTPToken(const nsCSubstring& aToken);
class nsCrossSiteListenerProxy : public nsIStreamListener,
public nsIInterfaceRequestor,
public nsIChannelEventSink,
public nsIAsyncVerifyRedirectCallback
nsresult
NS_StartCORSPreflight(nsIChannel* aRequestChannel,
nsIStreamListener* aListener,
nsIPrincipal* aPrincipal,
PRBool aWithCredentials,
nsTArray<nsCString>& aACUnsafeHeaders,
nsIChannel** aPreflightChannel);
class nsCORSListenerProxy : public nsIStreamListener,
public nsIInterfaceRequestor,
public nsIChannelEventSink,
public nsIAsyncVerifyRedirectCallback
{
public:
nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
PRBool aWithCredentials,
nsresult* aResult);
nsCrossSiteListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
PRBool aWithCredentials,
const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders,
nsresult* aResult);
nsCORSListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
PRBool aWithCredentials,
nsresult* aResult);
nsCORSListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
nsIChannel* aChannel,
PRBool aWithCredentials,
const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders,
nsresult* aResult);
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
@ -84,6 +92,8 @@ public:
// Must be called at startup.
static void Startup();
static void Shutdown();
private:
nsresult UpdateChannel(nsIChannel* aChannel);
nsresult CheckRequestApproved(nsIRequest* aRequest);

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

@ -42,7 +42,7 @@
#include "nsDOMAttributeMap.h"
#include "nsDOMAttribute.h"
#include "nsIDOM3Document.h"
#include "nsIDOMDocument.h"
#include "nsGenericElement.h"
#include "nsIContent.h"
#include "nsIDocument.h"
@ -298,7 +298,7 @@ nsDOMAttributeMap::SetNamedItemInternal(nsIDOMNode *aNode,
}
if (!mContent->HasSameOwnerDoc(iAttribute)) {
nsCOMPtr<nsIDOM3Document> domDoc =
nsCOMPtr<nsIDOMDocument> domDoc =
do_QueryInterface(mContent->GetOwnerDoc(), &rv);
NS_ENSURE_SUCCESS(rv, rv);

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

@ -4266,11 +4266,10 @@ nsDocument::EndLoad()
}
void
nsDocument::ContentStatesChanged(nsIContent* aContent1, nsIContent* aContent2,
nsEventStates aStateMask)
nsDocument::ContentStateChanged(nsIContent* aContent, nsEventStates aStateMask)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStatesChanged,
(this, aContent1, aContent2, aStateMask));
NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStateChanged,
(this, aContent, aStateMask));
}
void

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

@ -52,7 +52,6 @@
#include "nsTArray.h"
#include "nsHashSets.h"
#include "nsIDOMXMLDocument.h"
#include "nsIDOM3Document.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMDocumentXBL.h"
#include "nsIDOMNSDocument.h"
@ -509,7 +508,6 @@ class nsDocument : public nsIDocument,
public nsIDOMDocumentRange,
public nsIDOMDocumentTraversal,
public nsIDOMDocumentXBL,
public nsIDOM3Document,
public nsSupportsWeakReference,
public nsIDOMEventTarget,
public nsIDOM3EventTarget,
@ -708,9 +706,8 @@ public:
virtual void SetReadyStateInternal(ReadyState rs);
virtual ReadyState GetReadyStateEnum();
virtual void ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2,
nsEventStates aStateMask);
virtual void ContentStateChanged(nsIContent* aContent,
nsEventStates aStateMask);
virtual void DocumentStatesChanged(nsEventStates aStateMask);
virtual void StyleRuleChanged(nsIStyleSheet* aStyleSheet,
@ -805,9 +802,6 @@ public:
// nsIDOMDocument
NS_DECL_NSIDOMDOCUMENT
// nsIDOM3Document
NS_DECL_NSIDOM3DOCUMENT
// nsIDOMXMLDocument
NS_DECL_NSIDOMXMLDOCUMENT
@ -1279,7 +1273,6 @@ protected:
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMDocumentTraversal, \
nsDocument) \
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMEventTarget, nsDocument) \
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMNode, nsDocument) \
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOM3Document, nsDocument)
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(_class, nsIDOMNode, nsDocument)
#endif /* nsDocument_h___ */

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

@ -422,7 +422,7 @@ nsDocumentEncoder::SerializeNodeEnd(nsINode* aNode,
return NS_OK;
if (aNode->IsElement()) {
mSerializer->AppendElementEnd(static_cast<nsIContent*>(aNode), aStr);
mSerializer->AppendElementEnd(aNode->AsElement(), aStr);
}
return NS_OK;
}

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

@ -1115,11 +1115,10 @@ nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
}
#ifdef MOZ_SMIL
nsresult
nsGenericDOMDataNode::GetSMILOverrideStyle(nsIDOMCSSStyleDeclaration** aStyle)
nsIDOMCSSStyleDeclaration*
nsGenericDOMDataNode::GetSMILOverrideStyle()
{
*aStyle = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
return nsnull;
}
css::StyleRule*

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

@ -234,7 +234,7 @@ public:
{
return nsnull;
}
virtual nsresult GetSMILOverrideStyle(nsIDOMCSSStyleDeclaration** aStyle);
virtual nsIDOMCSSStyleDeclaration* GetSMILOverrideStyle();
virtual mozilla::css::StyleRule* GetSMILOverrideStyleRule();
virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule,
PRBool aNotify);

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

@ -3349,19 +3349,16 @@ nsGenericElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
}
#ifdef MOZ_SMIL
nsresult
nsGenericElement::GetSMILOverrideStyle(nsIDOMCSSStyleDeclaration** aStyle)
nsIDOMCSSStyleDeclaration*
nsGenericElement::GetSMILOverrideStyle()
{
nsGenericElement::nsDOMSlots *slots = DOMSlots();
if (!slots->mSMILOverrideStyle) {
slots->mSMILOverrideStyle = new nsDOMCSSAttributeDeclaration(this, PR_TRUE);
NS_ENSURE_TRUE(slots->mSMILOverrideStyle, NS_ERROR_OUT_OF_MEMORY);
}
// Why bother with QI?
NS_ADDREF(*aStyle = slots->mSMILOverrideStyle);
return NS_OK;
return slots->mSMILOverrideStyle;
}
css::StyleRule*
@ -3564,7 +3561,7 @@ nsINode::doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
rv = kid->GetNodeType(&nodeType);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOM3Document> domDoc = do_QueryInterface(GetOwnerDoc());
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(GetOwnerDoc());
// DocumentType nodes are the only nodes that can have a null
// ownerDocument according to the DOM spec, and we need to allow
@ -4075,7 +4072,7 @@ nsINode::ReplaceOrInsertBefore(PRBool aReplace, nsINode* aNewChild,
if (!HasSameOwnerDoc(newContent) &&
(nodeType != nsIDOMNode::DOCUMENT_TYPE_NODE ||
newContent->GetOwnerDoc())) {
nsCOMPtr<nsIDOM3Document> domDoc = do_QueryInterface(doc);
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
if (domDoc) {
nsresult rv;
@ -4766,7 +4763,7 @@ nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
stateMask ^= IntrinsicState();
if (document && !stateMask.IsEmpty()) {
MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, aNotify);
document->ContentStatesChanged(this, nsnull, stateMask);
document->ContentStateChanged(this, stateMask);
}
nsNodeUtils::AttributeChanged(this, aNamespaceID, aName, aModType);
}
@ -5013,7 +5010,7 @@ nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
stateMask ^= IntrinsicState();
if (document && !stateMask.IsEmpty()) {
MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, aNotify);
document->ContentStatesChanged(this, nsnull, stateMask);
document->ContentStateChanged(this, stateMask);
}
nsNodeUtils::AttributeChanged(this, aNameSpaceID, aName,
nsIDOMMutationEvent::REMOVAL);
@ -5486,8 +5483,7 @@ nsGenericElement::GetLinkTarget(nsAString& aTarget)
static nsresult
ParseSelectorList(nsINode* aNode,
const nsAString& aSelectorString,
nsCSSSelectorList** aSelectorList,
nsPresContext** aPresContext)
nsCSSSelectorList** aSelectorList)
{
NS_ENSURE_ARG(aNode);
@ -5518,117 +5514,9 @@ ParseSelectorList(nsINode* aNode,
} while (*slot);
*aSelectorList = selectorList;
// It's not strictly necessary to have a prescontext here, but it's
// a bit of an optimization for various stuff.
*aPresContext = nsnull;
nsIPresShell* shell = doc->GetShell();
if (shell) {
*aPresContext = shell->GetPresContext();
}
return NS_OK;
}
/*
* Callback to be called as we iterate over the tree and match elements. If
* the callbacks returns false, the iteration should be stopped.
*/
typedef PRBool
(* ElementMatchedCallback)(nsIContent* aMatchingElement, void* aClosure);
// returning false means stop iteration
static PRBool
TryMatchingElementsInSubtree(nsINode* aRoot,
RuleProcessorData* aParentData,
nsPresContext* aPresContext,
nsCSSSelectorList* aSelectorList,
ElementMatchedCallback aCallback,
void* aClosure)
{
/* To improve the performance of '+' and '~' combinators and the :nth-*
* selectors, we keep track of the immediately previous sibling data. That's
* cheaper than heap-allocating all the datas and keeping track of them all,
* and helps a good bit in the common cases. We also keep track of the whole
* parent data chain, since we have those Around anyway */
union { char c[2 * sizeof(RuleProcessorData)]; void *p; } databuf;
RuleProcessorData* prevSibling = nsnull;
RuleProcessorData* data = reinterpret_cast<RuleProcessorData*>(databuf.c);
PRBool continueIteration = PR_TRUE;
for (nsINode::ChildIterator iter(aRoot); !iter.IsDone(); iter.Next()) {
nsIContent* kid = iter;
if (!kid->IsElement()) {
continue;
}
/* See whether we match */
new (data) RuleProcessorData(aPresContext, kid->AsElement(), nsnull);
NS_ASSERTION(!data->mParentData, "Shouldn't happen");
NS_ASSERTION(!data->mPreviousSiblingData, "Shouldn't happen");
data->mParentData = aParentData;
data->mPreviousSiblingData = prevSibling;
if (nsCSSRuleProcessor::SelectorListMatches(*data, aSelectorList)) {
continueIteration = (*aCallback)(kid, aClosure);
}
if (continueIteration) {
continueIteration =
TryMatchingElementsInSubtree(kid, data, aPresContext, aSelectorList,
aCallback, aClosure);
}
/* Clear out the parent and previous sibling data if we set them, so that
* ~RuleProcessorData won't try to delete a placement-new'd object. Make
* sure this happens before our possible early break. Note that we can
* have null aParentData but non-null data->mParentData if we're scoped to
* an element. However, prevSibling and data->mPreviousSiblingData must
* always match.
*/
NS_ASSERTION(!aParentData || data->mParentData == aParentData,
"Unexpected parent");
NS_ASSERTION(data->mPreviousSiblingData == prevSibling,
"Unexpected prev sibling");
data->mPreviousSiblingData = nsnull;
if (prevSibling) {
if (aParentData) {
prevSibling->mParentData = nsnull;
}
prevSibling->~RuleProcessorData();
} else {
/* This is the first time through, so point |prevSibling| to the location
we want to have |data| end up pointing to. */
prevSibling = data + 1;
}
/* Now swap |prevSibling| and |data|. Again, before the early break */
RuleProcessorData* temp = prevSibling;
prevSibling = data;
data = temp;
if (!continueIteration) {
break;
}
}
if (prevSibling) {
if (aParentData) {
prevSibling->mParentData = nsnull;
}
/* Make sure to clean this up */
prevSibling->~RuleProcessorData();
}
return continueIteration;
}
static PRBool
FindFirstMatchingElement(nsIContent* aMatchingElement,
void* aClosure)
{
NS_PRECONDITION(aMatchingElement && aClosure, "How did that happen?");
nsIContent** slot = static_cast<nsIContent**>(aClosure);
*slot = aMatchingElement;
return PR_FALSE;
}
/* static */
nsIContent*
nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
@ -5637,26 +5525,25 @@ nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
NS_PRECONDITION(aResult, "Null out param?");
nsAutoPtr<nsCSSSelectorList> selectorList;
nsPresContext* presContext;
*aResult = ParseSelectorList(aRoot, aSelector,
getter_Transfers(selectorList),
&presContext);
getter_Transfers(selectorList));
NS_ENSURE_SUCCESS(*aResult, nsnull);
nsIContent* foundElement = nsnull;
TryMatchingElementsInSubtree(aRoot, nsnull, presContext, selectorList,
FindFirstMatchingElement, &foundElement);
TreeMatchContext matchingContext(PR_FALSE,
nsRuleWalker::eRelevantLinkUnvisited,
aRoot->GetOwnerDoc());
for (nsIContent* cur = aRoot->GetFirstChild();
cur;
cur = cur->GetNextNode(aRoot)) {
if (cur->IsElement() &&
nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
matchingContext,
selectorList)) {
return cur;
}
}
return foundElement;
}
static PRBool
AppendAllMatchingElements(nsIContent* aMatchingElement,
void* aClosure)
{
NS_PRECONDITION(aMatchingElement && aClosure, "How did that happen?");
static_cast<nsBaseContentList*>(aClosure)->AppendElement(aMatchingElement);
return PR_TRUE;
return nsnull;
}
/* static */
@ -5672,14 +5559,23 @@ nsGenericElement::doQuerySelectorAll(nsINode* aRoot,
NS_ADDREF(*aReturn = contentList);
nsAutoPtr<nsCSSSelectorList> selectorList;
nsPresContext* presContext;
nsresult rv = ParseSelectorList(aRoot, aSelector,
getter_Transfers(selectorList),
&presContext);
getter_Transfers(selectorList));
NS_ENSURE_SUCCESS(rv, rv);
TryMatchingElementsInSubtree(aRoot, nsnull, presContext, selectorList,
AppendAllMatchingElements, contentList);
TreeMatchContext matchingContext(PR_FALSE,
nsRuleWalker::eRelevantLinkUnvisited,
aRoot->GetOwnerDoc());
for (nsIContent* cur = aRoot->GetFirstChild();
cur;
cur = cur->GetNextNode(aRoot)) {
if (cur->IsElement() &&
nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
matchingContext,
selectorList)) {
contentList->AppendElement(cur);
}
}
return NS_OK;
}
@ -5688,15 +5584,16 @@ PRBool
nsGenericElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResult)
{
nsAutoPtr<nsCSSSelectorList> selectorList;
nsPresContext* presContext;
PRBool matches = PR_FALSE;
*aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList),
&presContext);
*aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList));
if (NS_SUCCEEDED(*aResult)) {
RuleProcessorData data(presContext, this, nsnull);
matches = nsCSSRuleProcessor::SelectorListMatches(data, selectorList);
TreeMatchContext matchingContext(PR_FALSE,
nsRuleWalker::eRelevantLinkUnvisited,
GetOwnerDoc());
matches = nsCSSRuleProcessor::SelectorListMatches(this, matchingContext,
selectorList);
}
return matches;

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

@ -455,7 +455,7 @@ public:
{
return nsnull;
}
virtual nsresult GetSMILOverrideStyle(nsIDOMCSSStyleDeclaration** aStyle);
virtual nsIDOMCSSStyleDeclaration* GetSMILOverrideStyle();
virtual mozilla::css::StyleRule* GetSMILOverrideStyleRule();
virtual nsresult SetSMILOverrideStyleRule(mozilla::css::StyleRule* aStyleRule,
PRBool aNotify);

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

@ -72,6 +72,9 @@
#include "nsIEditorDocShell.h"
#include "nsIEditor.h"
#include "nsIHTMLEditor.h"
#include "mozilla/dom/Element.h"
using namespace mozilla::dom;
static const PRInt32 kLongLineLen = 128;
@ -228,8 +231,8 @@ nsHTMLContentSerializer::SerializeHTMLAttributes(nsIContent* aContent,
}
NS_IMETHODIMP
nsHTMLContentSerializer::AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
nsHTMLContentSerializer::AppendElementStart(Element* aElement,
Element* aOriginalElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);
@ -342,7 +345,7 @@ nsHTMLContentSerializer::AppendElementStart(nsIContent *aElement,
}
NS_IMETHODIMP
nsHTMLContentSerializer::AppendElementEnd(nsIContent *aElement,
nsHTMLContentSerializer::AppendElementEnd(Element* aElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);

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

@ -57,11 +57,11 @@ class nsHTMLContentSerializer : public nsXHTMLContentSerializer {
nsHTMLContentSerializer();
virtual ~nsHTMLContentSerializer();
NS_IMETHOD AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
mozilla::dom::Element* aOriginalElement,
nsAString& aStr);
NS_IMETHOD AppendElementEnd(nsIContent *aElement,
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
nsAString& aStr);
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,

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

@ -829,7 +829,7 @@ nsImageLoadingContent::UpdateImageState(PRBool aNotify)
nsEventStates changedBits = oldState ^ ImageState();
if (!changedBits.IsEmpty()) {
mozAutoDocUpdate upd(doc, UPDATE_CONTENT_STATE, PR_TRUE);
doc->ContentStatesChanged(thisContent, nsnull, changedBits);
doc->ContentStateChanged(thisContent, changedBits);
}
}
}

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

@ -1657,7 +1657,7 @@ nsObjectLoadingContent::NotifyStateChanged(ObjectType aOldType,
{
mozAutoDocUpdate upd(doc, UPDATE_CONTENT_STATE, PR_TRUE);
doc->ContentStatesChanged(thisContent, nsnull, changedBits);
doc->ContentStateChanged(thisContent, changedBits);
}
if (aSync) {
// Make sure that frames are actually constructed, and do it after

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

@ -57,6 +57,9 @@
#include "nsUnicharUtils.h"
#include "nsCRT.h"
#include "nsIParserService.h"
#include "mozilla/dom/Element.h"
using namespace mozilla::dom;
#define PREF_STRUCTS "converter.html2txt.structs"
#define PREF_HEADER_STRATEGY "converter.html2txt.header_strategy"
@ -381,8 +384,8 @@ nsPlainTextSerializer::AppendCDATASection(nsIContent* aCDATASection,
}
NS_IMETHODIMP
nsPlainTextSerializer::AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
nsPlainTextSerializer::AppendElementStart(Element* aElement,
Element* aOriginalElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);
@ -414,7 +417,7 @@ nsPlainTextSerializer::AppendElementStart(nsIContent *aElement,
}
NS_IMETHODIMP
nsPlainTextSerializer::AppendElementEnd(nsIContent *aElement,
nsPlainTextSerializer::AppendElementEnd(Element* aElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);

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

@ -56,6 +56,12 @@
#include "nsIDocumentEncoder.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class Element;
} // namespace dom
} // namespace mozilla
class nsPlainTextSerializer : public nsIContentSerializer,
public nsIHTMLContentSink,
public nsIHTMLToTextSink
@ -84,10 +90,10 @@ public:
PRInt32 aEndOffset, nsAString& aStr) { return NS_OK; }
NS_IMETHOD AppendDoctype(nsIContent *aDoctype,
nsAString& aStr) { return NS_OK; }
NS_IMETHOD AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
mozilla::dom::Element* aOriginalElement,
nsAString& aStr);
NS_IMETHOD AppendElementEnd(nsIContent *aElement,
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
nsAString& aStr);
NS_IMETHOD Flush(nsAString& aStr);
@ -235,7 +241,7 @@ protected:
section.
mHeaderCounter[1] for <h1> etc. */
nsCOMPtr<nsIContent> mContent;
nsRefPtr<mozilla::dom::Element> mContent;
// For handling table rows
nsAutoTArray<PRPackedBool, 8> mHasWrittenCellsForRow;

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

@ -220,8 +220,8 @@ nsSyncLoader::LoadDocument(nsIChannel* aChannel,
}
if (aLoaderPrincipal) {
listener = new nsCrossSiteListenerProxy(listener, aLoaderPrincipal,
mChannel, PR_FALSE, &rv);
listener = new nsCORSListenerProxy(listener, aLoaderPrincipal,
mChannel, PR_FALSE, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
}

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

@ -48,6 +48,7 @@
#include "nsBidiUtils.h"
#include "nsUnicharUtils.h"
#include "nsUTF8Utils.h"
#include "mozilla/SSE.h"
#define TEXTFRAG_WHITE_AFTER_NEWLINE 50
#define TEXTFRAG_MAX_NEWLINES 7
@ -144,6 +145,69 @@ nsTextFragment::operator=(const nsTextFragment& aOther)
return *this;
}
static inline PRBool
Is8BitUnvectorized(const PRUnichar *str, const PRUnichar *end)
{
#if PR_BYTES_PER_WORD == 4
const size_t mask = 0xff00ff00;
const PRUint32 alignMask = 0x3;
const PRUint32 numUnicharsPerWord = 2;
#elif PR_BYTES_PER_WORD == 8
const size_t mask = 0xff00ff00ff00ff00;
const PRUint32 alignMask = 0x7;
const PRUint32 numUnicharsPerWord = 4;
#else
#error Unknown platform!
#endif
const PRInt32 len = end - str;
PRInt32 i = 0;
// Align ourselves to a word boundary.
PRInt32 alignLen =
PR_MIN(len, PRInt32(((-NS_PTR_TO_UINT32(str)) & alignMask) / sizeof(PRUnichar)));
for (; i < alignLen; i++) {
if (str[i] > 255)
return PR_FALSE;
}
// Check one word at a time.
const PRInt32 wordWalkEnd = ((len - i) / numUnicharsPerWord) * numUnicharsPerWord;
for (; i < wordWalkEnd; i += numUnicharsPerWord) {
const size_t word = *reinterpret_cast<const size_t*>(str + i);
if (word & mask)
return PR_FALSE;
}
// Take care of the remainder one character at a time.
for (; i < len; i++) {
if (str[i] > 255)
return PR_FALSE;
}
return PR_TRUE;
}
#ifdef MOZILLA_MAY_SUPPORT_SSE2
namespace mozilla {
namespace SSE2 {
PRBool Is8Bit(const PRUnichar *str, const PRUnichar *end);
}
}
#endif
static inline PRBool
Is8Bit(const PRUnichar *str, const PRUnichar *end)
{
#ifdef MOZILLA_MAY_SUPPORT_SSE2
if (mozilla::supports_sse2()) {
return mozilla::SSE2::Is8Bit(str, end);
}
#endif
return Is8BitUnvectorized(str, end);
}
void
nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength)
{
@ -203,14 +267,7 @@ nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength)
}
// See if we need to store the data in ucs2 or not
PRBool need2 = PR_FALSE;
while (ucp < uend) {
PRUnichar ch = *ucp++;
if (ch >= 256) {
need2 = PR_TRUE;
break;
}
}
PRBool need2 = !Is8Bit(ucp, uend);
if (need2) {
// Use ucs2 storage because we have to
@ -227,9 +284,7 @@ nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength)
}
// Copy data
// Use the same copying code we use elsewhere; it's likely to be
// carefully tuned.
LossyConvertEncoding<PRUnichar, char> converter(buff);
LossyConvertEncoding16to8 converter(buff);
copy_string(aBuffer, aBuffer+aLength, converter);
m1b = buff;
}
@ -260,9 +315,8 @@ nsTextFragment::CopyTo(PRUnichar *aDest, PRInt32 aOffset, PRInt32 aCount)
} else {
const char *cp = m1b + aOffset;
const char *end = cp + aCount;
while (cp < end) {
*aDest++ = (unsigned char)(*cp++);
}
LossyConvertEncoding8to16 converter(aDest);
copy_string(cp, end, converter);
}
}
}
@ -296,18 +350,7 @@ nsTextFragment::Append(const PRUnichar* aBuffer, PRUint32 aLength)
// Current string is a 1-byte string, check if the new data fits in one byte too.
const PRUnichar* ucp = aBuffer;
const PRUnichar* uend = ucp + aLength;
PRBool need2 = PR_FALSE;
while (ucp < uend) {
PRUnichar ch = *ucp++;
if (ch >= 256) {
need2 = PR_TRUE;
break;
}
}
if (need2) {
if (!Is8Bit(aBuffer, aBuffer + aLength)) {
// The old data was 1-byte, but the new is not so we have to expand it
// all to 2-byte
PRUnichar* buff = (PRUnichar*)nsMemory::Alloc((mState.mLength + aLength) *
@ -316,11 +359,10 @@ nsTextFragment::Append(const PRUnichar* aBuffer, PRUint32 aLength)
return;
}
// Copy data
for (PRUint32 i = 0; i < mState.mLength; ++i) {
buff[i] = (unsigned char)m1b[i];
}
// Copy data into buff
LossyConvertEncoding8to16 converter(buff);
copy_string(m1b, m1b+mState.mLength, converter);
memcpy(buff + mState.mLength, aBuffer, aLength * sizeof(PRUnichar));
mState.mLength += aLength;
@ -354,10 +396,10 @@ nsTextFragment::Append(const PRUnichar* aBuffer, PRUint32 aLength)
memcpy(buff, m1b, mState.mLength);
mState.mInHeap = PR_TRUE;
}
for (PRUint32 i = 0; i < aLength; ++i) {
buff[mState.mLength + i] = (char)aBuffer[i];
}
// Copy aBuffer into buff.
LossyConvertEncoding16to8 converter(buff + mState.mLength);
copy_string(aBuffer, aBuffer + aLength, converter);
m1b = buff;
mState.mLength += aLength;

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

@ -0,0 +1,72 @@
// This file should only be compiled if you're on x86 or x86_64. Additionally,
// you'll need to compile this file with -msse2 if you're using gcc.
#include <emmintrin.h>
#include "nscore.h"
namespace mozilla {
namespace SSE2 {
static inline bool
is_zero (__m128i x)
{
return
_mm_movemask_epi8(_mm_cmpeq_epi8(x, _mm_setzero_si128())) == 0xffff;
}
PRBool
Is8Bit(const PRUnichar *str, const PRUnichar *end)
{
const PRUint32 numUnicharsPerVector = 8;
#if PR_BYTES_PER_WORD == 4
const size_t mask = 0xff00ff00;
const PRUint32 numUnicharsPerWord = 2;
#elif PR_BYTES_PER_WORD == 8
const size_t mask = 0xff00ff00ff00ff00;
const PRUint32 numUnicharsPerWord = 4;
#else
#error Unknown platform!
#endif
const PRInt32 len = end - str;
PRInt32 i = 0;
// Align ourselves to a 16-byte boundary, as required by _mm_load_si128
// (i.e. MOVDQA).
PRInt32 alignLen =
PR_MIN(len, PRInt32(((-NS_PTR_TO_UINT32(str)) & 0xf) / sizeof(PRUnichar)));
for (; i < alignLen; i++) {
if (str[i] > 255)
return PR_FALSE;
}
// Check one XMM register (16 bytes) at a time.
const PRInt32 vectWalkEnd = ((len - i) / numUnicharsPerVector) * numUnicharsPerVector;
__m128i vectmask = _mm_set1_epi16(0xff00);
for(; i < vectWalkEnd; i += numUnicharsPerVector) {
const __m128i vect = *reinterpret_cast<const __m128i*>(str + i);
if (!is_zero(_mm_and_si128(vect, vectmask)))
return PR_FALSE;
}
// Check one word at a time.
const PRInt32 wordWalkEnd = ((len - i) / numUnicharsPerWord) * numUnicharsPerWord;
for(; i < wordWalkEnd; i += numUnicharsPerWord) {
const size_t word = *reinterpret_cast<const size_t*>(str + i);
if (word & mask)
return PR_FALSE;
}
// Take care of the remainder one character at a time.
for (; i < len; i++) {
if (str[i] > 255) {
return PR_FALSE;
}
}
return PR_TRUE;
}
} // namespace SSE2
} // namespace mozilla

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

@ -64,6 +64,9 @@
#include "nsContentUtils.h"
#include "nsAttrName.h"
#include "nsILineBreaker.h"
#include "mozilla/dom/Element.h"
using namespace mozilla::dom;
static const char kMozStr[] = "moz";
@ -915,8 +918,8 @@ nsXMLContentSerializer::SerializeAttributes(nsIContent* aContent,
}
NS_IMETHODIMP
nsXMLContentSerializer::AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
nsXMLContentSerializer::AppendElementStart(Element* aElement,
Element* aOriginalElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);
@ -1016,7 +1019,7 @@ nsXMLContentSerializer::AppendEndOfElementStart(nsIContent *aOriginalElement,
}
NS_IMETHODIMP
nsXMLContentSerializer::AppendElementEnd(nsIContent *aElement,
nsXMLContentSerializer::AppendElementEnd(Element* aElement,
nsAString& aStr)
{
NS_ENSURE_ARG(aElement);

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

@ -88,11 +88,11 @@ class nsXMLContentSerializer : public nsIContentSerializer {
NS_IMETHOD AppendDoctype(nsIContent *aDoctype,
nsAString& aStr);
NS_IMETHOD AppendElementStart(nsIContent *aElement,
nsIContent *aOriginalElement,
NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
mozilla::dom::Element* aOriginalElement,
nsAString& aStr);
NS_IMETHOD AppendElementEnd(nsIContent *aElement,
NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
nsAString& aStr);
NS_IMETHOD Flush(nsAString& aStr) { return NS_OK; }

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

@ -87,7 +87,6 @@
#include "nsCrossSiteListenerProxy.h"
#include "nsDOMError.h"
#include "nsIHTMLDocument.h"
#include "nsIDOM3Document.h"
#include "nsIMultiPartChannel.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIStorageStream.h"
@ -146,8 +145,6 @@
XML_HTTP_REQUEST_SENT | \
XML_HTTP_REQUEST_STOPPED)
#define ACCESS_CONTROL_CACHE_SIZE 100
#define NS_BADCERTHANDLER_CONTRACTID \
"@mozilla.org/content/xmlhttprequest-bad-cert-handler;1"
@ -286,225 +283,6 @@ nsMultipartProxyListener::OnDataAvailable(nsIRequest *aRequest,
count);
}
// Class used as streamlistener and notification callback when
// doing the initial GET request for an access-control check
class nsACProxyListener : public nsIStreamListener,
public nsIInterfaceRequestor,
public nsIChannelEventSink
{
public:
nsACProxyListener(nsIChannel* aOuterChannel,
nsIStreamListener* aOuterListener,
nsISupports* aOuterContext,
nsIPrincipal* aReferrerPrincipal,
const nsACString& aRequestMethod,
PRBool aWithCredentials)
: mOuterChannel(aOuterChannel), mOuterListener(aOuterListener),
mOuterContext(aOuterContext), mReferrerPrincipal(aReferrerPrincipal),
mRequestMethod(aRequestMethod), mWithCredentials(aWithCredentials)
{ }
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
private:
void AddResultToCache(nsIRequest* aRequest);
nsCOMPtr<nsIChannel> mOuterChannel;
nsCOMPtr<nsIStreamListener> mOuterListener;
nsCOMPtr<nsISupports> mOuterContext;
nsCOMPtr<nsIPrincipal> mReferrerPrincipal;
nsCString mRequestMethod;
PRBool mWithCredentials;
};
NS_IMPL_ISUPPORTS4(nsACProxyListener, nsIStreamListener, nsIRequestObserver,
nsIInterfaceRequestor, nsIChannelEventSink)
void
nsACProxyListener::AddResultToCache(nsIRequest *aRequest)
{
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
NS_ASSERTION(http, "Request was not http");
// The "Access-Control-Max-Age" header should return an age in seconds.
nsCAutoString headerVal;
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Max-Age"),
headerVal);
if (headerVal.IsEmpty()) {
return;
}
// Sanitize the string. We only allow 'delta-seconds' as specified by
// http://dev.w3.org/2006/waf/access-control (digits 0-9 with no leading or
// trailing non-whitespace characters).
PRUint32 age = 0;
nsCSubstring::const_char_iterator iter, end;
headerVal.BeginReading(iter);
headerVal.EndReading(end);
while (iter != end) {
if (*iter < '0' || *iter > '9') {
return;
}
age = age * 10 + (*iter - '0');
// Cap at 24 hours. This also avoids overflow
age = NS_MIN(age, 86400U);
++iter;
}
if (!age || !nsXMLHttpRequest::EnsureACCache()) {
return;
}
// String seems fine, go ahead and cache.
// Note that we have already checked that these headers follow the correct
// syntax.
nsCOMPtr<nsIURI> uri;
NS_GetFinalChannelURI(http, getter_AddRefs(uri));
// PR_Now gives microseconds
PRTime expirationTime = PR_Now() + (PRUint64)age * PR_USEC_PER_SEC;
nsAccessControlLRUCache::CacheEntry* entry =
nsXMLHttpRequest::sAccessControlCache->
GetEntry(uri, mReferrerPrincipal, mWithCredentials, PR_TRUE);
if (!entry) {
return;
}
// The "Access-Control-Allow-Methods" header contains a comma separated
// list of method names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Methods"),
headerVal);
nsCCharSeparatedTokenizer methods(headerVal, ',');
while(methods.hasMoreTokens()) {
const nsDependentCSubstring& method = methods.nextToken();
if (method.IsEmpty()) {
continue;
}
PRUint32 i;
for (i = 0; i < entry->mMethods.Length(); ++i) {
if (entry->mMethods[i].token.Equals(method)) {
entry->mMethods[i].expirationTime = expirationTime;
break;
}
}
if (i == entry->mMethods.Length()) {
nsAccessControlLRUCache::TokenTime* newMethod =
entry->mMethods.AppendElement();
if (!newMethod) {
return;
}
newMethod->token = method;
newMethod->expirationTime = expirationTime;
}
}
// The "Access-Control-Allow-Headers" header contains a comma separated
// list of method names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Headers"),
headerVal);
nsCCharSeparatedTokenizer headers(headerVal, ',');
while(headers.hasMoreTokens()) {
const nsDependentCSubstring& header = headers.nextToken();
if (header.IsEmpty()) {
continue;
}
PRUint32 i;
for (i = 0; i < entry->mHeaders.Length(); ++i) {
if (entry->mHeaders[i].token.Equals(header)) {
entry->mHeaders[i].expirationTime = expirationTime;
break;
}
}
if (i == entry->mHeaders.Length()) {
nsAccessControlLRUCache::TokenTime* newHeader =
entry->mHeaders.AppendElement();
if (!newHeader) {
return;
}
newHeader->token = header;
newHeader->expirationTime = expirationTime;
}
}
}
NS_IMETHODIMP
nsACProxyListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
{
nsresult status;
nsresult rv = aRequest->GetStatus(&status);
if (NS_SUCCEEDED(rv)) {
rv = status;
}
if (NS_SUCCEEDED(rv)) {
// Everything worked, try to cache and then fire off the actual request.
AddResultToCache(aRequest);
rv = mOuterChannel->AsyncOpen(mOuterListener, mOuterContext);
}
if (NS_FAILED(rv)) {
mOuterChannel->Cancel(rv);
mOuterListener->OnStartRequest(mOuterChannel, mOuterContext);
mOuterListener->OnStopRequest(mOuterChannel, mOuterContext, rv);
return rv;
}
return NS_OK;
}
NS_IMETHODIMP
nsACProxyListener::OnStopRequest(nsIRequest *aRequest, nsISupports *aContext,
nsresult aStatus)
{
return NS_OK;
}
/** nsIStreamListener methods **/
NS_IMETHODIMP
nsACProxyListener::OnDataAvailable(nsIRequest *aRequest,
nsISupports *ctxt,
nsIInputStream *inStr,
PRUint32 sourceOffset,
PRUint32 count)
{
return NS_OK;
}
NS_IMETHODIMP
nsACProxyListener::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
nsIChannel *aNewChannel,
PRUint32 aFlags,
nsIAsyncVerifyRedirectCallback *callback)
{
// Only internal redirects allowed for now.
if (!NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags))
return NS_ERROR_DOM_BAD_URI;
callback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
NS_IMETHODIMP
nsACProxyListener::GetInterface(const nsIID & aIID, void **aResult)
{
return QueryInterface(aIID, aResult);
}
/////////////////////////////////////////////
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXHREventTarget)
@ -633,219 +411,11 @@ NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
NS_IMPL_ADDREF_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
NS_IMPL_RELEASE_INHERITED(nsXMLHttpRequestUpload, nsXHREventTarget)
void
nsAccessControlLRUCache::CacheEntry::PurgeExpired(PRTime now)
{
PRUint32 i;
for (i = 0; i < mMethods.Length(); ++i) {
if (now >= mMethods[i].expirationTime) {
mMethods.RemoveElementAt(i--);
}
}
for (i = 0; i < mHeaders.Length(); ++i) {
if (now >= mHeaders[i].expirationTime) {
mHeaders.RemoveElementAt(i--);
}
}
}
PRBool
nsAccessControlLRUCache::CacheEntry::CheckRequest(const nsCString& aMethod,
const nsTArray<nsCString>& aHeaders)
{
PurgeExpired(PR_Now());
if (!aMethod.EqualsLiteral("GET") && !aMethod.EqualsLiteral("POST")) {
PRUint32 i;
for (i = 0; i < mMethods.Length(); ++i) {
if (aMethod.Equals(mMethods[i].token))
break;
}
if (i == mMethods.Length()) {
return PR_FALSE;
}
}
for (PRUint32 i = 0; i < aHeaders.Length(); ++i) {
PRUint32 j;
for (j = 0; j < mHeaders.Length(); ++j) {
if (aHeaders[i].Equals(mHeaders[j].token,
nsCaseInsensitiveCStringComparator())) {
break;
}
}
if (j == mHeaders.Length()) {
return PR_FALSE;
}
}
return PR_TRUE;
}
nsAccessControlLRUCache::CacheEntry*
nsAccessControlLRUCache::GetEntry(nsIURI* aURI,
nsIPrincipal* aPrincipal,
PRBool aWithCredentials,
PRBool aCreate)
{
nsCString key;
if (!GetCacheKey(aURI, aPrincipal, aWithCredentials, key)) {
NS_WARNING("Invalid cache key!");
return nsnull;
}
CacheEntry* entry;
if (mTable.Get(key, &entry)) {
// Entry already existed so just return it. Also update the LRU list.
// Move to the head of the list.
PR_REMOVE_LINK(entry);
PR_INSERT_LINK(entry, &mList);
return entry;
}
if (!aCreate) {
return nsnull;
}
// This is a new entry, allocate and insert into the table now so that any
// failures don't cause items to be removed from a full cache.
entry = new CacheEntry(key);
if (!entry) {
NS_WARNING("Failed to allocate new cache entry!");
return nsnull;
}
if (!mTable.Put(key, entry)) {
// Failed, clean up the new entry.
delete entry;
NS_WARNING("Failed to add entry to the access control cache!");
return nsnull;
}
PR_INSERT_LINK(entry, &mList);
NS_ASSERTION(mTable.Count() <= ACCESS_CONTROL_CACHE_SIZE + 1,
"Something is borked, too many entries in the cache!");
// Now enforce the max count.
if (mTable.Count() > ACCESS_CONTROL_CACHE_SIZE) {
// Try to kick out all the expired entries.
PRTime now = PR_Now();
mTable.Enumerate(RemoveExpiredEntries, &now);
// If that didn't remove anything then kick out the least recently used
// entry.
if (mTable.Count() > ACCESS_CONTROL_CACHE_SIZE) {
CacheEntry* lruEntry = static_cast<CacheEntry*>(PR_LIST_TAIL(&mList));
PR_REMOVE_LINK(lruEntry);
// This will delete 'lruEntry'.
mTable.Remove(lruEntry->mKey);
NS_ASSERTION(mTable.Count() == ACCESS_CONTROL_CACHE_SIZE,
"Somehow tried to remove an entry that was never added!");
}
}
return entry;
}
void
nsAccessControlLRUCache::RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal)
{
CacheEntry* entry;
nsCString key;
if (GetCacheKey(aURI, aPrincipal, PR_TRUE, key) &&
mTable.Get(key, &entry)) {
PR_REMOVE_LINK(entry);
mTable.Remove(key);
}
if (GetCacheKey(aURI, aPrincipal, PR_FALSE, key) &&
mTable.Get(key, &entry)) {
PR_REMOVE_LINK(entry);
mTable.Remove(key);
}
}
void
nsAccessControlLRUCache::Clear()
{
PR_INIT_CLIST(&mList);
mTable.Clear();
}
/* static */ PLDHashOperator
nsAccessControlLRUCache::RemoveExpiredEntries(const nsACString& aKey,
nsAutoPtr<CacheEntry>& aValue,
void* aUserData)
{
PRTime* now = static_cast<PRTime*>(aUserData);
aValue->PurgeExpired(*now);
if (aValue->mHeaders.IsEmpty() &&
aValue->mHeaders.IsEmpty()) {
// Expired, remove from the list as well as the hash table.
PR_REMOVE_LINK(aValue);
return PL_DHASH_REMOVE;
}
return PL_DHASH_NEXT;
}
/* static */ PRBool
nsAccessControlLRUCache::GetCacheKey(nsIURI* aURI,
nsIPrincipal* aPrincipal,
PRBool aWithCredentials,
nsACString& _retval)
{
NS_ASSERTION(aURI, "Null uri!");
NS_ASSERTION(aPrincipal, "Null principal!");
NS_NAMED_LITERAL_CSTRING(space, " ");
nsCOMPtr<nsIURI> uri;
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, PR_FALSE);
nsCAutoString scheme, host, port;
if (uri) {
uri->GetScheme(scheme);
uri->GetHost(host);
port.AppendInt(NS_GetRealPort(uri));
}
nsCAutoString cred;
if (aWithCredentials) {
_retval.AssignLiteral("cred");
}
else {
_retval.AssignLiteral("nocred");
}
nsCAutoString spec;
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
_retval.Assign(cred + space + scheme + space + host + space + port + space +
spec);
return PR_TRUE;
}
/////////////////////////////////////////////
//
//
/////////////////////////////////////////////
// Will be initialized in nsXMLHttpRequest::EnsureACCache.
nsAccessControlLRUCache* nsXMLHttpRequest::sAccessControlCache = nsnull;
nsXMLHttpRequest::nsXMLHttpRequest()
: mRequestObserver(nsnull), mState(XML_HTTP_REQUEST_UNINITIALIZED),
mUploadTransferred(0), mUploadTotal(0), mUploadComplete(PR_TRUE),
@ -985,7 +555,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLHttpRequest,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mReadRequest)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mResponseXML)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mACGetChannel)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCORSPreflightChannel)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnUploadProgressListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnReadystatechangeListener)
@ -1006,7 +576,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest,
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReadRequest)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mResponseXML)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mACGetChannel)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCORSPreflightChannel)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnUploadProgressListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnReadystatechangeListener)
@ -1363,8 +933,8 @@ nsXMLHttpRequest::Abort()
if (mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED);
}
if (mACGetChannel) {
mACGetChannel->Cancel(NS_BINDING_ABORTED);
if (mCORSPreflightChannel) {
mCORSPreflightChannel->Cancel(NS_BINDING_ABORTED);
}
mResponseXML = nsnull;
PRUint32 responseLength = mResponseBody.Length();
@ -1390,7 +960,7 @@ nsXMLHttpRequest::Abort()
}
// The ChangeState call above calls onreadystatechange handlers which
// if they load a new url will cause nsXMLHttpRequest::OpenRequest to clear
// if they load a new url will cause nsXMLHttpRequest::Open to clear
// the abort state bit. If this occurs we're not uninitialized (bug 361773).
if (mState & XML_HTTP_REQUEST_ABORTED) {
ChangeState(XML_HTTP_REQUEST_UNINITIALIZED, PR_FALSE); // IE seems to do it
@ -1655,7 +1225,7 @@ nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
nsCAutoString method;
httpChannel->GetRequestMethod(method);
if (!mACUnsafeHeaders.IsEmpty() ||
if (!mCORSUnsafeHeaders.IsEmpty() ||
HasListenersFor(NS_LITERAL_STRING(UPLOADPROGRESS_STR)) ||
(mUpload && mUpload->HasListeners()) ||
(!method.LowerCaseEqualsLiteral("get") &&
@ -1667,16 +1237,18 @@ nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
return NS_OK;
}
/* noscript void openRequest (in AUTF8String method, in AUTF8String url, in boolean async, in AString user, in AString password); */
NS_IMETHODIMP
nsXMLHttpRequest::OpenRequest(const nsACString& method,
const nsACString& url,
PRBool async,
const nsAString& user,
const nsAString& password)
nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url,
PRBool async, const nsAString& user,
const nsAString& password, PRUint8 optional_argc)
{
NS_ENSURE_ARG(!method.IsEmpty());
if (!optional_argc) {
// No optional arguments were passed in. Default async to true.
async = PR_TRUE;
}
NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
// Disallow HTTP/1.1 TRACE method (see bug 302489)
@ -1806,20 +1378,6 @@ nsXMLHttpRequest::OpenRequest(const nsACString& method,
return rv;
}
/* void open (in AUTF8String method, in AUTF8String url); */
NS_IMETHODIMP
nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url,
PRBool async, const nsAString& user,
const nsAString& password, PRUint8 optional_argc)
{
if (!optional_argc) {
// No optional arguments were passed in. Default async to true.
async = PR_TRUE;
}
return OpenRequest(method, url, async, user, password);
}
/*
* "Copy" from a stream.
*/
@ -2279,13 +1837,10 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult,
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(supports);
if (doc) {
aContentType.AssignLiteral("application/xml");
nsCOMPtr<nsIDOM3Document> dom3doc = do_QueryInterface(doc);
if (dom3doc) {
nsAutoString inputEncoding;
dom3doc->GetInputEncoding(inputEncoding);
if (!DOMStringIsNull(inputEncoding)) {
CopyUTF16toUTF8(inputEncoding, aCharset);
}
nsAutoString inputEncoding;
doc->GetInputEncoding(inputEncoding);
if (!DOMStringIsNull(inputEncoding)) {
CopyUTF16toUTF8(inputEncoding, aCharset);
}
// Serialize to a stream so that the encoding used will
@ -2571,7 +2126,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
if (!contentType.LowerCaseEqualsLiteral("text/plain") &&
!contentType.LowerCaseEqualsLiteral("application/x-www-form-urlencoded") &&
!contentType.LowerCaseEqualsLiteral("multipart/form-data")) {
mACUnsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
mCORSUnsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
}
}
}
@ -2588,41 +2143,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
PRBool withCredentials = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
// If so, set up the preflight
if (mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT) {
// Check to see if this initial OPTIONS request has already been cached
// in our special Access Control Cache.
nsCOMPtr<nsIURI> uri;
rv = NS_GetFinalChannelURI(mChannel, getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
nsAccessControlLRUCache::CacheEntry* entry =
sAccessControlCache ?
sAccessControlCache->GetEntry(uri, mPrincipal, withCredentials, PR_FALSE) :
nsnull;
if (!entry || !entry->CheckRequest(method, mACUnsafeHeaders)) {
// Either it wasn't cached or the cached result has expired. Build a
// channel for the OPTIONS request.
nsCOMPtr<nsILoadGroup> loadGroup;
GetLoadGroup(getter_AddRefs(loadGroup));
nsLoadFlags loadFlags;
rv = mChannel->GetLoadFlags(&loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_NewChannel(getter_AddRefs(mACGetChannel), uri, nsnull,
loadGroup, nsnull, loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHttpChannel> acHttp = do_QueryInterface(mACGetChannel);
NS_ASSERTION(acHttp, "Failed to QI to nsIHttpChannel!");
rv = acHttp->SetRequestMethod(NS_LITERAL_CSTRING("OPTIONS"));
NS_ENSURE_SUCCESS(rv, rv);
}
}
// Hook us up to listen to redirects and the like
mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
mChannel->SetNotificationCallbacks(this);
@ -2637,10 +2157,10 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
}
if (!IsSystemXHR()) {
// Always create a nsCrossSiteListenerProxy here even if it's
// Always create a nsCORSListenerProxy here even if it's
// a same-origin request right now, since it could be redirected.
listener = new nsCrossSiteListenerProxy(listener, mPrincipal, mChannel,
withCredentials, &rv);
listener = new nsCORSListenerProxy(listener, mPrincipal, mChannel,
withCredentials, &rv);
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -2661,10 +2181,6 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
else if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
AddLoadFlags(mChannel,
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
if (mACGetChannel) {
AddLoadFlags(mACGetChannel,
nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
}
}
// Since we expect XML data, set the type hint accordingly
@ -2672,22 +2188,16 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
// ignoring return value, as this is not critical
mChannel->SetContentType(NS_LITERAL_CSTRING("application/xml"));
// If we're doing a cross-site non-GET request we need to first do
// a GET request to the same URI. Set that up if needed
if (mACGetChannel) {
nsCOMPtr<nsIStreamListener> acProxyListener =
new nsACProxyListener(mChannel, listener, nsnull, mPrincipal, method,
withCredentials);
NS_ENSURE_TRUE(acProxyListener, NS_ERROR_OUT_OF_MEMORY);
// Set up the preflight if needed
if (mState & XML_HTTP_REQUEST_NEED_AC_PREFLIGHT) {
// Check to see if this initial OPTIONS request has already been cached
// in our special Access Control Cache.
acProxyListener =
new nsCrossSiteListenerProxy(acProxyListener, mPrincipal, mACGetChannel,
withCredentials, method, mACUnsafeHeaders,
&rv);
NS_ENSURE_TRUE(acProxyListener, NS_ERROR_OUT_OF_MEMORY);
rv = NS_StartCORSPreflight(mChannel, listener,
mPrincipal, withCredentials,
mCORSUnsafeHeaders,
getter_AddRefs(mCORSPreflightChannel));
NS_ENSURE_SUCCESS(rv, rv);
rv = mACGetChannel->AsyncOpen(acProxyListener, nsnull);
}
else {
// Start reading from the channel
@ -2697,7 +2207,7 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
if (NS_FAILED(rv)) {
// Drop our ref to the channel to avoid cycles
mChannel = nsnull;
mACGetChannel = nsnull;
mCORSPreflightChannel = nsnull;
return rv;
}
@ -2774,17 +2284,17 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
{
nsresult rv;
// Make sure we don't store an invalid header name in mACUnsafeHeaders
// Make sure we don't store an invalid header name in mCORSUnsafeHeaders
if (!IsValidHTTPToken(header)) {
return NS_ERROR_FAILURE;
}
// Check that we haven't already opened the channel. We can't rely on
// the channel throwing from mChannel->SetRequestHeader since we might
// still be waiting for mACGetChannel to actually open mChannel
if (mACGetChannel) {
// still be waiting for mCORSPreflightChannel to actually open mChannel
if (mCORSPreflightChannel) {
PRBool pending;
rv = mACGetChannel->IsPending(&pending);
rv = mCORSPreflightChannel->IsPending(&pending);
NS_ENSURE_SUCCESS(rv, rv);
if (pending) {
@ -2849,7 +2359,7 @@ nsXMLHttpRequest::SetRequestHeader(const nsACString& header,
}
if (!safeHeader) {
mACUnsafeHeaders.AppendElement(header);
mCORSUnsafeHeaders.AppendElement(header);
}
}

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

@ -60,10 +60,6 @@
#include "nsTArray.h"
#include "nsIJSNativeInitializer.h"
#include "nsIDOMLSProgressEvent.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "prclist.h"
#include "prtime.h"
#include "nsIDOMNSEvent.h"
#include "nsITimer.h"
#include "nsIPrivateDOMEvent.h"
@ -74,72 +70,6 @@
class nsILoadGroup;
class AsyncVerifyRedirectCallbackForwarder;
class nsAccessControlLRUCache
{
public:
struct TokenTime
{
nsCString token;
PRTime expirationTime;
};
struct CacheEntry : public PRCList
{
CacheEntry(nsCString& aKey)
: mKey(aKey)
{
MOZ_COUNT_CTOR(nsAccessControlLRUCache::CacheEntry);
}
~CacheEntry()
{
MOZ_COUNT_DTOR(nsAccessControlLRUCache::CacheEntry);
}
void PurgeExpired(PRTime now);
PRBool CheckRequest(const nsCString& aMethod,
const nsTArray<nsCString>& aCustomHeaders);
nsCString mKey;
nsTArray<TokenTime> mMethods;
nsTArray<TokenTime> mHeaders;
};
nsAccessControlLRUCache()
{
MOZ_COUNT_CTOR(nsAccessControlLRUCache);
PR_INIT_CLIST(&mList);
}
~nsAccessControlLRUCache()
{
Clear();
MOZ_COUNT_DTOR(nsAccessControlLRUCache);
}
PRBool Initialize()
{
return mTable.Init();
}
CacheEntry* GetEntry(nsIURI* aURI, nsIPrincipal* aPrincipal,
PRBool aWithCredentials, PRBool aCreate);
void RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal);
void Clear();
private:
static PLDHashOperator
RemoveExpiredEntries(const nsACString& aKey, nsAutoPtr<CacheEntry>& aValue,
void* aUserData);
static PRBool GetCacheKey(nsIURI* aURI, nsIPrincipal* aPrincipal,
PRBool aWithCredentials, nsACString& _retval);
nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
PRCList mList;
};
class nsXHREventTarget : public nsDOMEventTargetWrapperCache,
public nsIXMLHttpRequestEventTarget
{
@ -281,32 +211,8 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXMLHttpRequest,
nsXHREventTarget)
static PRBool EnsureACCache()
{
if (sAccessControlCache)
return PR_TRUE;
nsAutoPtr<nsAccessControlLRUCache> newCache(new nsAccessControlLRUCache());
NS_ENSURE_TRUE(newCache, PR_FALSE);
if (newCache->Initialize()) {
sAccessControlCache = newCache.forget();
return PR_TRUE;
}
return PR_FALSE;
}
static void ShutdownACCache()
{
delete sAccessControlCache;
sAccessControlCache = nsnull;
}
PRBool AllowUploadProgress();
static nsAccessControlLRUCache* sAccessControlCache;
protected:
friend class nsMultipartProxyListener;
@ -357,8 +263,8 @@ protected:
// mReadRequest is different from mChannel for multipart requests
nsCOMPtr<nsIRequest> mReadRequest;
nsCOMPtr<nsIDOMDocument> mResponseXML;
nsCOMPtr<nsIChannel> mACGetChannel;
nsTArray<nsCString> mACUnsafeHeaders;
nsCOMPtr<nsIChannel> mCORSPreflightChannel;
nsTArray<nsCString> mCORSUnsafeHeaders;
nsRefPtr<nsDOMEventListenerWrapper> mOnUploadProgressListener;
nsRefPtr<nsDOMEventListenerWrapper> mOnReadystatechangeListener;

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

@ -280,6 +280,7 @@ _TEST_FILES1 = test_bug5141.html \
file_XHRDocURI.xml^headers^ \
file_XHRDocURI.text \
file_XHRDocURI.text^headers^ \
test_DOMException.html \
$(NULL)
_TEST_FILES2 = \
@ -431,6 +432,7 @@ _TEST_FILES2 = \
test_bug567350.html \
test_bug574596.html \
test_bug578096.html \
test_bug585978.html \
test_bug592366.html \
test_bug597345.html \
script-1_bug597345.sjs \

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

@ -76,7 +76,7 @@ nsresult TestGetURL(const nsCString& aURL)
rv = xhr->Init(systemPrincipal, nsnull, nsnull, nsnull);
TEST_ENSURE_SUCCESS(rv, "Couldn't initialize the XHR!");
rv = xhr->OpenRequest(getString, aURL, PR_FALSE, empty, empty);
rv = xhr->Open(getString, aURL, PR_FALSE, empty, empty);
TEST_ENSURE_SUCCESS(rv, "OpenRequest failed!");
rv = xhr->Send(nsnull);

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

@ -77,9 +77,9 @@ nsresult TestNativeXMLHttpRequest()
const nsAString& empty = EmptyString();
printf("*** About to see an expected warning about mPrincipal:\n");
rv = xhr->OpenRequest(getString, testURL, PR_FALSE, empty, empty);
rv = xhr->Open(getString, testURL, PR_FALSE, empty, empty);
printf("*** End of expected warning output.\n");
TEST_ENSURE_FAILED(rv, "OpenRequest should have failed!");
TEST_ENSURE_FAILED(rv, "Open should have failed!");
nsCOMPtr<nsIScriptSecurityManager> secman =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
@ -92,8 +92,8 @@ nsresult TestNativeXMLHttpRequest()
rv = xhr->Init(systemPrincipal, nsnull, nsnull, nsnull);
TEST_ENSURE_SUCCESS(rv, "Couldn't initialize the XHR!");
rv = xhr->OpenRequest(getString, testURL, PR_FALSE, empty, empty);
TEST_ENSURE_SUCCESS(rv, "OpenRequest failed!");
rv = xhr->Open(getString, testURL, PR_FALSE, empty, empty);
TEST_ENSURE_SUCCESS(rv, "Open failed!");
rv = xhr->Send(nsnull);
TEST_ENSURE_SUCCESS(rv, "Send failed!");

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