This commit is contained in:
David Anderson 2012-05-08 17:34:07 -07:00
Родитель 44704ed94f 9e8cf21871
Коммит 68a2caab6c
1012 изменённых файлов: 20723 добавлений и 55781 удалений

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

@ -721,7 +721,7 @@ getRoleCB(AtkObject *aAtkObj)
if (!accWrap)
return ATK_ROLE_INVALID;
#ifdef DEBUG_A11Y
#ifdef DEBUG
NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
"Does not support nsIAccessibleText when it should");
#endif

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

@ -74,9 +74,9 @@ public:
mFirstIter(nsnull), mLastIter(nsnull)
{ AppendTarget(aAcc); }
Relation(nsIContent* aContent) :
Relation(nsDocAccessible* aDocument, nsIContent* aContent) :
mFirstIter(nsnull), mLastIter(nsnull)
{ AppendTarget(aContent); }
{ AppendTarget(aDocument, aContent); }
Relation& operator = (const RelationCopyHelper& aRH)
{
@ -120,10 +120,10 @@ public:
* Append the one accessible for this content node to the set of related
* accessibles.
*/
inline void AppendTarget(nsIContent* aContent)
void AppendTarget(nsDocAccessible* aDocument, nsIContent* aContent)
{
if (aContent)
AppendTarget(GetAccService()->GetAccessible(aContent, nsnull));
AppendTarget(aDocument->GetAccessible(aContent));
}
/**

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

@ -443,10 +443,10 @@ nsAccUtils::GetLiveAttrValue(PRUint32 aRule, nsAString& aValue)
return false;
}
#ifdef DEBUG_A11Y
#ifdef DEBUG
bool
nsAccUtils::IsTextInterfaceSupportCorrect(nsAccessible *aAccessible)
nsAccUtils::IsTextInterfaceSupportCorrect(nsAccessible* aAccessible)
{
// Don't test for accessible docs, it makes us create accessibles too
// early and fire mutation events before we need to
@ -455,8 +455,8 @@ nsAccUtils::IsTextInterfaceSupportCorrect(nsAccessible *aAccessible)
bool foundText = false;
PRInt32 childCount = aAccessible->GetChildCount();
for (PRint32 childIdx = 0; childIdx < childCount; childIdx++) {
nsAccessible *child = GetChildAt(childIdx);
for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) {
nsAccessible* child = aAccessible->GetChildAt(childIdx);
if (IsText(child)) {
foundText = true;
break;
@ -470,7 +470,7 @@ nsAccUtils::IsTextInterfaceSupportCorrect(nsAccessible *aAccessible)
return false;
}
return true;
return true;
}
#endif

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

@ -270,7 +270,7 @@ public:
*/
static bool GetLiveAttrValue(PRUint32 aRule, nsAString& aValue);
#ifdef DEBUG_A11Y
#ifdef DEBUG
/**
* Detect whether the given accessible object implements nsIAccessibleText,
* when it is text or has text child node.

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

@ -49,9 +49,6 @@
#include "nsIDOMWindow.h"
#include "nsIFrame.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIObserverService.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsIPresShell.h"
#include "nsIServiceManager.h"
#include "nsIStringBundle.h"
@ -67,8 +64,6 @@ using namespace mozilla::a11y;
nsIStringBundle *nsAccessNode::gStringBundle = 0;
bool nsAccessNode::gIsFormFillEnabled = false;
ApplicationAccessible* nsAccessNode::gApplicationAccessible = nsnull;
/*
@ -163,28 +158,6 @@ void nsAccessNode::InitXPAccessibility()
stringBundleService->CreateBundle(ACCESSIBLE_BUNDLE_URL,
&gStringBundle);
}
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefBranch) {
prefBranch->GetBoolPref("browser.formfill.enable", &gIsFormFillEnabled);
}
NotifyA11yInitOrShutdown(true);
}
// nsAccessNode protected static
void nsAccessNode::NotifyA11yInitOrShutdown(bool aIsInit)
{
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
NS_ASSERTION(obsService, "No observer service to notify of a11y init/shutdown");
if (!obsService)
return;
static const PRUnichar kInitIndicator[] = { '1', 0 };
static const PRUnichar kShutdownIndicator[] = { '0', 0 };
obsService->NotifyObservers(nsnull, "a11y-init-or-shutdown",
aIsInit ? kInitIndicator : kShutdownIndicator);
}
void nsAccessNode::ShutdownXPAccessibility()
@ -202,8 +175,6 @@ void nsAccessNode::ShutdownXPAccessibility()
gApplicationAccessible->Shutdown();
NS_RELEASE(gApplicationAccessible);
}
NotifyA11yInitOrShutdown(false);
}
RootAccessible*

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

@ -164,16 +164,9 @@ protected:
nsCOMPtr<nsIContent> mContent;
nsDocAccessible* mDoc;
/**
* Notify global nsIObserver's that a11y is getting init'd or shutdown.
*/
static void NotifyA11yInitOrShutdown(bool aIsInit);
// Static data, we do our own refcounting for our static data.
static nsIStringBundle* gStringBundle;
static bool gIsFormFillEnabled;
private:
nsAccessNode() MOZ_DELETE;
nsAccessNode(const nsAccessNode&) MOZ_DELETE;

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

@ -46,6 +46,7 @@
#include "AtkSocketAccessible.h"
#endif
#include "FocusManager.h"
#include "HTMLListAccessible.h"
#include "nsAccessiblePivot.h"
#include "nsAccUtils.h"
#include "nsARIAMap.h"
@ -222,7 +223,7 @@ nsAccessibilityService::CreateHTMLLIAccessible(nsIContent* aContent,
nsIPresShell* aPresShell)
{
nsAccessible* accessible =
new nsHTMLLIAccessible(aContent, GetDocAccessible(aPresShell));
new HTMLLIAccessible(aContent, GetDocAccessible(aPresShell));
NS_ADDREF(accessible);
return accessible;
}
@ -599,7 +600,7 @@ nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell,
if (document) {
nsAccessible* accessible = document->GetAccessible(aHTMLListItemContent);
if (accessible) {
nsHTMLLIAccessible* listItem = accessible->AsHTMLListItem();
HTMLLIAccessible* listItem = accessible->AsHTMLListItem();
if (listItem)
listItem->UpdateBullet(aHasBullet);
}
@ -1271,6 +1272,9 @@ nsAccessibilityService::Init()
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
static const PRUnichar kInitIndicator[] = { '1', 0 };
observerService->NotifyObservers(nsnull, "a11y-init-or-shutdown", kInitIndicator);
// Initialize accessibility.
nsAccessNodeWrap::InitAccessibility();
@ -1284,9 +1288,13 @@ nsAccessibilityService::Shutdown()
// Remove observers.
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService)
if (observerService) {
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
static const PRUnichar kShutdownIndicator[] = { '0', 0 };
observerService->NotifyObservers(nsnull, "a11y-init-or-shutdown", kShutdownIndicator);
}
// Stop accessible document loader.
nsAccDocManager::Shutdown();
@ -1651,7 +1659,7 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
if (tag == nsGkAtoms::ul || tag == nsGkAtoms::ol ||
tag == nsGkAtoms::dl) {
nsAccessible* accessible = new nsHTMLListAccessible(aContent, aDoc);
nsAccessible* accessible = new HTMLListAccessible(aContent, aDoc);
NS_IF_ADDREF(accessible);
return accessible;
}
@ -1678,7 +1686,7 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
// Normally for li, it is created by the list item frame (in nsBlockFrame)
// which knows about the bullet frame; however, in this case the list item
// must have been styled using display: foo
nsAccessible* accessible = new nsHTMLLIAccessible(aContent, aDoc);
nsAccessible* accessible = new HTMLLIAccessible(aContent, aDoc);
NS_IF_ADDREF(accessible);
return accessible;
}

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

@ -914,7 +914,7 @@ void nsAccessible::GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame
// Initialization area
*aBoundingFrame = nsnull;
nsIFrame *firstFrame = GetBoundsFrame();
nsIFrame* firstFrame = GetFrame();
if (!firstFrame)
return;
@ -1029,13 +1029,6 @@ nsAccessible::GetBounds(PRInt32* aX, PRInt32* aY,
return NS_OK;
}
// helpers
nsIFrame* nsAccessible::GetBoundsFrame()
{
return GetFrame();
}
NS_IMETHODIMP nsAccessible::SetSelected(bool aSelect)
{
if (IsDefunct())
@ -2109,7 +2102,7 @@ nsAccessible::RelationByType(PRUint32 aType)
if (form) {
nsCOMPtr<nsIContent> formContent =
do_QueryInterface(form->GetDefaultSubmitElement());
return Relation(formContent);
return Relation(mDoc, formContent);
}
}
} else {
@ -2150,13 +2143,13 @@ nsAccessible::RelationByType(PRUint32 aType)
}
}
nsCOMPtr<nsIContent> relatedContent(do_QueryInterface(buttonEl));
return Relation(relatedContent);
return Relation(mDoc, relatedContent);
}
}
return Relation();
}
case nsIAccessibleRelation::RELATION_MEMBER_OF:
return Relation(GetAtomicRegion());
return Relation(mDoc, GetAtomicRegion());
case nsIAccessibleRelation::RELATION_SUBWINDOW_OF:
case nsIAccessibleRelation::RELATION_EMBEDS:
case nsIAccessibleRelation::RELATION_EMBEDDED_BY:

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

@ -62,12 +62,13 @@ class nsAccessible;
class nsHyperTextAccessible;
class nsHTMLImageAccessible;
class nsHTMLImageMapAccessible;
class nsHTMLLIAccessible;
struct nsRoleMapEntry;
class Relation;
namespace mozilla {
namespace a11y {
class HTMLLIAccessible;
class TableAccessible;
/**
@ -445,6 +446,11 @@ public:
*/
void TestChildCache(nsAccessible* aCachedChild) const;
/**
* Return boundaries rect relative the bounding frame.
*/
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
//////////////////////////////////////////////////////////////////////////////
// Downcasting and types
@ -471,7 +477,7 @@ public:
inline bool IsHTMLFileInput() const { return mFlags & eHTMLFileInputAccessible; }
inline bool IsHTMLListItem() const { return mFlags & eHTMLListItemAccessible; }
nsHTMLLIAccessible* AsHTMLListItem();
mozilla::a11y::HTMLLIAccessible* AsHTMLListItem();
inline bool IsImageAccessible() const { return mFlags & eImageAccessible; }
nsHTMLImageAccessible* AsImage();
@ -745,9 +751,6 @@ protected:
*/
mozilla::a11y::role ARIATransformRole(mozilla::a11y::role aRole);
virtual nsIFrame* GetBoundsFrame();
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
//////////////////////////////////////////////////////////////////////////////
// Name helpers

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

@ -123,6 +123,8 @@ public:
virtual nsresult HandleAccEvent(AccEvent* aAccEvent);
#endif
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
// nsHyperTextAccessible
virtual already_AddRefed<nsIEditor> GetEditor() const;
@ -384,7 +386,6 @@ protected:
virtual void CacheChildren();
// nsDocAccessible
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
virtual nsresult AddEventListeners();
virtual nsresult RemoveEventListeners();

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

@ -63,6 +63,9 @@
#include "nsIServiceManager.h"
#include "nsITextControlFrame.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
@ -496,7 +499,7 @@ HTMLTextFieldAccessible::NativeState()
// No parent can mean a fake widget created for XUL textbox. If accessible
// is unattached from tree then we don't care.
if (mParent && gIsFormFillEnabled) {
if (mParent && Preferences::GetBool("browser.formfill.enable")) {
// Check to see if autocompletion is allowed on this input. We don't expose
// it for password fields even though the entire password can be remembered
// for a page if the user asks it to be. However, the kind of autocomplete
@ -704,7 +707,7 @@ HTMLGroupboxAccessible::RelationByType(PRUint32 aType)
Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
// No override for label, so use <legend> for this <fieldset>
if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
rel.AppendTarget(GetLegend());
rel.AppendTarget(mDoc, GetLegend());
return rel;
}
@ -790,7 +793,7 @@ HTMLFigureAccessible::RelationByType(PRUint32 aType)
{
Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType);
if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY)
rel.AppendTarget(Caption());
rel.AppendTarget(mDoc, Caption());
return rel;
}

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

@ -0,0 +1,201 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "HTMLListAccessible.h"
#include "nsDocAccessible.h"
#include "Role.h"
#include "States.h"
#include "nsBlockFrame.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// HTMLListAccessible
////////////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS_INHERITED0(HTMLListAccessible, nsHyperTextAccessible)
role
HTMLListAccessible::NativeRole()
{
if (mContent->Tag() == nsGkAtoms::dl)
return roles::DEFINITION_LIST;
return roles::LIST;
}
PRUint64
HTMLListAccessible::NativeState()
{
return nsHyperTextAccessibleWrap::NativeState() | states::READONLY;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLLIAccessible
////////////////////////////////////////////////////////////////////////////////
HTMLLIAccessible::
HTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
nsHyperTextAccessibleWrap(aContent, aDoc), mBullet(nsnull)
{
mFlags |= eHTMLListItemAccessible;
nsBlockFrame* blockFrame = do_QueryFrame(GetFrame());
if (blockFrame && blockFrame->HasBullet()) {
mBullet = new HTMLListBulletAccessible(mContent, mDoc);
if (!Document()->BindToDocument(mBullet, nsnull))
mBullet = nsnull;
}
}
NS_IMPL_ISUPPORTS_INHERITED0(HTMLLIAccessible, nsHyperTextAccessible)
void
HTMLLIAccessible::Shutdown()
{
mBullet = nsnull;
nsHyperTextAccessibleWrap::Shutdown();
}
role
HTMLLIAccessible::NativeRole()
{
if (mContent->Tag() == nsGkAtoms::dt)
return roles::TERM;
return roles::LISTITEM;
}
PRUint64
HTMLLIAccessible::NativeState()
{
return nsHyperTextAccessibleWrap::NativeState() | states::READONLY;
}
NS_IMETHODIMP
HTMLLIAccessible::GetBounds(PRInt32* aX, PRInt32* aY,
PRInt32* aWidth, PRInt32* aHeight)
{
nsresult rv = nsAccessibleWrap::GetBounds(aX, aY, aWidth, aHeight);
if (NS_FAILED(rv) || !mBullet)
return rv;
PRInt32 bulletX = 0, bulletY = 0, bulletWidth = 0, bulletHeight = 0;
rv = mBullet->GetBounds(&bulletX, &bulletY, &bulletWidth, &bulletHeight);
NS_ENSURE_SUCCESS(rv, rv);
*aX = bulletX; // Move x coordinate of list item over to cover bullet as well
*aWidth += bulletWidth;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLLIAccessible: public
void
HTMLLIAccessible::UpdateBullet(bool aHasBullet)
{
if (aHasBullet == !!mBullet) {
NS_NOTREACHED("Bullet and accessible are in sync already!");
return;
}
nsDocAccessible* document = Document();
if (aHasBullet) {
mBullet = new HTMLListBulletAccessible(mContent, mDoc);
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.
}
////////////////////////////////////////////////////////////////////////////////
// HTMLLIAccessible: nsAccessible protected
void
HTMLLIAccessible::CacheChildren()
{
if (mBullet)
AppendChild(mBullet);
// Cache children from subtree.
nsAccessibleWrap::CacheChildren();
}
////////////////////////////////////////////////////////////////////////////////
// HTMLListBulletAccessible
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// HTMLListBulletAccessible: nsAccessNode
bool
HTMLListBulletAccessible::IsPrimaryForNode() const
{
return false;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLListBulletAccessible: nsAccessible
ENameValueFlag
HTMLListBulletAccessible::Name(nsString &aName)
{
aName.Truncate();
// 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);
// Append space otherwise bullets are jammed up against list text.
aName.Append(' ');
}
return eNameOK;
}
role
HTMLListBulletAccessible::NativeRole()
{
return roles::STATICTEXT;
}
PRUint64
HTMLListBulletAccessible::NativeState()
{
PRUint64 state = nsLeafAccessible::NativeState();
state &= ~states::FOCUSABLE;
state |= states::READONLY;
return state;
}
void
HTMLListBulletAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
PRUint32 aLength)
{
nsAutoString bulletText;
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
NS_ASSERTION(blockFrame, "No frame for list item!");
if (blockFrame)
blockFrame->GetBulletText(bulletText);
aText.Append(Substring(bulletText, aStartOffset, aLength));
}

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

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_HTMLListAccessible_h__
#define mozilla_a11y_HTMLListAccessible_h__
#include "nsHyperTextAccessibleWrap.h"
#include "nsBaseWidgetAccessible.h"
namespace mozilla {
namespace a11y {
class HTMLListBulletAccessible;
/**
* Used for HTML list (like HTML ul).
*/
class HTMLListAccessible : public nsHyperTextAccessibleWrap
{
public:
HTMLListAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
nsHyperTextAccessibleWrap(aContent, aDoc) { }
virtual ~HTMLListAccessible() { }
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsAccessible
virtual a11y::role NativeRole();
virtual PRUint64 NativeState();
};
/**
* Used for HTML list item (e.g. HTML li).
*/
class HTMLLIAccessible : public nsHyperTextAccessibleWrap
{
public:
HTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
virtual ~HTMLLIAccessible() { }
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsAccessNode
virtual void Shutdown();
// nsIAccessible
NS_IMETHOD GetBounds(PRInt32* aX, PRInt32* aY,
PRInt32* aWidth, PRInt32* aHeight);
// nsAccessible
virtual a11y::role NativeRole();
virtual PRUint64 NativeState();
// nsHTMLLIAccessible
void UpdateBullet(bool aHasBullet);
protected:
// nsAccessible
virtual void CacheChildren();
private:
nsRefPtr<HTMLListBulletAccessible> mBullet;
};
/**
* Used for bullet of HTML list item element (for example, HTML li).
*/
class HTMLListBulletAccessible : public nsLeafAccessible
{
public:
HTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
nsLeafAccessible(aContent, aDoc) { }
virtual ~HTMLListBulletAccessible() { }
// nsAccessNode
virtual bool IsPrimaryForNode() const;
// nsAccessible
virtual ENameValueFlag Name(nsString& aName);
virtual a11y::role NativeRole();
virtual PRUint64 NativeState();
virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0,
PRUint32 aLength = PR_UINT32_MAX);
};
} // namespace a11y
} // namespace mozilla
inline mozilla::a11y::HTMLLIAccessible*
nsAccessible::AsHTMLListItem()
{
return mFlags & eHTMLListItemAccessible ?
static_cast<mozilla::a11y::HTMLLIAccessible*>(this) : nsnull;
}
#endif

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

@ -52,6 +52,7 @@ LIBXUL_LIBRARY = 1
CPPSRCS = \
nsHTMLCanvasAccessible.cpp \
HTMLFormControlAccessible.cpp \
HTMLListAccessible.cpp \
nsHTMLImageAccessible.cpp \
nsHTMLImageMapAccessible.cpp \
nsHTMLLinkAccessible.cpp \

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

@ -105,6 +105,7 @@ public:
virtual PRUint64 NativeState();
virtual nsAccessible* ChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame);
// HyperLinkAccessible
virtual PRUint32 StartOffset();
@ -114,7 +115,6 @@ protected:
// nsAccessible
virtual void CacheChildren();
virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame);
};
#endif

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

@ -256,22 +256,6 @@ nsHTMLSelectOptionAccessible::GetNameInternal(nsAString& aName)
return NS_OK;
}
// nsAccessible protected
nsIFrame* nsHTMLSelectOptionAccessible::GetBoundsFrame()
{
PRUint64 state = 0;
nsIContent* content = GetSelectState(&state);
if (state & states::COLLAPSED) {
if (content) {
return content->GetPrimaryFrame();
}
return nsnull;
}
return nsAccessible::GetBoundsFrame();
}
PRUint64
nsHTMLSelectOptionAccessible::NativeState()
{
@ -348,8 +332,16 @@ nsHTMLSelectOptionAccessible::GetLevelInternal()
return level;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLSelectOptionAccessible: nsIAccessible
void
nsHTMLSelectOptionAccessible::GetBoundsRect(nsRect& aTotalBounds,
nsIFrame** aBoundingFrame)
{
nsAccessible* combobox = GetCombobox();
if (combobox && (combobox->State() & states::COLLAPSED))
combobox->GetBoundsRect(aTotalBounds, aBoundingFrame);
else
nsHyperTextAccessibleWrap::GetBoundsRect(aTotalBounds, aBoundingFrame);
}
/** select us! close combo box if necessary*/
NS_IMETHODIMP nsHTMLSelectOptionAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
@ -551,8 +543,6 @@ nsHTMLComboboxAccessible::Shutdown()
}
}
/**
*/
PRUint64
nsHTMLComboboxAccessible::NativeState()
{
@ -561,8 +551,7 @@ nsHTMLComboboxAccessible::NativeState()
// Get focus status from base class
PRUint64 state = nsAccessible::NativeState();
nsIFrame *frame = GetBoundsFrame();
nsIComboboxControlFrame *comboFrame = do_QueryFrame(frame);
nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame());
if (comboFrame && comboFrame->IsDroppedDown())
state |= states::EXPANDED;
else
@ -750,8 +739,7 @@ nsHTMLComboboxListAccessible::NativeState()
// Get focus status from base class
PRUint64 state = nsAccessible::NativeState();
nsIFrame *boundsFrame = GetBoundsFrame();
nsIComboboxControlFrame* comboFrame = do_QueryFrame(boundsFrame);
nsIComboboxControlFrame* comboFrame = do_QueryFrame(mParent->GetFrame());
if (comboFrame && comboFrame->IsDroppedDown())
state |= states::FLOATING;
else

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

@ -122,6 +122,7 @@ public:
virtual PRUint64 NativeState();
virtual PRInt32 GetLevelInternal();
virtual void GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame);
// ActionAccessible
virtual PRUint8 ActionCount();
@ -129,10 +130,6 @@ public:
// Widgets
virtual nsAccessible* ContainerWidget() const;
protected:
// nsAccessible
virtual nsIFrame* GetBoundsFrame();
private:
/**
@ -141,6 +138,19 @@ private:
* @return Select element content, returns null if not avaliable
*/
nsIContent* GetSelectState(PRUint64* aState);
/**
* Return a combobox accessible the option belongs to if any.
*/
nsAccessible* GetCombobox() const
{
if (mParent && mParent->IsListControl()) {
nsAccessible* combobox = mParent->Parent();
return combobox->IsCombobox() ? combobox : nsnull;
}
return nsnull;
}
};
/*

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

@ -41,19 +41,12 @@
#include "nsDocAccessible.h"
#include "nsAccUtils.h"
#include "nsIAccessibleRelation.h"
#include "nsTextEquivUtils.h"
#include "Relation.h"
#include "Role.h"
#include "States.h"
#include "nsIAccessibleRelation.h"
#include "nsIFrame.h"
#include "nsPresContext.h"
#include "nsBlockFrame.h"
#include "nsISelection.h"
#include "nsISelectionController.h"
#include "nsComponentManagerUtils.h"
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
@ -227,198 +220,3 @@ nsHTMLOutputAccessible::GetAttributesInternal(nsIPersistentProperties* aAttribut
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLLIAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLLIAccessible::
nsHTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
nsHyperTextAccessibleWrap(aContent, aDoc), mBullet(nsnull)
{
mFlags |= eHTMLListItemAccessible;
nsBlockFrame* blockFrame = do_QueryFrame(GetFrame());
if (blockFrame && blockFrame->HasBullet()) {
mBullet = new nsHTMLListBulletAccessible(mContent, mDoc);
if (!Document()->BindToDocument(mBullet, nsnull))
mBullet = nsnull;
}
}
NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLIAccessible, nsHyperTextAccessible)
void
nsHTMLLIAccessible::Shutdown()
{
mBullet = nsnull;
nsHyperTextAccessibleWrap::Shutdown();
}
role
nsHTMLLIAccessible::NativeRole()
{
if (mContent->Tag() == nsGkAtoms::dt)
return roles::TERM;
return roles::LISTITEM;
}
PRUint64
nsHTMLLIAccessible::NativeState()
{
return nsHyperTextAccessibleWrap::NativeState() | states::READONLY;
}
NS_IMETHODIMP nsHTMLLIAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height)
{
nsresult rv = nsAccessibleWrap::GetBounds(x, y, width, height);
if (NS_FAILED(rv) || !mBullet)
return rv;
PRInt32 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
*width += bulletWidth;
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 = Document();
if (aHasBullet) {
mBullet = new nsHTMLListBulletAccessible(mContent, mDoc);
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 (mBullet)
AppendChild(mBullet);
// Cache children from subtree.
nsAccessibleWrap::CacheChildren();
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLListBulletAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLListBulletAccessible::
nsHTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
nsLeafAccessible(aContent, aDoc)
{
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLListBulletAccessible: nsAccessNode
bool
nsHTMLListBulletAccessible::IsPrimaryForNode() const
{
return false;
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLListBulletAccessible: nsAccessible
ENameValueFlag
nsHTMLListBulletAccessible::Name(nsString &aName)
{
aName.Truncate();
// 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);
// Append space otherwise bullets are jammed up against list text.
aName.Append(' ');
}
return eNameOK;
}
role
nsHTMLListBulletAccessible::NativeRole()
{
return roles::STATICTEXT;
}
PRUint64
nsHTMLListBulletAccessible::NativeState()
{
PRUint64 state = nsLeafAccessible::NativeState();
state &= ~states::FOCUSABLE;
state |= states::READONLY;
return state;
}
void
nsHTMLListBulletAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset,
PRUint32 aLength)
{
nsAutoString bulletText;
nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
NS_ASSERTION(blockFrame, "No frame for list item!");
if (blockFrame)
blockFrame->GetBulletText(bulletText);
aText.Append(Substring(bulletText, aStartOffset, aLength));
}
////////////////////////////////////////////////////////////////////////////////
// nsHTMLListAccessible
////////////////////////////////////////////////////////////////////////////////
nsHTMLListAccessible::
nsHTMLListAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
nsHyperTextAccessibleWrap(aContent, aDoc)
{
}
NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLListAccessible, nsHyperTextAccessible)
role
nsHTMLListAccessible::NativeRole()
{
if (mContent->Tag() == nsGkAtoms::dl)
return roles::DEFINITION_LIST;
return roles::LIST;
}
PRUint64
nsHTMLListAccessible::NativeState()
{
return nsHyperTextAccessibleWrap::NativeState() | states::READONLY;
}

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

@ -119,78 +119,4 @@ public:
virtual Relation RelationByType(PRUint32 aType);
};
/**
* Used for bullet of HTML list item element (for example, HTML li).
*/
class nsHTMLListBulletAccessible : public nsLeafAccessible
{
public:
nsHTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
// nsAccessNode
virtual bool IsPrimaryForNode() const;
// nsAccessible
virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
virtual mozilla::a11y::role NativeRole();
virtual PRUint64 NativeState();
virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0,
PRUint32 aLength = PR_UINT32_MAX);
};
/**
* Used for HTML list (like HTML ul).
*/
class nsHTMLListAccessible : public nsHyperTextAccessibleWrap
{
public:
nsHTMLListAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsAccessible
virtual mozilla::a11y::role NativeRole();
virtual PRUint64 NativeState();
};
/**
* Used for HTML list item (e.g. HTML li).
*/
class nsHTMLLIAccessible : public nsHyperTextAccessibleWrap
{
public:
nsHTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
// nsAccessNode
virtual void Shutdown();
// nsIAccessible
NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
// nsAccessible
virtual mozilla::a11y::role NativeRole();
virtual PRUint64 NativeState();
// nsHTMLLIAccessible
void UpdateBullet(bool aHasBullet);
protected:
// nsAccessible
virtual void CacheChildren();
private:
nsRefPtr<nsHTMLListBulletAccessible> mBullet;
};
inline nsHTMLLIAccessible*
nsAccessible::AsHTMLListItem()
{
return mFlags & eHTMLListItemAccessible ?
static_cast<nsHTMLLIAccessible*>(this) : nsnull;
}
#endif

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

@ -53,9 +53,8 @@ var AccessFu = {
},
/**
* Start the special AccessFu mode, this primarily means controlling the virtual
* cursor with arrow keys. Currently, on platforms other than Android this needs
* to be called explicitly.
* Start AccessFu mode, this primarily means controlling the virtual cursor
* with arrow keys.
*/
enable: function enable() {
dump('AccessFu enable');
@ -72,8 +71,6 @@ var AccessFu = {
this.chromeWin.addEventListener('resize', this, true);
this.chromeWin.addEventListener('scroll', this, true);
this.chromeWin.addEventListener('TabOpen', this, true);
this.chromeWin.addEventListener('TabSelect', this, true);
this.chromeWin.addEventListener('TabClosed', this, true);
},
/**
@ -82,18 +79,16 @@ var AccessFu = {
disable: function disable() {
dump('AccessFu disable');
this.presenters.forEach(function(p) {p.detach();});
this.presenters.forEach(function(p) { p.detach(); });
this.presenters = [];
VirtualCursorController.detach();
Services.obs.addObserver(this, 'accessible-event', false);
this.chromeWin.removeEventListener('DOMActivate', this);
this.chromeWin.removeEventListener('resize', this);
this.chromeWin.removeEventListener('scroll', this);
this.chromeWin.removeEventListener('TabOpen', this);
this.chromeWin.removeEventListener('TabSelect', this);
this.chromeWin.removeEventListener('TabClose', this);
Services.obs.removeObserver(this, 'accessible-event');
this.chromeWin.removeEventListener('DOMActivate', this, true);
this.chromeWin.removeEventListener('resize', this, true);
this.chromeWin.removeEventListener('scroll', this, true);
this.chromeWin.removeEventListener('TabOpen', this, true);
},
amINeeded: function(aPref) {
@ -125,14 +120,17 @@ var AccessFu = {
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case 'TabSelect':
{
this.getDocAccessible(
function(docAcc) {
this.presenters.forEach(function(p) {p.tabSelected(docAcc);});
});
break;
}
case 'TabOpen':
{
let browser = aEvent.target.linkedBrowser || aEvent.target;
// Store the new browser node. We will need to check later when a new
// content document is attached if it has been attached to this new tab.
// If it has, than we will need to send a 'loading' message along with
// the usual 'newdoc' to presenters.
this._pendingDocuments[browser] = true;
this.presenters.forEach(function(p) { p.tabStateChanged(null, 'newtab'); });
break;
}
case 'DOMActivate':
{
let activatedAcc = getAccessible(aEvent.originalTarget);
@ -153,25 +151,12 @@ var AccessFu = {
case 'scroll':
case 'resize':
{
this.presenters.forEach(function(p) {p.viewportChanged();});
this.presenters.forEach(function(p) { p.viewportChanged(); });
break;
}
}
},
getDocAccessible: function getDocAccessible(aCallback) {
let browserApp = (Services.appinfo.OS == 'Android') ?
this.chromeWin.BrowserApp : this.chromeWin.gBrowser;
let docAcc = getAccessible(browserApp.selectedBrowser.contentDocument);
if (!docAcc) {
// Wait for a reorder event fired by the parent of the new doc.
this._pendingDocuments[browserApp.selectedBrowser] = aCallback;
} else {
aCallback.apply(this, [docAcc]);
}
},
observe: function observe(aSubject, aTopic, aData) {
switch (aTopic) {
case 'nsPref:changed':
@ -223,16 +208,86 @@ var AccessFu = {
}
);
}
else if (event.state == Ci.nsIAccessibleStates.STATE_BUSY &&
!(event.isExtraState()) && event.isEnabled()) {
let role = event.accessible.role;
if ((role == Ci.nsIAccessibleRole.ROLE_DOCUMENT ||
role == Ci.nsIAccessibleRole.ROLE_APPLICATION)) {
// An existing document has changed to state "busy", this means
// something is loading. Send a 'loading' message to presenters.
this.presenters.forEach(
function(p) {
p.tabStateChanged(event.accessible, 'loading');
}
);
}
}
break;
}
case Ci.nsIAccessibleEvent.EVENT_REORDER:
{
let node = aEvent.accessible.DOMNode;
let callback = this._pendingDocuments[node];
if (callback && aEvent.accessible.childCount) {
// We have a callback associated with a document.
callback.apply(this, [aEvent.accessible.getChildAt(0)]);
delete this._pendingDocuments[node];
let acc = aEvent.accessible;
if (acc.childCount) {
let docAcc = acc.getChildAt(0);
if (this._pendingDocuments[aEvent.DOMNode]) {
// This is a document in a new tab. Check if it is
// in a BUSY state (i.e. loading), and inform presenters.
// We need to do this because a state change event will not be
// fired when an object is created with the BUSY state.
// If this is not a new tab, don't bother because we sent 'loading'
// when the previous doc changed its state to BUSY.
let state = {};
docAcc.getState(state, {});
if (state.value & Ci.nsIAccessibleStates.STATE_BUSY &&
this.isNotChromeDoc(docAcc))
this.presenters.forEach(
function(p) { p.tabStateChanged(docAcc, 'loading'); }
);
delete this._pendingDocuments[aEvent.DOMNode];
}
if (this.isBrowserDoc(docAcc))
// A new top-level content document has been attached
this.presenters.forEach(
function(p) { p.tabStateChanged(docAcc, 'newdoc'); }
);
}
break;
}
case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE:
{
if (this.isNotChromeDoc(aEvent.accessible)) {
this.presenters.forEach(
function(p) {
p.tabStateChanged(aEvent.accessible, 'loaded');
}
);
}
break;
}
case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_STOPPED:
{
this.presenters.forEach(
function(p) {
p.tabStateChanged(aEvent.accessible, 'loadstopped');
}
);
break;
}
case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD:
{
this.presenters.forEach(
function(p) {
p.tabStateChanged(aEvent.accessible, 'reload');
}
);
break;
}
case Ci.nsIAccessibleEvent.EVENT_FOCUS:
{
if (this.isBrowserDoc(aEvent.accessible)) {
// The document recieved focus, call tabSelected to present current tab.
this.presenters.forEach(
function(p) { p.tabSelected(aEvent.accessible); });
}
break;
}
@ -269,6 +324,38 @@ var AccessFu = {
}
},
/**
* Check if accessible is a top-level content document (i.e. a child of a XUL
* browser node).
* @param {nsIAccessible} aDocAcc the accessible to check.
* @return {boolean} true if this is a top-level content document.
*/
isBrowserDoc: function isBrowserDoc(aDocAcc) {
let parent = aDocAcc.parent;
if (!parent)
return false;
let domNode = parent.DOMNode;
if (!domNode)
return false;
const ns = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
return (domNode.localName == 'browser' && domNode.namespaceURI == ns);
},
/**
* Check if document is not a local "chrome" document, like about:home.
* @param {nsIDOMDocument} aDocument the document to check.
* @return {boolean} true if this is not a chrome document.
*/
isNotChromeDoc: function isNotChromeDoc(aDocument) {
let location = aDocument.DOMNode.location;
if (!location)
return false;
return location.protocol != "about:";
},
getNewContext: function getNewContext(aOldObject, aNewObject) {
let newLineage = [];
let oldLineage = [];

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

@ -66,15 +66,21 @@ Presenter.prototype = {
selectionChanged: function selectionChanged(aObject) {},
/**
* The page state has changed, loading, stopped loading, etc. TODO.
* The tab, or the tab's document state has changed.
* @param {nsIAccessible} aDocObj the tab document accessible that has had its
* state changed, or null if the tab has no associated document yet.
* @param {string} aPageState the state name for the tab, valid states are:
* 'newtab', 'loading', 'newdoc', 'loaded', 'stopped', and 'reload'.
*/
pageStateChanged: function pageStateChanged() {},
tabStateChanged: function tabStateChanged(aDocObj, aPageState) {},
/**
* The tab has changed.
* @param {nsIAccessible} aObject the document contained in the tab.
* The current tab has changed.
* @param {nsIAccessible} aObject the document contained by the tab
* accessible, or null if it is a new tab with no attached
* document yet.
*/
tabSelected: function tabSelected(aObject) {},
tabSelected: function tabSelected(aDocObj) {},
/**
* The viewport has changed, either a scroll, pan, zoom, or
@ -147,9 +153,17 @@ VisualPresenter.prototype.pivotChanged = function(aObject, aNewContext) {
}
};
VisualPresenter.prototype.tabSelected = function(aObject) {
let vcDoc = aObject.QueryInterface(Ci.nsIAccessibleCursorable);
this.pivotChanged(vcDoc.virtualCursor.position);
VisualPresenter.prototype.tabSelected = function(aDocObj) {
let vcPos = aDocObj ?
aDocObj.QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor.position :
null;
this.pivotChanged(vcPos);
};
VisualPresenter.prototype.tabStateChanged = function(aDocObj, aPageState) {
if (aPageState == "newdoc")
this.pivotChanged(null);
};
// Internals
@ -242,16 +256,40 @@ AndroidPresenter.prototype.actionInvoked = function(aObject, aActionName) {
});
};
AndroidPresenter.prototype.tabSelected = function(aObject) {
let vcDoc = aObject.QueryInterface(Ci.nsIAccessibleCursorable);
AndroidPresenter.prototype.tabSelected = function(aDocObj) {
// Send a pivot change message with the full context utterance for this doc.
let vcDoc = aDocObj.QueryInterface(Ci.nsIAccessibleCursorable);
let context = [];
let parent = vcDoc.virtualCursor.position || aObject;
while ((parent = parent.parent))
let parent = vcDoc.virtualCursor.position || aDocObj;
while ((parent = parent.parent)) {
context.push(parent);
if (parent == aDocObj)
break;
}
context.reverse();
this.pivotChanged(vcDoc.virtualCursor.position || aObject, context);
this.pivotChanged(vcDoc.virtualCursor.position || aDocObj, context);
};
AndroidPresenter.prototype.tabStateChanged = function(aDocObj, aPageState) {
let stateUtterance = UtteranceGenerator.
genForTabStateChange(aDocObj, aPageState);
if (!stateUtterance.length)
return;
this.sendMessageToJava({
gecko: {
type: 'Accessibility:Event',
eventType: ANDROID_TYPE_VIEW_TEXT_CHANGED,
text: stateUtterance,
addedCount: stateUtterance.join(' ').length,
removedCount: 0,
fromIndex: 0
}
});
};
AndroidPresenter.prototype.textChanged = function(aIsInserted, aStart, aLength, aText, aModifiedText) {

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

@ -22,6 +22,22 @@ var gAccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
var EXPORTED_SYMBOLS = ['UtteranceGenerator'];
/**
* Generates speech utterances from objects, actions and state changes.
* An utterance is an array of strings.
*
* It should not be assumed that flattening an utterance array would create a
* gramatically correct sentence. For example, {@link genForObject} might
* return: ['graphic', 'Welcome to my home page'].
* Each string element in an utterance should be gramatically correct in itself.
* Another example from {@link genForObject}: ['list item 2 of 5', 'Alabama'].
*
* An utterance is ordered from the least to the most important. Speaking the
* last string usually makes sense, but speaking the first often won't.
* For example {@link genForAction} might return ['button', 'clicked'] for a
* clicked event. Speaking only 'clicked' makes sense. Speaking 'button' does
* not.
*/
var UtteranceGenerator = {
gActionMap: {
jump: 'jumpAction',
@ -39,6 +55,19 @@ var UtteranceGenerator = {
cycle: 'cycleAction'
},
/**
* Generates an utterance for an object.
* @param {nsIAccessible} aAccessible accessible object to generate utterance
* for.
* @param {boolean} aForceName include the object's name in the utterance
* even if this object type does not usually have it's name uttered.
* @return {Array} Two string array. The first string describes the object
* and its states. The second string is the object's name. Some object
* types may have the description or name omitted, instead an empty string
* is returned as a placeholder. Whether the object's description or it's role
* is included is determined by {@link verbosityRoleMap}.
*/
genForObject: function(aAccessible, aForceName) {
let roleString = gAccRetrieval.getStringRole(aAccessible.role);
@ -53,10 +82,45 @@ var UtteranceGenerator = {
return func.apply(this, [aAccessible, roleString, flags]);
},
/**
* Generates an utterance for an action performed.
* TODO: May become more verbose in the future.
* @param {nsIAccessible} aAccessible accessible object that the action was
* invoked in.
* @param {string} aActionName the name of the action, one of the keys in
* {@link gActionMap}.
* @return {Array} A one string array with the action.
*/
genForAction: function(aObject, aActionName) {
return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
},
/**
* Generates an utterance for a tab state change.
* @param {nsIAccessible} aAccessible accessible object of the tab's attached
* document.
* @param {string} aTabState the tab state name, see
* {@link Presenter.tabStateChanged}.
* @return {Array} The tab state utterace.
*/
genForTabStateChange: function (aObject, aTabState) {
switch (aTabState) {
case 'newtab':
return [gStringBundle.GetStringFromName('tabNew')];
case 'loading':
return [gStringBundle.GetStringFromName('tabLoading')];
case 'loaded':
return [aObject.name || '',
gStringBundle.GetStringFromName('tabLoaded')];
case 'loadstopped':
return [gStringBundle.GetStringFromName('tabLoadStopped')];
case 'reload':
return [gStringBundle.GetStringFromName('tabReload')];
default:
return [];
}
},
verbosityRoleMap: {
'menubar': INCLUDE_ROLE,
'scrollbar': INCLUDE_ROLE,
@ -115,35 +179,45 @@ var UtteranceGenerator = {
let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
let desc = (aFlags & INCLUDE_ROLE) ? this._getLocalizedRole(aRoleStr) : '';
if (!name && !desc)
return [];
let utterance = [];
let state = {};
let extState = {};
aAccessible.getState(state, extState);
if (desc) {
let state = {};
let extState = {};
aAccessible.getState(state, extState);
if (state.value & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
let stateStr = (state.value & Ci.nsIAccessibleStates.STATE_CHECKED) ?
'objChecked' : 'objNotChecked';
desc = gStringBundle.formatStringFromName(stateStr, [desc], 1);
if (state.value & Ci.nsIAccessibleStates.STATE_CHECKABLE) {
let stateStr = (state.value & Ci.nsIAccessibleStates.STATE_CHECKED) ?
'objChecked' : 'objNotChecked';
desc = gStringBundle.formatStringFromName(stateStr, [desc], 1);
}
if (extState.value & Ci.nsIAccessibleStates.EXT_STATE_EXPANDABLE) {
let stateStr = (state.value & Ci.nsIAccessibleStates.STATE_EXPANDED) ?
'objExpanded' : 'objCollapsed';
desc = gStringBundle.formatStringFromName(stateStr, [desc], 1);
}
utterance.push(desc);
}
if (extState.value & Ci.nsIAccessibleStates.EXT_STATE_EXPANDABLE) {
let stateStr = (state.value & Ci.nsIAccessibleStates.STATE_EXPANDED) ?
'objExpanded' : 'objCollapsed';
desc = gStringBundle.formatStringFromName(stateStr, [desc], 1);
}
if (name)
utterance.push(name);
return [desc, name];
return utterance;
},
heading: function(aAccessible, aRoleStr, aFlags) {
let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
let level = {};
aAccessible.groupPosition(level, {}, {});
let desc = gStringBundle.formatStringFromName('headingLevel',
[level.value], 1);
return [desc, name];
let utterance =
[gStringBundle.formatStringFromName('headingLevel', [level.value], 1)];
if (name)
utterance.push(name);
return utterance;
},
listitem: function(aAccessible, aRoleStr, aFlags) {
@ -152,10 +226,14 @@ var UtteranceGenerator = {
let itemno = {};
let itemof = {};
aAccessible.groupPosition({}, itemof, itemno);
let desc = gStringBundle.formatStringFromName(
'objItemOf', [localizedRole, itemno.value, itemof.value], 3);
let utterance =
[gStringBundle.formatStringFromName(
'objItemOf', [localizedRole, itemno.value, itemof.value], 3)];
return [desc, name];
if (name)
utterance.push(name);
return utterance;
}
},

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

@ -24,7 +24,7 @@ var VirtualCursorController = {
},
detach: function detach() {
this.chromeWin.document.removeEventListener('keypress', this.onkeypress);
this.chromeWin.document.removeEventListener('keypress', this.onkeypress, true);
},
getBrowserApp: function getBrowserApp() {
@ -114,38 +114,67 @@ var VirtualCursorController = {
SimpleTraversalRule: {
getMatchRoles: function(aRules) {
aRules.value = [];
return 0;
aRules.value = this._matchRoles;
return this._matchRoles.length;
},
preFilter: Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE,
match: function(aAccessible) {
if (aAccessible.childCount)
// Non-leafs do not interest us.
return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE;
// XXX: Find a better solution for ROLE_STATICTEXT.
// It allows to filter list bullets but the same time it
// filters CSS generated content too as unwanted side effect.
let ignoreRoles = [Ci.nsIAccessibleRole.ROLE_WHITESPACE,
Ci.nsIAccessibleRole.ROLE_STATICTEXT];
if (ignoreRoles.indexOf(aAccessible.role) < 0) {
let name = aAccessible.name;
if (name && name.trim())
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
}
let state = {};
aAccessible.getState(state, {});
if (state.value & Ci.nsIAccessibleStates.STATE_FOCUSABLE)
switch (aAccessible.role) {
case Ci.nsIAccessibleRole.ROLE_COMBOBOX:
// We don't want to ignore the subtree because this is often
// where the list box hangs out.
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE;
case Ci.nsIAccessibleRole.ROLE_TEXT_LEAF:
{
// Nameless text leaves are boring, skip them.
let name = aAccessible.name;
if (name && name.trim())
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
else
return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE;
}
case Ci.nsIAccessibleRole.ROLE_LINK:
// If the link has children we should land on them instead.
// Image map links don't have children so we need to match those.
if (aAccessible.childCount == 0)
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
else
return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE;
default:
// Ignore the subtree, if there is one. So that we don't land on
// the same content that was already presented by its parent.
return Ci.nsIAccessibleTraversalRule.FILTER_MATCH |
Ci.nsIAccessibleTraversalRule.FILTER_IGNORE_SUBTREE;
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule])
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule]),
_matchRoles: [
Ci.nsIAccessibleRole.ROLE_MENUITEM,
Ci.nsIAccessibleRole.ROLE_LINK,
Ci.nsIAccessibleRole.ROLE_PAGETAB,
Ci.nsIAccessibleRole.ROLE_GRAPHIC,
// XXX: Find a better solution for ROLE_STATICTEXT.
// It allows to filter list bullets but at the same time it
// filters CSS generated content too as an unwanted side effect.
// Ci.nsIAccessibleRole.ROLE_STATICTEXT,
Ci.nsIAccessibleRole.ROLE_TEXT_LEAF,
Ci.nsIAccessibleRole.ROLE_PUSHBUTTON,
Ci.nsIAccessibleRole.ROLE_CHECKBUTTON,
Ci.nsIAccessibleRole.ROLE_RADIOBUTTON,
Ci.nsIAccessibleRole.ROLE_COMBOBOX,
Ci.nsIAccessibleRole.ROLE_PROGRESSBAR,
Ci.nsIAccessibleRole.ROLE_BUTTONDROPDOWN,
Ci.nsIAccessibleRole.ROLE_BUTTONMENU,
Ci.nsIAccessibleRole.ROLE_CHECK_MENU_ITEM,
Ci.nsIAccessibleRole.ROLE_PASSWORD_TEXT,
Ci.nsIAccessibleRole.ROLE_RADIO_MENU_ITEM,
Ci.nsIAccessibleRole.ROLE_TOGGLE_BUTTON,
Ci.nsIAccessibleRole.ROLE_ENTRY
]
}
};

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

@ -453,7 +453,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
- (NSString*)role
{
#ifdef DEBUG_A11Y
#ifdef DEBUG
NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(mGeckoAccessible),
"Does not support nsIAccessibleText when it should");
#endif

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

@ -372,7 +372,7 @@ __try {
if (xpAccessible->IsDefunct())
return CO_E_OBJNOTCONNECTED;
#ifdef DEBUG_A11Y
#ifdef DEBUG
NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(xpAccessible),
"Does not support nsIAccessibleText when it should");
#endif
@ -1670,7 +1670,7 @@ nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
aid->ToUTF8String(id);
}
#ifdef DEBUG_A11Y
#ifdef DEBUG
printf("\n\nMSAA event: event: %d, target: %s@id='%s', childid: %d, hwnd: %d\n\n",
eventType, NS_ConvertUTF16toUTF8(tag).get(), id.get(),
childID, hWnd);

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

@ -463,23 +463,19 @@ nsXULMenupopupAccessible::NativeState()
{
PRUint64 state = nsAccessible::NativeState();
#ifdef DEBUG_A11Y
#ifdef DEBUG
// We are onscreen if our parent is active
bool isActive = mContent->HasAttr(kNameSpaceID_None,
nsGkAtoms::menuactive);
bool isActive = mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::menuactive);
if (!isActive) {
nsAccessible* parent = Parent();
if (!parent)
return state;
nsIContent *parentContent = parnet->GetContent();
NS_ENSURE_TRUE(parentContent, state);
isActive = parentContent->HasAttr(kNameSpaceID_None,
nsGkAtoms::open);
if (parent) {
nsIContent* parentContent = parent->GetContent();
if (parentContent)
isActive = parentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::open);
}
}
NS_ASSERTION(isActive || states & states::INVISIBLE,
NS_ASSERTION(isActive || (state & states::INVISIBLE),
"XULMenupopup doesn't have INVISIBLE when it's inactive");
#endif

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

@ -160,7 +160,7 @@ nsXULTabAccessible::RelationByType(PRUint32 aType)
return rel;
nsCOMPtr<nsIContent> tabpanelContent(do_QueryInterface(tabpanelNode));
rel.AppendTarget(tabpanelContent);
rel.AppendTarget(mDoc, tabpanelContent);
return rel;
}
@ -254,6 +254,6 @@ nsXULTabpanelAccessible::RelationByType(PRUint32 aType)
return rel;
nsCOMPtr<nsIContent> tabContent(do_QueryInterface(tabNode));
rel.AppendTarget(tabContent);
rel.AppendTarget(mDoc, tabContent);
return rel;
}

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

@ -46,6 +46,7 @@ include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_select.html \
test_zoom.html \
$(NULL)

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

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html>
<head>
<title>Accessible boundaries when page is zoomed</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../layout.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
function openComboboxNCheckBounds(aID)
{
this.combobox = getAccessible(aID);
this.comboboxList = this.combobox.firstChild;
this.comboboxOption = this.comboboxList.firstChild;
this.eventSeq = [
new invokerChecker(EVENT_FOCUS, this.comboboxOption)
];
this.invoke = function openComboboxNCheckBounds_invoke()
{
getNode(aID).focus();
synthesizeKey("VK_DOWN", { altKey: true });
}
this.finalCheck = function openComboboxNCheckBounds_invoke()
{
testBounds(this.comboboxOption);
}
this.getID = function openComboboxNCheckBounds_getID()
{
return "open combobox and test boundaries";
}
}
//gA11yEventDumpToConsole = true;
var gQueue = null;
function doTest()
{
// Combobox
testBounds("combobox");
// Option boundaries matches to combobox boundaries when collapsed.
var selectBounds = getBoundsForDOMElm("combobox");
testBounds("option1", selectBounds);
// Open combobox and test option boundaries.
gQueue = new eventQueue();
gQueue.push(new openComboboxNCheckBounds("combobox"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<select id="combobox">
<option id="option1">item1</option>
<option>item2</option>
</select>
</body>
</html>

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

@ -94,10 +94,10 @@ function getChildAtPoint(aIdentifier, aX, aY, aFindDeepestChild)
/**
* Test the accessible boundaries.
*/
function testBounds(aID)
function testBounds(aID, aRect)
{
var [expectedX, expectedY, expectedWidth, expectedHeight] =
getBoundsForDOMElm(aID);
(aRect != undefined) ? aRect : getBoundsForDOMElm(aID);
var [x, y, width, height] = getBounds(aID);
is(x, expectedX, "Wrong x coordinate of " + prettyName(aID));
@ -166,6 +166,9 @@ function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight)
getInterface(Components.interfaces.nsIDOMWindowUtils);
var ratio = winUtil.screenPixelsPerCSSPixel;
return [aX * ratio, aY * ratio, aWidth * ratio, aHeight * ratio];
}
// CSS pixels and ratio can be not integer. Device pixels are always integer.
// Do our best and hope it works.
return [ Math.round(aX * ratio), Math.round(aY * ratio),
Math.round(aWidth * ratio), Math.round(aHeight * ratio) ];
}

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

@ -17,6 +17,7 @@ const STATE_COLLAPSED = nsIAccessibleStates.STATE_COLLAPSED;
const STATE_DEFAULT = nsIAccessibleStates.STATE_DEFAULT;
const STATE_EXPANDED = nsIAccessibleStates.STATE_EXPANDED;
const STATE_EXTSELECTABLE = nsIAccessibleStates.STATE_EXTSELECTABLE;
const STATE_FLOATING = nsIAccessibleStates.STATE_FLOATING;
const STATE_FOCUSABLE = nsIAccessibleStates.STATE_FOCUSABLE;
const STATE_FOCUSED = nsIAccessibleStates.STATE_FOCUSED;
const STATE_HASPOPUP = nsIAccessibleStates.STATE_HASPOPUP;

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

@ -7,14 +7,53 @@
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../states.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
function openComboboxNCheckStates(aID)
{
this.combobox = getAccessible(aID);
this.comboboxList = this.combobox.firstChild;
this.comboboxOption = this.comboboxList.firstChild;
this.eventSeq = [
new invokerChecker(EVENT_FOCUS, this.comboboxOption)
];
this.invoke = function openComboboxNCheckStates_invoke()
{
getNode(aID).focus();
synthesizeKey("VK_DOWN", { altKey: true });
}
this.finalCheck = function openComboboxNCheckStates_invoke()
{
// Expanded state on combobox.
testStates(this.combobox, STATE_EXPANDED);
// Floating state on combobox list.
testStates(this.comboboxList, STATE_FLOATING);
}
this.getID = function openComboboxNCheckStates_getID()
{
return "open combobox and test states";
}
}
//gA11yEventDumpToConsole = true;
var gQueue = null;
function doTest()
{
// combobox
@ -24,7 +63,7 @@
STATE_FOCUSED, 0);
var comboboxList = combobox.firstChild;
testStates(comboboxList, 0, 0, STATE_FOCUSABLE, 0);
testStates(comboboxList, STATE_INVISIBLE, 0, STATE_FOCUSABLE, 0);
var opt1 = comboboxList.firstChild;
testStates(opt1, STATE_SELECTABLE | STATE_SELECTED | STATE_FOCUSABLE,
@ -46,7 +85,10 @@
STATE_SELECTED | STATE_FOCUSED | STATE_FOCUSED,
0, 0, EXT_STATE_ACTIVE);
SimpleTest.finish();
// open combobox
gQueue = new eventQueue();
gQueue.push(new openComboboxNCheckStates("combobox"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();

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

@ -503,3 +503,12 @@ pref("app.update.download.backgroundInterval", 0);
// field.
pref("app.update.log", true);
#endif
// Extensions preferences
pref("extensions.update.enabled", false);
pref("extensions.getAddons.cache.enabled", false);
// Context Menu
pref("ui.click_hold_context_menus", true);
pref("ui.click_hold_context_menus.delay", 1000);

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

@ -14,36 +14,31 @@ Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/ContactService.jsm');
Cu.import('resource://gre/modules/Webapps.jsm');
XPCOMUtils.defineLazyGetter(Services, 'env', function() {
return Cc['@mozilla.org/process/environment;1']
.getService(Ci.nsIEnvironment);
});
XPCOMUtils.defineLazyServiceGetter(Services, 'env',
'@mozilla.org/process/environment;1',
'nsIEnvironment');
XPCOMUtils.defineLazyGetter(Services, 'ss', function() {
return Cc['@mozilla.org/content/style-sheet-service;1']
.getService(Ci.nsIStyleSheetService);
});
XPCOMUtils.defineLazyServiceGetter(Services, 'ss',
'@mozilla.org/content/style-sheet-service;1',
'nsIStyleSheetService');
XPCOMUtils.defineLazyGetter(Services, 'idle', function() {
return Cc['@mozilla.org/widget/idleservice;1']
.getService(Ci.nsIIdleService);
});
XPCOMUtils.defineLazyServiceGetter(Services, 'idle',
'@mozilla.org/widget/idleservice;1',
'nsIIdleService');
XPCOMUtils.defineLazyGetter(Services, 'audioManager', function() {
#ifdef MOZ_WIDGET_GONK
return Cc['@mozilla.org/telephony/audiomanager;1']
.getService(Ci.nsIAudioManager);
XPCOMUtils.defineLazyServiceGetter(Services, 'audioManager',
'@mozilla.org/telephony/audiomanager;1',
'nsIAudioManager');
#else
return {
"masterVolume": 0
};
Services.audioManager = {
'masterVolume': 0
};
#endif
});
XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function() {
return Cc['@mozilla.org/focus-manager;1']
.getService(Ci.nsFocusManager);
});
XPCOMUtils.defineLazyServiceGetter(Services, 'fm',
'@mozilla.org/focus-manager;1',
'nsIFocusManager');
XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() {
Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
@ -144,9 +139,20 @@ var shell = {
},
stop: function shell_stop() {
['keydown', 'keypress', 'keyup'].forEach((function unlistenKey(type) {
window.removeEventListener(type, this, false, true);
window.removeEventListener(type, this, true, true);
}).bind(this));
window.addEventListener('MozApplicationManifest', this);
window.removeEventListener('MozApplicationManifest', this);
window.removeEventListener('mozfullscreenchange', this);
window.removeEventListener('sizemodechange', this);
this.contentBrowser.removeEventListener('load', this, true);
#ifndef MOZ_WIDGET_GONK
delete Services.audioManager;
#endif
},
toggleDebug: function shell_toggleDebug() {
@ -301,118 +307,6 @@ var shell = {
}
};
(function PowerManager() {
// This will eventually be moved to content, so use content API as
// much as possible here. TODO: Bug 738530
let power = navigator.mozPower;
let idleHandler = function idleHandler(subject, topic, time) {
if (topic === "idle") {
if (power.getWakeLockState("screen") != "locked-foreground") {
navigator.mozPower.screenEnabled = false;
}
}
}
let wakeLockHandler = function wakeLockHandler(topic, state) {
// Turn off the screen when no one needs the it or all of them are
// invisible, otherwise turn the screen on. Note that the CPU
// might go to sleep as soon as the screen is turned off and
// acquiring wake lock will not bring it back (actually the code
// is not executed at all).
if (topic == "screen") {
if (state != "locked-foreground") {
if (Services.idle.idleTime > idleTimeout*1000) {
navigator.mozPower.screenEnabled = false;
}
} else {
navigator.mozPower.screenEnabled = true;
}
}
if (topic == "cpu") {
navigator.mozPower.cpuSleepAllowed = (state != "locked-foreground" &&
state != "locked-background");
}
}
let idleTimeout = Services.prefs.getIntPref("power.screen.timeout");
if (!('mozSettings' in navigator))
return;
let request = navigator.mozSettings.getLock().get("power.screen.timeout");
request.onsuccess = function onSuccess() {
idleTimeout = request.result["power.screen.timeout"] || idleTimeout;
if (idleTimeout) {
Services.idle.addIdleObserver(idleHandler, idleTimeout);
power.addWakeLockListener(wakeLockHandler);
}
};
request.onerror = function onError() {
if (idleTimeout) {
Services.idle.addIdleObserver(idleHandler, idleTimeout);
power.addWakeLockListener(wakeLockHandler);
}
};
// XXX We may override other's callback here, but this is the only
// user of mozSettings in shell.js at this moment.
navigator.mozSettings.onsettingchange = function onSettingChange(e) {
if (e.settingName == "power.screen.timeout" && e.settingValue) {
Services.idle.removeIdleObserver(idleHandler, idleTimeout);
idleTimeout = e.settingValue;
Services.idle.addIdleObserver(idleHandler, idleTimeout);
}
};
})();
const DATA_CALL_SETTING_BOLKEYS = ["ril.data.enabled",
"ril.data.roaming.enabled"];
const DATA_CALL_SETTING_CHARKEYS = ["ril.data.apn",
"ril.data.user",
"ril.data.passwd"];
(function DataCallSettings() {
let sm = navigator.mozSettings;
let lock = sm.getLock();
DATA_CALL_SETTING_BOLKEYS.forEach(function(key) {
let request = lock.get(key);
request.onsuccess = function onSuccess() {
let value = request.result[key] || false;
Services.prefs.setBoolPref(key, value);
dump("DataCallSettings - " + key + ":" + value);
};
request.onerror = function onError() {
Services.prefs.setBoolPref(key, false);
};
});
DATA_CALL_SETTING_CHARKEYS.forEach(function(key) {
let request = lock.get(key);
request.onsuccess = function onSuccess() {
let value = request.result[key] || "";
Services.prefs.setCharPref(key, value);
dump("DataCallSettings - " + key + ":" + value);
};
request.onerror = function onError() {
Services.prefs.setCharPref(key, "");
};
});
navigator.mozSettings.onsettingchange = function onSettingChange(e) {
dump("DataCallSettings - onsettingchange: " + e.settingName +
": " + e.settingValue);
if (e.settingValue) {
if (DATA_CALL_SETTING_BOLKEYS.indexOf(e.settingName) > -1 ) {
Services.prefs.setBoolPref(e.settingName, e.settingValue);
return;
}
if (DATA_CALL_SETTING_CHARKEYS.indexOf(e.settingName) > -1) {
Services.prefs.setCharPref(e.settingName, e.settingValue);
}
}
};
})();
function nsBrowserAccess() {
}
@ -593,7 +487,11 @@ var WebappsHelper = {
return;
let manifest = new DOMApplicationManifest(aManifest, json.origin);
shell.sendEvent(content, "mozChromeEvent", { type: "webapps-launch", url: manifest.fullLaunchPath(), origin: json.origin });
shell.sendEvent(content, "mozChromeEvent", {
"type": "webapps-launch",
"url": manifest.fullLaunchPath(json.startPoint),
"origin": json.origin
});
});
break;
case "webapps-ask-install":
@ -623,4 +521,136 @@ window.addEventListener('ContentStart', function(evt) {
if (Services.prefs.getBoolPref('devtools.debugger.enabled')) {
startDebugger();
}
}, false);
});
// Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget
// is resolved this helper could be removed.
var SettingsListener = {
_callbacks: {},
init: function sl_init() {
if ('mozSettings' in navigator && navigator.mozSettings)
navigator.mozSettings.onsettingchange = this.onchange.bind(this);
},
onchange: function sl_onchange(evt) {
var callback = this._callbacks[evt.settingName];
if (callback) {
callback(evt.settingValue);
}
},
observe: function sl_observe(name, defaultValue, callback) {
var settings = window.navigator.mozSettings;
if (!settings) {
window.setTimeout(function() { callback(defaultValue); });
return;
}
if (!callback || typeof callback !== 'function') {
throw new Error('Callback is not a function');
}
var req = settings.getLock().get(name);
req.addEventListener('success', (function onsuccess() {
callback(typeof(req.result[name]) != 'undefined' ?
req.result[name] : defaultValue);
}));
this._callbacks[name] = callback;
}
};
SettingsListener.init();
SettingsListener.observe('language.current', 'en-US', function(value) {
Services.prefs.setCharPref('intl.accept_languages', value);
});
(function PowerManager() {
// This will eventually be moved to content, so use content API as
// much as possible here. TODO: Bug 738530
let power = navigator.mozPower;
let idleHandler = function idleHandler(subject, topic, time) {
if (topic !== 'idle')
return;
if (power.getWakeLockState("screen") != "locked-foreground") {
navigator.mozPower.screenEnabled = false;
}
}
let wakeLockHandler = function(topic, state) {
// Turn off the screen when no one needs the it or all of them are
// invisible, otherwise turn the screen on. Note that the CPU
// might go to sleep as soon as the screen is turned off and
// acquiring wake lock will not bring it back (actually the code
// is not executed at all).
if (topic === 'screen') {
if (state != "locked-foreground") {
if (Services.idle.idleTime > idleTimeout*1000) {
navigator.mozPower.screenEnabled = false;
}
} else {
navigator.mozPower.screenEnabled = true;
}
} else if (topic == 'cpu') {
navigator.mozPower.cpuSleepAllowed = (state != 'locked-foreground' &&
state != 'locked-background');
}
}
let idleTimeout = Services.prefs.getIntPref('power.screen.timeout');
if (!('mozSettings' in navigator))
return;
let request = navigator.mozSettings.getLock().get('power.screen.timeout');
request.onsuccess = function onSuccess() {
idleTimeout = request.result['power.screen.timeout'] || idleTimeout;
if (!idleTimeout)
return;
Services.idle.addIdleObserver(idleHandler, idleTimeout);
power.addWakeLockListener(wakeLockHandler);
};
request.onerror = function onError() {
if (!idleTimeout)
return;
Services.idle.addIdleObserver(idleHandler, idleTimeout);
power.addWakeLockListener(wakeLockHandler);
};
SettingsListener.observe('power.screen.timeout', 30, function(value) {
if (!value)
return;
Services.idle.removeIdleObserver(idleHandler, idleTimeout);
idleTimeout = value;
Services.idle.addIdleObserver(idleHandler, idleTimeout);
});
window.addEventListener('unload', function removeIdleObjects() {
Services.idle.removeIdleObserver(idleHandler, idleTimeout);
power.removeWakeLockListener(wakeLockHandler);
});
})();
(function RILSettingsToPrefs() {
['ril.data.enabled', 'ril.data.roaming.enabled'].forEach(function(key) {
SettingsListener.observe(key, false, function(value) {
Services.prefs.setBoolPref(key, value);
});
});
['ril.data.apn', 'ril.data.user', 'ril.data.passwd'].forEach(function(key) {
SettingsListener.observe(key, false, function(value) {
Services.prefs.setBoolPref(key, value);
});
});
})();

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

@ -16,9 +16,6 @@
onunload="shell.stop();">
<script type="application/javascript" src="chrome://browser/content/shell.js"/>
#ifndef MOZ_TOUCH
<script type="application/javascript" src="chrome://browser/content/touch.js"/>
#endif
<browser id="homescreen"
type="content-primary"

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

@ -1,201 +0,0 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
(function touchEventHandler() {
let debugging = false;
function debug(str) {
if (debugging)
dump(str + '\n');
};
let contextMenuTimeout = 0;
// This guard is used to not re-enter the events processing loop for
// self dispatched events
let ignoreEvents = false;
// During a 'touchstart' and the first 'touchmove' mouse events can be
// prevented for the current touch sequence.
let canPreventMouseEvents = false;
// Used to track the first mousemove and to cancel click dispatc if it's not
// true.
let isNewTouchAction = false;
// If this is set to true all mouse events will be cancelled by calling
// both evt.preventDefault() and evt.stopPropagation().
// This will not prevent a contextmenu event to be fired.
// This can be turned on if canPreventMouseEvents is true and the consumer
// application call evt.preventDefault();
let preventMouseEvents = false;
let TouchEventHandler = {
events: ['mousedown', 'mousemove', 'mouseup', 'click', 'unload'],
start: function teh_start() {
this.events.forEach((function(evt) {
shell.contentBrowser.addEventListener(evt, this, true);
}).bind(this));
},
stop: function teh_stop() {
this.events.forEach((function(evt) {
shell.contentBrowser.removeEventListener(evt, this, true);
}).bind(this));
},
handleEvent: function teh_handleEvent(evt) {
if (evt.button || ignoreEvents)
return;
let eventTarget = this.target;
let type = '';
switch (evt.type) {
case 'mousedown':
debug('mousedown:');
this.target = evt.target;
this.timestamp = evt.timeStamp;
preventMouseEvents = false;
canPreventMouseEvents = true;
isNewTouchAction = true;
contextMenuTimeout =
this.sendContextMenu(evt.target, evt.pageX, evt.pageY, 2000);
this.startX = evt.pageX;
this.startY = evt.pageY;
type = 'touchstart';
break;
case 'mousemove':
if (!eventTarget)
return;
// On device a mousemove event if fired right after the mousedown
// because of the size of the finger, so let's ignore what happens
// below 5ms
if (evt.timeStamp - this.timestamp < 30)
break;
if (isNewTouchAction) {
canPreventMouseEvents = true;
isNewTouchAction = false;
}
if (Math.abs(this.startX - evt.pageX) > 15 ||
Math.abs(this.startY - evt.pageY) > 15)
window.clearTimeout(contextMenuTimeout);
type = 'touchmove';
break;
case 'mouseup':
if (!eventTarget)
return;
debug('mouseup:');
window.clearTimeout(contextMenuTimeout);
this.target = null;
type = 'touchend';
break;
case 'unload':
if (!eventTarget)
return;
window.clearTimeout(contextMenuTimeout);
this.target = null;
TouchEventHandler.stop();
return;
case 'click':
if (isNewTouchAction) {
// Mouse events has been cancelled so dispatch a sequence
// of events to where touchend has been fired
if (preventMouseEvents) {
evt.preventDefault();
evt.stopPropagation();
let target = evt.target;
ignoreEvents = true;
window.setTimeout(function dispatchMouseEvents(self) {
self.fireMouseEvent('mousemove', evt);
self.fireMouseEvent('mousedown', evt);
self.fireMouseEvent('mouseup', evt);
ignoreEvents = false;
}, 0, this);
}
debug('click: fire');
}
return;
}
let target = eventTarget || this.target;
if (target && type) {
let touchEvent = this.sendTouchEvent(evt, target, type);
if (touchEvent.defaultPrevented && canPreventMouseEvents)
preventMouseEvents = true;
}
if (preventMouseEvents) {
evt.preventDefault();
evt.stopPropagation();
if (type != 'touchmove')
debug('cancelled (fire ' + type + ')');
}
},
fireMouseEvent: function teh_fireMouseEvent(type, evt) {
debug(type + ': fire');
let content = evt.target.ownerDocument.defaultView;
var utils = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
utils.sendMouseEvent(type, evt.pageX, evt.pageY, 0, 1, 0, true);
},
sendContextMenu: function teh_sendContextMenu(target, x, y, delay) {
let doc = target.ownerDocument;
let evt = doc.createEvent('MouseEvent');
evt.initMouseEvent('contextmenu', true, true, doc.defaultView,
0, x, y, x, y, false, false, false, false,
0, null);
let timeout = window.setTimeout((function contextMenu() {
debug('fire context-menu');
target.dispatchEvent(evt);
if (!evt.defaultPrevented)
return;
doc.releaseCapture();
this.target = null;
isNewTouchAction = false;
}).bind(this), delay);
return timeout;
},
sendTouchEvent: function teh_sendTouchEvent(evt, target, name) {
let touchEvent = document.createEvent('touchevent');
let point = document.createTouch(window, target, 0,
evt.pageX, evt.pageY,
evt.screenX, evt.screenY,
evt.clientX, evt.clientY,
1, 1, 0, 0);
let touches = document.createTouchList(point);
let targetTouches = touches;
let changedTouches = touches;
touchEvent.initTouchEvent(name, true, true, window, 0,
false, false, false, false,
touches, targetTouches, changedTouches);
target.dispatchEvent(touchEvent);
return touchEvent;
}
};
window.addEventListener('ContentStart', function touchStart(evt) {
window.removeEventListener('ContentStart', touchStart);
TouchEventHandler.start();
});
})();

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

@ -13,10 +13,9 @@ Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/Geometry.jsm');
XPCOMUtils.defineLazyGetter(Services, 'fm', function() {
return Cc['@mozilla.org/focus-manager;1']
.getService(Ci.nsIFocusManager);
});
XPCOMUtils.defineLazyServiceGetter(Services, 'fm',
'@mozilla.org/focus-manager;1',
'nsIFocusManager');
// MozKeyboard
(function VirtualKeyboardManager() {

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

@ -7,9 +7,6 @@ chrome.jar:
content/dbg-browser-actors.js (content/dbg-browser-actors.js)
* content/shell.xul (content/shell.xul)
* content/shell.js (content/shell.js)
#ifndef MOZ_TOUCH
content/touch.js (content/touch.js)
#endif
content/webapi.js (content/webapi.js)
content/content.css (content/content.css)

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

@ -344,7 +344,7 @@ let TestPilotSetup = {
appcontent.addEventListener("DOMContentLoaded", function(event) {
let newUrl = event.originalTarget.URL;
self._feedbackManager.fillInFeedbackPage(newUrl, window);
for (i = 0; i < self.taskList.length; i++) {
for (let i = 0; i < self.taskList.length; i++) {
self.taskList[i].onUrlLoad(newUrl, event);
}
}, true);

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

@ -873,12 +873,6 @@ pref("places.frecency.unvisitedTypedBonus", 200);
// 2 - pre-populate site URL and pre-fetch certificate
pref("browser.ssl_override_behavior", 2);
// Controls the display of domain in the identity box for SSL connections.
// 0 - do not show domain
// 1 - show effectiveTLD + 1 (e.g. mozilla.org)
// 2 - show full domain (e.g. bugzilla.mozilla.org)
pref("browser.identity.ssl_domain_display", 0);
// True if the user should be prompted when a web application supports
// offline apps.
pref("browser.offline-apps.notify", true);
@ -1061,6 +1055,9 @@ pref("devtools.debugger.enabled", false);
pref("devtools.debugger.remote-enabled", false);
pref("devtools.debugger.remote-host", "localhost");
pref("devtools.debugger.remote-port", 6000);
pref("devtools.debugger.remote-autoconnect", false);
pref("devtools.debugger.remote-connection-retries", 3);
pref("devtools.debugger.remote-timeout", 3000);
// The default Debugger UI height
pref("devtools.debugger.ui.height", 250);

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

@ -1025,27 +1025,31 @@ let gGestureSupport = {
switch (aEvent.type) {
case "MozSwipeGesture":
aEvent.preventDefault();
return this.onSwipe(aEvent);
this.onSwipe(aEvent);
break;
case "MozMagnifyGestureStart":
aEvent.preventDefault();
#ifdef XP_WIN
return this._setupGesture(aEvent, "pinch", def(25, 0), "out", "in");
this._setupGesture(aEvent, "pinch", def(25, 0), "out", "in");
#else
return this._setupGesture(aEvent, "pinch", def(150, 1), "out", "in");
this._setupGesture(aEvent, "pinch", def(150, 1), "out", "in");
#endif
break;
case "MozRotateGestureStart":
aEvent.preventDefault();
return this._setupGesture(aEvent, "twist", def(25, 0), "right", "left");
this._setupGesture(aEvent, "twist", def(25, 0), "right", "left");
break;
case "MozMagnifyGestureUpdate":
case "MozRotateGestureUpdate":
aEvent.preventDefault();
return this._doUpdate(aEvent);
this._doUpdate(aEvent);
break;
case "MozTapGesture":
aEvent.preventDefault();
return this._doAction(aEvent, ["tap"]);
case "MozPressTapGesture":
// Fall through to default behavior
return;
this._doAction(aEvent, ["tap"]);
break;
/* case "MozPressTapGesture":
break; */
}
},
@ -1130,8 +1134,6 @@ let gGestureSupport = {
* The original gesture event to convert into a fake click event
* @param aGesture
* Array of gesture name parts (to be joined by periods)
* @return Name of the command found for the event's keys and gesture. If no
* command is found, no value is returned (undefined).
*/
_doAction: function GS__doAction(aEvent, aGesture) {
// Create an array of pressed keys in a fixed order so that a command for
@ -1169,9 +1171,8 @@ let gGestureSupport = {
goDoCommand(command);
}
return command;
break;
}
return null;
},
/**
@ -1192,10 +1193,12 @@ let gGestureSupport = {
*/
onSwipe: function GS_onSwipe(aEvent) {
// Figure out which one (and only one) direction was triggered
["UP", "RIGHT", "DOWN", "LEFT"].forEach(function (dir) {
if (aEvent.direction == aEvent["DIRECTION_" + dir])
return this._doAction(aEvent, ["swipe", dir.toLowerCase()]);
}, this);
for (let dir of ["UP", "RIGHT", "DOWN", "LEFT"]) {
if (aEvent.direction == aEvent["DIRECTION_" + dir]) {
this._doAction(aEvent, ["swipe", dir.toLowerCase()]);
break;
}
}
},
/**
@ -5201,10 +5204,13 @@ var TabsProgressListener = {
aFlags) {
// Filter out any sub-frame loads
if (aBrowser.contentWindow == aWebProgress.DOMWindow) {
// initialize the click-to-play state
aBrowser._clickToPlayDoorhangerShown = false;
aBrowser._clickToPlayPluginsActivated = false;
// Filter out any onLocationChanges triggered by anchor navigation
// or history.push/pop/replaceState.
if (aRequest) {
// Initialize the click-to-play state.
aBrowser._clickToPlayDoorhangerShown = false;
aBrowser._clickToPlayPluginsActivated = false;
}
FullZoom.onLocationChange(aLocationURI, false, aBrowser);
}
},
@ -8199,30 +8205,19 @@ var gIdentityHandler = {
* @param newMode The newly set identity mode. Should be one of the IDENTITY_MODE_* constants.
*/
setIdentityMessages : function(newMode) {
if (newMode == this.IDENTITY_MODE_DOMAIN_VERIFIED) {
var iData = this.getIdentityData();
let icon_label = "";
let tooltip = "";
let icon_country_label = "";
let icon_labels_dir = "ltr";
// It would be sort of nice to use the CN= field in the cert, since that's
// typically what we want here, but thanks to x509 certs being extensible,
// it's not the only place you have to check, there can be more than one domain,
// et cetera, ad nauseum. We know the cert is valid for location.host, so
// let's just use that. Check the pref to determine how much of the verified
// hostname to show
var icon_label = "";
var icon_country_label = "";
var icon_labels_dir = "ltr";
switch (gPrefService.getIntPref("browser.identity.ssl_domain_display")) {
case 2 : // Show full domain
icon_label = this._lastLocation.hostname;
break;
case 1 : // Show eTLD.
icon_label = this.getEffectiveHost();
}
switch (newMode) {
case this.IDENTITY_MODE_DOMAIN_VERIFIED: {
let iData = this.getIdentityData();
// Verifier is either the CA Org, for a normal cert, or a special string
// for certs that are trusted because of a security exception.
var tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
[iData.caOrg]);
tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
[iData.caOrg]);
// Check whether this site is a security exception. XPConnect does the right
// thing here in terms of converting _lastLocation.port from string to int, but
@ -8237,15 +8232,16 @@ var gIdentityHandler = {
(this._lastLocation.port || 443),
iData.cert, {}, {}))
tooltip = gNavigatorBundle.getString("identity.identified.verified_by_you");
}
else if (newMode == this.IDENTITY_MODE_IDENTIFIED) {
break; }
case this.IDENTITY_MODE_IDENTIFIED: {
// If it's identified, then we can populate the dialog with credentials
iData = this.getIdentityData();
let iData = this.getIdentityData();
tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
[iData.caOrg]);
icon_label = iData.subjectOrg;
if (iData.country)
icon_country_label = "(" + iData.country + ")";
// If the organization name starts with an RTL character, then
// swap the positions of the organization and country code labels.
// The Unicode ranges reflect the definition of the UCS2_CHAR_IS_BIDI
@ -8254,18 +8250,11 @@ var gIdentityHandler = {
// Unicode Bidirectional Algorithm proper (at the paragraph level).
icon_labels_dir = /^[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufefc]/.test(icon_label) ?
"rtl" : "ltr";
}
else if (newMode == this.IDENTITY_MODE_CHROMEUI) {
icon_label = "";
tooltip = "";
icon_country_label = "";
icon_labels_dir = "ltr";
}
else {
break; }
case this.IDENTITY_MODE_CHROMEUI:
break;
default:
tooltip = gNavigatorBundle.getString("identity.unknown.tooltip");
icon_label = "";
icon_country_label = "";
icon_labels_dir = "ltr";
}
// Push the appropriate strings out to the UI
@ -8295,19 +8284,20 @@ var gIdentityHandler = {
this._identityPopupEncLabel.textContent = this._encryptionLabel[newMode];
// Initialize the optional strings to empty values
var supplemental = "";
var verifier = "";
let supplemental = "";
let verifier = "";
let host = "";
let owner = "";
if (newMode == this.IDENTITY_MODE_DOMAIN_VERIFIED) {
var iData = this.getIdentityData();
var host = this.getEffectiveHost();
var owner = gNavigatorBundle.getString("identity.ownerUnknown2");
switch (newMode) {
case this.IDENTITY_MODE_DOMAIN_VERIFIED:
host = this.getEffectiveHost();
owner = gNavigatorBundle.getString("identity.ownerUnknown2");
verifier = this._identityBox.tooltipText;
supplemental = "";
}
else if (newMode == this.IDENTITY_MODE_IDENTIFIED) {
break;
case this.IDENTITY_MODE_IDENTIFIED: {
// If it's identified, then we can populate the dialog with credentials
iData = this.getIdentityData();
let iData = this.getIdentityData();
host = this.getEffectiveHost();
owner = iData.subjectOrg;
verifier = this._identityBox.tooltipText;
@ -8322,11 +8312,7 @@ var gIdentityHandler = {
supplemental += iData.state;
else if (iData.country) // Country only
supplemental += iData.country;
}
else {
// These strings will be hidden in CSS anyhow
host = "";
owner = "";
break; }
}
// Push the appropriate strings out to the UI

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

@ -775,7 +775,8 @@ nsContextMenu.prototype = {
urlSecurityCheck(frameURL, this.browser.contentPrincipal,
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
var referrer = doc.referrer;
this.browser.loadURI(frameURL, referrer ? makeURI(referrer) : null);
openUILinkIn(frameURL, "current", { disallowInheritPrincipal: true,
referrerURI: referrer ? makeURI(referrer) : null });
},
// View Partial Source
@ -847,7 +848,8 @@ nsContextMenu.prototype = {
}
var doc = this.target.ownerDocument;
openUILink(viewURL, e, null, null, null, null, doc.documentURIObject );
openUILink(viewURL, e, { disallowInheritPrincipal: true,
referrerURI: doc.documentURIObject });
},
saveVideoFrameAsImage: function () {
@ -883,7 +885,8 @@ nsContextMenu.prototype = {
this.browser.contentPrincipal,
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
var doc = this.target.ownerDocument;
openUILink(this.bgImageURL, e, null, null, null, null, doc.documentURIObject );
openUILink(this.bgImageURL, e, { disallowInheritPrincipal: true,
referrerURI: doc.documentURIObject });
},
disableSetDesktopBackground: function() {

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

@ -181,6 +181,8 @@ _BROWSER_FILES = \
browser_bug664672.js \
browser_bug710878.js \
browser_bug719271.js \
browser_bug743421.js \
browser_bug749738.js \
browser_canonizeURL.js \
browser_findbarClose.js \
browser_homeDrop.js \
@ -253,6 +255,7 @@ _BROWSER_FILES = \
plugin_alternate_content.html \
plugin_both.html \
plugin_both2.html \
plugin_bug743421.html \
plugin_clickToPlayAllow.html \
plugin_clickToPlayDeny.html \
alltabslistener.html \
@ -278,6 +281,7 @@ _BROWSER_FILES = \
redirect_bug623155.sjs \
browser_tabDrop.js \
browser_lastAccessedTab.js \
browser_bug734076.js \
$(NULL)
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))

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

@ -0,0 +1,107 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let tab = gBrowser.selectedTab = gBrowser.addTab();
registerCleanupFunction(function () {
gBrowser.removeTab(tab);
});
let browser = tab.linkedBrowser;
browser.stop(); // stop the about:blank load
let writeDomainURL = encodeURI("data:text/html,<script>document.write(document.domain);</script>");
let tests = [
{
name: "view background image",
url: "http://mochi.test:8888/",
go: function (cb) {
let contentBody = browser.contentDocument.body;
contentBody.style.backgroundImage = "url('" + writeDomainURL + "')";
doOnLoad(function () {
let domain = browser.contentDocument.body.textContent;
is(domain, "", "no domain was inherited for view background image");
cb();
});
let contextMenu = initContextMenu(contentBody);
contextMenu.viewBGImage();
}
},
{
name: "view image",
url: "http://mochi.test:8888/",
go: function (cb) {
doOnLoad(function () {
let domain = browser.contentDocument.body.textContent;
is(domain, "", "no domain was inherited for view image");
cb();
});
let doc = browser.contentDocument;
let img = doc.createElement("img");
img.setAttribute("src", writeDomainURL);
doc.body.appendChild(img);
let contextMenu = initContextMenu(img);
contextMenu.viewMedia();
}
},
{
name: "show only this frame",
url: "http://mochi.test:8888/",
go: function (cb) {
doOnLoad(function () {
let domain = browser.contentDocument.body.textContent;
is(domain, "", "no domain was inherited for 'show only this frame'");
cb();
});
let doc = browser.contentDocument;
let iframe = doc.createElement("iframe");
iframe.setAttribute("src", writeDomainURL);
doc.body.appendChild(iframe);
iframe.addEventListener("load", function onload() {
let contextMenu = initContextMenu(iframe.contentDocument.body);
contextMenu.showOnlyThisFrame();
}, false);
}
}
];
function doOnLoad(cb) {
browser.addEventListener("load", function onLoad(e) {
if (e.target != browser.contentDocument)
return;
browser.removeEventListener("load", onLoad, true);
cb();
}, true);
}
function doNext() {
let test = tests.shift();
if (test) {
info("Running test: " + test.name);
doOnLoad(function () {
test.go(function () {
executeSoon(doNext);
});
});
browser.contentDocument.location = test.url;
} else {
executeSoon(finish);
}
}
doNext();
}
function initContextMenu(aNode) {
document.popupNode = aNode;
let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
let contextMenu = new nsContextMenu(contentAreaContextMenu, gBrowser);
return contextMenu;
}

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

@ -0,0 +1,107 @@
var rootDir = getRootDirectory(gTestPath);
const gTestRoot = rootDir;
var gTestBrowser = null;
var gNextTest = null;
Components.utils.import("resource://gre/modules/Services.jsm");
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() { Services.prefs.clearUserPref("plugins.click_to_play"); });
Services.prefs.setBoolPref("plugins.click_to_play", true);
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
gTestBrowser.addEventListener("load", pageLoad, true);
prepareTest(test1a, gTestRoot + "plugin_bug743421.html");
}
function finishTest() {
gTestBrowser.removeEventListener("load", pageLoad, true);
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function pageLoad() {
// The plugin events are async dispatched and can come after the load event
// This just allows the events to fire before we then go on to test the states
executeSoon(gNextTest);
}
function prepareTest(nextTest, url) {
gNextTest = nextTest;
gTestBrowser.contentWindow.location = url;
}
// Tests that navigation within the page and the window.history API doesn't break click-to-play state.
function test1a() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1a, Should not have a click-to-play notification");
var plugin = gTestBrowser.contentWindow.addPlugin();
setTimeout(test1b, 500);
}
function test1b() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(popupNotification, "Test 1b, Should have a click-to-play notification");
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0];
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(!objLoadingContent.activated, "Test 1b, Plugin should not be activated");
EventUtils.synthesizeMouse(plugin, 100, 100, { });
setTimeout(test1c, 500);
}
function test1c() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1c, Should not have a click-to-play notification");
var plugin = gTestBrowser.contentWindow.addPlugin();
setTimeout(test1d, 500);
}
function test1d() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1d, Should not have a click-to-play notification");
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[1];
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 1d, Plugin should be activated");
gNextTest = test1e;
gTestBrowser.contentWindow.addEventListener("hashchange", test1e, false);
gTestBrowser.contentWindow.location += "#anchorNavigation";
}
function test1e() {
gTestBrowser.contentWindow.removeEventListener("hashchange", test1e, false);
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1e, Should not have a click-to-play notification");
var plugin = gTestBrowser.contentWindow.addPlugin();
setTimeout(test1f, 500);
}
function test1f() {
var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification, "Test 1f, Should not have a click-to-play notification");
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[2];
var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent.activated, "Test 1f, Plugin should be activated");
gTestBrowser.contentWindow.history.replaceState({}, "", "replacedState");
gTestBrowser.contentWindow.addPlugin();
setTimeout(test1g, 500);
}
function test1g() {
var popupNotification2 = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
ok(!popupNotification2, "Test 1g, Should not have a click-to-play notification after replaceState");
var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[3];
var objLoadingContent2 = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
ok(objLoadingContent2.activated, "Test 1g, Plugin should be activated");
finishTest();
}

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

@ -0,0 +1,36 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const DUMMY_PAGE = "http://example.org/browser/browser/base/content/test/dummy_page.html";
function test() {
waitForExplicitFinish();
let tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
load(tab, DUMMY_PAGE, function() {
gFindBar.onFindCommand();
EventUtils.sendString("Dummy");
gBrowser.removeTab(tab);
try {
gFindBar.close();
ok(true, "findbar.close should not throw an exception");
} catch(e) {
ok(false, "findbar.close threw exception: " + e);
}
finish();
});
}
function load(aTab, aUrl, aCallback) {
aTab.linkedBrowser.addEventListener("load", function onload(aEvent) {
aEvent.currentTarget.removeEventListener("load", onload, true);
waitForFocus(aCallback, content);
}, true);
aTab.linkedBrowser.loadURI(aUrl);
}

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

@ -1,9 +1,6 @@
/* Tests for correct behaviour of getEffectiveHost on identity handler */
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
Services.prefs.clearUserPref("browser.identity.ssl_domain_display");
});
ok(gIdentityHandler, "gIdentityHandler should exist");
@ -102,7 +99,6 @@ function nextTest() {
gTestDesc += " (second time)";
if (gCurrentTest.isHTTPS) {
gCheckETLD = true;
Services.prefs.setIntPref("browser.identity.ssl_domain_display", 1);
}
content.location = gCurrentTest.location;
} else {
@ -110,18 +106,11 @@ function nextTest() {
gTestDesc = "#" + gCurrentTestIndex + " (" + gCurrentTest.name + " without eTLD in identity icon label)";
if (!gForward)
gTestDesc += " (second time)";
Services.prefs.clearUserPref("browser.identity.ssl_domain_display");
content.location.reload(true);
}
}
function checkResult() {
if (gCurrentTest.isHTTPS && Services.prefs.getIntPref("browser.identity.ssl_domain_display") == 1) {
// Check that the effective host is displayed in the UI
let label = document.getElementById("identity-icon-label");
is(label.value, gCurrentTest.effectiveHost, "effective host is displayed in identity icon label for test " + gTestDesc);
}
// Sanity check other values, and the value of gIdentityHandler.getEffectiveHost()
is(gIdentityHandler._lastLocation.host, gCurrentTest.host, "host matches for test " + gTestDesc);
is(gIdentityHandler.getEffectiveHost(), gCurrentTest.effectiveHost, "effectiveHost matches for test " + gTestDesc);

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

@ -191,7 +191,7 @@ var wrongBrowserNotification;
var tests = [
{ // Test #0
run: function () {
this.notifyObj = new basicNotification(),
this.notifyObj = new basicNotification();
showNotification(this.notifyObj);
},
onShown: function (popup) {
@ -206,7 +206,7 @@ var tests = [
},
{ // Test #1
run: function () {
this.notifyObj = new basicNotification(),
this.notifyObj = new basicNotification();
showNotification(this.notifyObj);
},
onShown: function (popup) {
@ -221,7 +221,7 @@ var tests = [
},
{ // Test #2
run: function () {
this.notifyObj = new basicNotification(),
this.notifyObj = new basicNotification();
this.notification = showNotification(this.notifyObj);
},
onShown: function (popup) {
@ -285,7 +285,7 @@ var tests = [
// notification.
{ // Test #6
run: function () {
this.notifyObj = new basicNotification(),
this.notifyObj = new basicNotification();
// Show the same notification twice
this.notification1 = showNotification(this.notifyObj);
this.notification2 = showNotification(this.notifyObj);
@ -332,7 +332,7 @@ var tests = [
// Test notification without mainAction
{ // Test #8
run: function () {
this.notifyObj = new basicNotification(),
this.notifyObj = new basicNotification();
this.notifyObj.mainAction = null;
this.notification = showNotification(this.notifyObj);
},
@ -568,7 +568,7 @@ var tests = [
// Test notification "Not Now" menu item
{ // Test #17
run: function () {
this.notifyObj = new basicNotification(),
this.notifyObj = new basicNotification();
this.notification = showNotification(this.notifyObj);
},
onShown: function (popup) {
@ -584,7 +584,7 @@ var tests = [
// Test notification close button
{ // Test #18
run: function () {
this.notifyObj = new basicNotification(),
this.notifyObj = new basicNotification();
this.notification = showNotification(this.notifyObj);
},
onShown: function (popup) {
@ -677,7 +677,7 @@ var tests = [
this.notification2.remove();
ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered");
}
],
]
},
// Test that multiple notification icons are removed when switching tabs
{ // Test #22
@ -718,7 +718,7 @@ var tests = [
gBrowser.selectedTab = this.oldSelectedTab;
this.notificationOld.remove();
}
],
]
}
];

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

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script>
function addPlugin(callback) {
var embed = document.createElement("embed");
embed.style.width = "200px";
embed.style.height = "200px";
embed.setAttribute("type", "application/x-test");
return document.body.appendChild(embed);
}
</script>
</body>
</html>

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

@ -2901,11 +2901,6 @@ SessionStoreService.prototype = {
ScratchpadManager.restoreSession(aState.scratchpads);
}
// This will force the keypress listener that Panorama has to attach if it
// isn't already. This will be the case if tab view wasn't entered or there
// were only visible tabs when TabView.init was first called.
aWindow.TabView.init();
// set smoothScroll back to the original value
tabstrip.smoothScroll = smoothScroll;

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

@ -7,7 +7,11 @@ export MOZILLA_OFFICIAL=1
mk_add_options MOZ_MAKE_FLAGS=-j1
. $topsrcdir/build/win32/mozconfig.vs2010
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
. $topsrcdir/build/win32/mozconfig.vs2010-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

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

@ -3,4 +3,8 @@ ac_add_options --enable-update-packaging
ac_add_options --enable-official-branding
ac_add_options --with-l10n-base=../../l10n-central
. $topsrcdir/build/win32/mozconfig.vs2010
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
. $topsrcdir/build/win32/mozconfig.vs2010-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi

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

@ -16,7 +16,11 @@ export MOZ_TELEMETRY_REPORTING=1
mk_add_options MOZ_MAKE_FLAGS=-j1
. $topsrcdir/build/win32/mozconfig.vs2010
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
. $topsrcdir/build/win32/mozconfig.vs2010-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

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

@ -12,7 +12,11 @@ export MOZILLA_OFFICIAL=1
export MOZ_TELEMETRY_REPORTING=1
. $topsrcdir/build/win32/mozconfig.vs2010
if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
. $topsrcdir/build/win32/mozconfig.vs2010-win64
else
. $topsrcdir/build/win32/mozconfig.vs2010
fi
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1

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

@ -46,6 +46,7 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const DBG_XUL = "chrome://browser/content/debugger.xul";
const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
const REMOTE_PROFILE_NAME = "_remote-debug";
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
@ -82,24 +83,22 @@ DebuggerUI.prototype = {
},
/**
* Starts a remote debugger in a new process, or stops it if already started.
* @see DebuggerProcess.constructor
* @return DebuggerProcess if the debugger is started, null if it's stopped.
* Starts a remote debugger in a new window, or stops it if already started.
* @return RemoteDebuggerWindow if the debugger is started, null if stopped.
*/
toggleRemoteDebugger: function DUI_toggleRemoteDebugger(aOnClose, aOnRun) {
toggleRemoteDebugger: function DUI_toggleRemoteDebugger() {
let win = this.chromeWindow;
if (win._remoteDebugger) {
win._remoteDebugger.close();
return null;
}
return new DebuggerProcess(win, aOnClose, aOnRun);
return new RemoteDebuggerWindow(this);
},
/**
* Starts a chrome debugger in a new process, or stops it if already started.
* @see DebuggerProcess.constructor
* @return DebuggerProcess if the debugger is started, null if it's stopped.
* @return ChromeDebuggerProcess if the debugger is started, null if stopped.
*/
toggleChromeDebugger: function DUI_toggleChromeDebugger(aOnClose, aOnRun) {
let win = this.chromeWindow;
@ -108,17 +107,35 @@ DebuggerUI.prototype = {
win._chromeDebugger.close();
return null;
}
return new DebuggerProcess(win, aOnClose, aOnRun, true);
return new ChromeDebuggerProcess(win, aOnClose, aOnRun, true);
},
/**
* Get the debugger for a specified tab.
* @return DebuggerPane if a debugger exists for the tab, null otherwise
* @return DebuggerPane if a debugger exists for the tab, null otherwise.
*/
getDebugger: function DUI_getDebugger(aTab) {
return aTab._scriptDebugger;
},
/**
* Get the remote debugger for the current chrome window.
* @return RemoteDebuggerWindow if a remote debugger exists, null otherwise.
*/
getRemoteDebugger: function DUI_getRemoteDebugger() {
let win = this.chromeWindow;
return '_remoteDebugger' in win ? win._remoteDebugger : null;
},
/**
* Get the chrome debugger for the current firefox instance.
* @return ChromeDebuggerProcess if a chrome debugger exists, null otherwise.
*/
getChromeDebugger: function DUI_getChromeDebugger() {
let win = this.chromeWindow;
return '_chromeDebugger' in win ? win._chromeDebugger : null;
},
/**
* Get the preferences associated with the debugger frontend.
* @return object
@ -131,12 +148,14 @@ DebuggerUI.prototype = {
/**
* Creates a pane that will host the debugger.
*
* @param DebuggerUI aDebuggerUI
* The parent instance creating the new debugger.
* @param XULElement aTab
* The tab in which to create the debugger.
*/
function DebuggerPane(aTab) {
this._tab = aTab;
this._initServer();
this._create();
}
@ -181,7 +200,7 @@ DebuggerPane.prototype = {
self._frame.addEventListener("unload", self.close, true);
// Bind shortcuts for accessing the breakpoint methods in the debugger.
let bkp = self.debuggerWindow.DebuggerController.Breakpoints;
let bkp = self.contentWindow.DebuggerController.Breakpoints;
self.addBreakpoint = bkp.addBreakpoint;
self.removeBreakpoint = bkp.removeBreakpoint;
self.getBreakpoint = bkp.getBreakpoint;
@ -216,7 +235,7 @@ DebuggerPane.prototype = {
* Gets the debugger content window.
* @return nsIDOMWindow if a debugger window exists, null otherwise
*/
get debuggerWindow() {
get contentWindow() {
return this._frame ? this._frame.contentWindow : null;
},
@ -225,38 +244,115 @@ DebuggerPane.prototype = {
* @return object if a debugger window exists, null otherwise
*/
get breakpoints() {
let debuggerWindow = this.debuggerWindow;
if (debuggerWindow) {
return debuggerWindow.DebuggerController.Breakpoints.store;
let contentWindow = this.contentWindow;
if (contentWindow) {
return contentWindow.DebuggerController.Breakpoints.store;
}
return null;
}
};
/**
* Creates a process that will hold the remote debugger.
* Creates a window that will host a remote debugger.
*
* @param DebuggerUI aDebuggerUI
* The parent instance creating the new debugger.
*/
function RemoteDebuggerWindow(aDebuggerUI) {
this._globalUI = aDebuggerUI;
this._win = aDebuggerUI.chromeWindow;
this._create();
}
RemoteDebuggerWindow.prototype = {
/**
* Creates and initializes the widgets containing the remote debugger UI.
*/
_create: function DP__create() {
this._win._remoteDebugger = this;
this._dbgwin = this._globalUI.chromeWindow.open(DBG_XUL,
L10N.getStr("remoteDebuggerWindowTitle"),
"width=" + DebuggerPreferences.remoteWinWidth + "," +
"height=" + DebuggerPreferences.remoteWinHeight + "," +
"chrome,dependent,resizable,centerscreen");
this._dbgwin._remoteFlag = true;
this.close = this.close.bind(this);
let self = this;
this._dbgwin.addEventListener("Debugger:Loaded", function dbgLoaded() {
self._dbgwin.removeEventListener("Debugger:Loaded", dbgLoaded, true);
self._dbgwin.addEventListener("Debugger:Close", self.close, true);
self._dbgwin.addEventListener("unload", self.close, true);
// Bind shortcuts for accessing the breakpoint methods in the debugger.
let bkp = self.contentWindow.DebuggerController.Breakpoints;
self.addBreakpoint = bkp.addBreakpoint;
self.removeBreakpoint = bkp.removeBreakpoint;
self.getBreakpoint = bkp.getBreakpoint;
}, true);
},
/**
* Closes the remote debugger, along with the parent window if necessary.
*/
close: function DP_close() {
if (!this._win) {
return;
}
delete this._win._remoteDebugger;
this._win = null;
this._dbgwin.close();
this._dbgwin = null;
},
/**
* Gets the remote debugger content window.
* @return nsIDOMWindow if a debugger window exists, null otherwise.
*/
get contentWindow() {
return this._dbgwin;
},
/**
* Shortcut for accessing the list of breakpoints in the remote debugger.
* @return object if a debugger window exists, null otherwise.
*/
get breakpoints() {
let contentWindow = this.contentWindow;
if (contentWindow) {
return contentWindow.DebuggerController.Breakpoints.store;
}
return null;
}
};
/**
* Creates a process that will hold a chrome debugger.
*
* @param function aOnClose
* Optional, a function called when the process exits.
* @param function aOnRun
* Optional, a function called when the process starts running.
* @param boolean aInitServerFlag
* True to initialize the server. This should happen only in the chrome
* debugging case. This should also be true by default after bug #747429.
* @param nsIDOMWindow aWindow
* The chrome window for which the remote debugger instance is created.
* The chrome window for which the debugger instance is created.
*/
function DebuggerProcess(aWindow, aOnClose, aOnRun, aInitServerFlag) {
function ChromeDebuggerProcess(aWindow, aOnClose, aOnRun) {
this._win = aWindow;
this._closeCallback = aOnClose;
this._runCallback = aOnRun;
aInitServerFlag && this._initServer();
this._initServer();
this._initProfile();
this._create();
}
DebuggerProcess.prototype = {
ChromeDebuggerProcess.prototype = {
/**
* Initializes the debugger server.
@ -293,7 +389,7 @@ DebuggerProcess.prototype = {
* Creates and initializes the profile & process for the remote debugger.
*/
_create: function RDP__create() {
this._win._remoteDebugger = this;
this._win._chromeDebugger = this;
let file = FileUtils.getFile("CurProcD",
[Services.appinfo.OS == "WINNT" ? "firefox.exe"
@ -323,7 +419,7 @@ DebuggerProcess.prototype = {
if (!this._win) {
return;
}
delete this._win._remoteDebugger;
delete this._win._chromeDebugger;
this._win = null;
if (this._dbgProcess.isRunning) {
@ -341,6 +437,26 @@ DebuggerProcess.prototype = {
}
};
/**
* Localization convenience methods.
*/
let L10N = {
/**
* L10N shortcut function.
*
* @param string aName
* @return string
*/
getStr: function L10N_getStr(aName) {
return this.stringBundle.GetStringFromName(aName);
}
};
XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
return Services.strings.createBundle(DBG_STRINGS_URI);
});
/**
* Various debugger preferences.
*/

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

@ -87,6 +87,7 @@ let DebuggerController = {
DebuggerView.StackFrames.initialize();
DebuggerView.Properties.initialize();
DebuggerView.Scripts.initialize();
DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger);
this.dispatchEvent("Debugger:Loaded");
this._connect();
@ -114,7 +115,48 @@ let DebuggerController = {
this.dispatchEvent("Debugger:Unloaded");
this._disconnect();
this._isRemote && this._quitApp();
this._isChromeDebugger && this._quitApp();
},
/**
* Prepares the hostname and port number for a remote debugger connection
* and handles connection retries and timeouts.
*
* @return boolean true if connection should proceed normally
*/
_prepareConnection: function DC__prepareConnection() {
// If we exceeded the total number of connection retries, bail.
if (this._remoteConnectionTry === Prefs.remoteConnectionRetries) {
Services.prompt.alert(null,
L10N.getStr("remoteDebuggerPromptTitle"),
L10N.getStr("remoteDebuggerConnectionFailedMessage"));
this.dispatchEvent("Debugger:Close");
return false;
}
// TODO: This is ugly, need to rethink the design for the UI in #751677.
if (!Prefs.remoteAutoConnect) {
let prompt = new RemoteDebuggerPrompt();
let result = prompt.show(!!this._remoteConnectionTimeout);
if (!result) {
this.dispatchEvent("Debugger:Close");
return false;
}
Prefs.remoteHost = prompt.uri.host;
Prefs.remotePort = prompt.uri.port;
}
// If this debugger is connecting remotely to a server, we need to check
// after a while if the connection actually succeeded.
this._remoteConnectionTry = ++this._remoteConnectionTry || 1;
this._remoteConnectionTimeout = window.setTimeout(function() {
// If we couldn't connect to any server yet, try again...
if (!DebuggerController.activeThread) {
DebuggerController._connect();
}
}, Prefs.remoteTimeout);
return true;
},
/**
@ -122,9 +164,15 @@ let DebuggerController = {
* wiring event handlers as necessary.
*/
_connect: function DC__connect() {
let transport =
this._isRemote ? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort)
: DebuggerServer.connectPipe();
if (this._isRemoteDebugger) {
if (!this._prepareConnection()) {
return;
}
}
let transport = (this._isChromeDebugger || this._isRemoteDebugger)
? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort)
: DebuggerServer.connectPipe();
let client = this.client = new DebuggerClient(transport);
@ -223,8 +271,16 @@ let DebuggerController = {
* Returns true if this is a remote debugger instance.
* @return boolean
*/
get _isRemote() {
return !window.parent.content;
get _isRemoteDebugger() {
return window._remoteFlag;
},
/**
* Returns true if this is a chrome debugger instance.
* @return boolean
*/
get _isChromeDebugger() {
return !window.parent.content && !this._isRemoteDebugger;
},
/**
@ -1325,7 +1381,29 @@ XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
/**
* Shortcuts for accessing various debugger preferences.
*/
let Prefs = {};
let Prefs = {
/**
* Gets a flag specifying if the the debugger should automatically connect to
* the default host and port number.
* @return boolean
*/
get remoteAutoConnect() {
if (this._autoConn === undefined) {
this._autoConn = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
}
return this._autoConn;
},
/**
* Sets a flag specifying if the the debugger should automatically connect.
* @param boolean value
*/
set remoteAutoConnect(value) {
Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", value);
this._autoConn = value;
}
};
/**
* Gets the preferred default remote debugging host.
@ -1343,6 +1421,22 @@ XPCOMUtils.defineLazyGetter(Prefs, "remotePort", function() {
return Services.prefs.getIntPref("devtools.debugger.remote-port");
});
/**
* Gets the max number of attempts to reconnect to a remote server.
* @return number
*/
XPCOMUtils.defineLazyGetter(Prefs, "remoteConnectionRetries", function() {
return Services.prefs.getIntPref("devtools.debugger.remote-connection-retries");
});
/**
* Gets the remote debugging connection timeout (in milliseconds).
* @return number
*/
XPCOMUtils.defineLazyGetter(Prefs, "remoteTimeout", function() {
return Services.prefs.getIntPref("devtools.debugger.remote-timeout");
});
/**
* Preliminary setup for the DebuggerController object.
*/

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

@ -82,6 +82,61 @@ let DebuggerView = {
*/
_onEditorLoad: function DV__onEditorLoad() {
DebuggerController.Breakpoints.initialize();
},
/**
* Sets the close button hidden or visible. It's hidden by default.
* @param boolean aVisibleFlag
*/
showCloseButton: function DV_showCloseButton(aVisibleFlag) {
document.getElementById("close").setAttribute("hidden", !aVisibleFlag);
}
};
/**
* A simple way of displaying a "Connect to..." prompt.
*/
function RemoteDebuggerPrompt() {
/**
* The remote uri the user wants to connect to.
*/
this.uri = null;
}
RemoteDebuggerPrompt.prototype = {
/**
* Shows the prompt and sets the uri using the user input.
*
* @param boolean aIsReconnectingFlag
* True to show the reconnect message instead.
*/
show: function RDP_show(aIsReconnectingFlag) {
let check = { value: Prefs.remoteAutoConnect };
let input = { value: "http://" + Prefs.remoteHost +
":" + Prefs.remotePort + "/" };
while (true) {
let result = Services.prompt.prompt(null,
L10N.getStr("remoteDebuggerPromptTitle"),
L10N.getStr(aIsReconnectingFlag
? "remoteDebuggerReconnectMessage"
: "remoteDebuggerPromptMessage"), input,
L10N.getStr("remoteDebuggerPromptCheck"), check);
Prefs.remoteAutoConnect = check.value;
try {
let uri = Services.io.newURI(input.value, null, null);
let url = uri.QueryInterface(Ci.nsIURL);
// If a url could be successfully retrieved, then the uri is correct.
this.uri = uri;
return result;
}
catch(e) { }
}
}
};

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

@ -75,7 +75,7 @@
<div id="body" class="vbox flex">
<xul:toolbar id="dbg-toolbar">
<xul:button id="close">&debuggerUI.closeButton;</xul:button>
<xul:button id="close" hidden="false">&debuggerUI.closeButton;</xul:button>
<xul:button id="resume"/>
<xul:button id="step-over">&debuggerUI.stepOverButton;</xul:button>
<xul:button id="step-in">&debuggerUI.stepInButton;</xul:button>

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

@ -47,6 +47,7 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_dbg_createRemote.js \
browser_dbg_createChrome.js \
browser_dbg_debuggerstatement.js \
browser_dbg_listtabs.js \
browser_dbg_tabactor-01.js \

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

@ -30,7 +30,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {

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

@ -28,7 +28,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {

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

@ -15,7 +15,7 @@ function test() {
debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testCleanExit();
});

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

@ -0,0 +1,89 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that a chrome debugger can be created in a new process.
var gProcess = null;
var gTab = null;
var gDebuggee = null;
function test() {
debug_chrome(STACK_URL, aOnClosing, function(aTab, aDebuggee, aProcess) {
gTab = aTab;
gDebuggee = aDebuggee;
gProcess = aProcess;
testSimpleCall();
});
}
function testSimpleCall() {
Services.tm.currentThread.dispatch({ run: function() {
ok(gProcess._dbgProcess,
"The remote debugger process wasn't created properly!");
ok(gProcess._dbgProcess.isRunning,
"The remote debugger process isn't running!");
is(typeof gProcess._dbgProcess.pid, "number",
"The remote debugger process doesn't have a pid (?!)");
info("process location: " + gProcess._dbgProcess.location);
info("process pid: " + gProcess._dbgProcess.pid);
info("process name: " + gProcess._dbgProcess.processName);
info("process sig: " + gProcess._dbgProcess.processSignature);
ok(gProcess._dbgProfile,
"The remote debugger profile wasn't created properly!");
ok(gProcess._dbgProfile.localDir,
"The remote debugger profile doesn't have a localDir...");
ok(gProcess._dbgProfile.rootDir,
"The remote debugger profile doesn't have a rootDir...");
ok(gProcess._dbgProfile.name,
"The remote debugger profile doesn't have a name...");
info("profile localDir: " + gProcess._dbgProfile.localDir);
info("profile rootDir: " + gProcess._dbgProfile.rootDir);
info("profile name: " + gProcess._dbgProfile.name);
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
.createInstance(Ci.nsIToolkitProfileService);
let profile = profileService.getProfileByName(gProcess._dbgProfile.name);
ok(profile,
"The remote debugger profile wasn't *actually* created properly!");
is(profile.localDir.path, gProcess._dbgProfile.localDir.path,
"The remote debugger profile doesn't have the correct localDir!");
is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path,
"The remote debugger profile doesn't have the correct rootDir!");
DebuggerUI.toggleChromeDebugger();
}}, 0);
}
function aOnClosing() {
ok(!gProcess._dbgProcess.isRunning,
"The remote debugger process isn't closed as it should be!");
is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256),
"The remote debugger process didn't die cleanly.");
info("process exit value: " + gProcess._dbgProcess.exitValue);
info("profile localDir: " + gProcess._dbgProfile.localDir.path);
info("profile rootDir: " + gProcess._dbgProfile.rootDir.path);
info("profile name: " + gProcess._dbgProfile.name);
executeSoon(function() {
finish();
});
}
registerCleanupFunction(function() {
removeTab(gTab);
gProcess = null;
gTab = null;
gDebuggee = null;
});

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

@ -1,86 +1,80 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var gProcess = null;
// Tests that a remote debugger can be created in a new window.
var gWindow = null;
var gTab = null;
var gDebuggee = null;
var gAutoConnect = null;
const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html";
function test() {
remote_debug_tab_pane(STACK_URL, aOnClosing, function(aTab, aDebuggee, aProcess) {
debug_remote(TEST_URL, function(aTab, aDebuggee, aWindow) {
gTab = aTab;
gDebuggee = aDebuggee;
gProcess = aProcess;
gWindow = aWindow;
let gDebugger = gWindow.contentWindow;
testSimpleCall();
});
}
is(gDebugger.document.getElementById("close").getAttribute("hidden"), "true",
"The close button should be hidden in a remote debugger.");
function testSimpleCall() {
Services.tm.currentThread.dispatch({ run: function() {
is(gDebugger.DebuggerController.activeThread.paused, false,
"Should be running after debug_remote.");
ok(gProcess._dbgProcess,
"The remote debugger process wasn't created properly!");
ok(gProcess._dbgProcess.isRunning,
"The remote debugger process isn't running!");
is(typeof gProcess._dbgProcess.pid, "number",
"The remote debugger process doesn't have a pid (?!)");
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
info("process location: " + gProcess._dbgProcess.location);
info("process pid: " + gProcess._dbgProcess.pid);
info("process name: " + gProcess._dbgProcess.processName);
info("process sig: " + gProcess._dbgProcess.processSignature);
let frames = gDebugger.DebuggerView.StackFrames._frames;
let childNodes = frames.childNodes;
ok(gProcess._dbgProfile,
"The remote debugger profile wasn't created properly!");
ok(gProcess._dbgProfile.localDir,
"The remote debugger profile doesn't have a localDir...");
ok(gProcess._dbgProfile.rootDir,
"The remote debugger profile doesn't have a rootDir...");
ok(gProcess._dbgProfile.name,
"The remote debugger profile doesn't have a name...");
is(gDebugger.DebuggerController.activeThread.paused, true,
"Should be paused after an interrupt request.");
info("profile localDir: " + gProcess._dbgProfile.localDir);
info("profile rootDir: " + gProcess._dbgProfile.rootDir);
info("profile name: " + gProcess._dbgProfile.name);
is(frames.querySelectorAll(".dbg-stackframe").length, 1,
"Should have one frame in the stack.");
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
.createInstance(Ci.nsIToolkitProfileService);
gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() {
Services.tm.currentThread.dispatch({ run: function() {
closeDebuggerAndFinish(gTab, true);
}}, 0);
});
let profile = profileService.getProfileByName(gProcess._dbgProfile.name);
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.getElementById("resume"),
gDebugger);
}}, 0);
});
ok(profile,
"The remote debugger profile wasn't *actually* created properly!");
is(profile.localDir.path, gProcess._dbgProfile.localDir.path,
"The remote debugger profile doesn't have the correct localDir!");
is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path,
"The remote debugger profile doesn't have the correct rootDir!");
let iframe = gTab.linkedBrowser.contentWindow.wrappedJSObject.frames[0];
DebuggerUI.toggleRemoteDebugger();
}}, 0);
}
is(iframe.document.title, "Browser Debugger Test Tab", "Found the iframe");
function aOnClosing() {
ok(!gProcess._dbgProcess.isRunning,
"The remote debugger process isn't closed as it should be!");
is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256),
"The remote debugger process didn't die cleanly.");
iframe.runDebuggerStatement();
},
function beforeTabAdded() {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
DebuggerServer.addBrowserActors();
}
DebuggerServer.closeListener();
info("process exit value: " + gProcess._dbgProcess.exitValue);
gAutoConnect = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect");
Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true);
info("profile localDir: " + gProcess._dbgProfile.localDir.path);
info("profile rootDir: " + gProcess._dbgProfile.rootDir.path);
info("profile name: " + gProcess._dbgProfile.name);
executeSoon(function() {
finish();
// Open the listener at some point in the future to test automatic reconnect.
window.setTimeout(function() {
DebuggerServer.openListener(
Services.prefs.getIntPref("devtools.debugger.remote-port"));
}, Math.random() * 1000);
});
}
registerCleanupFunction(function() {
Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", gAutoConnect);
removeTab(gTab);
gProcess = null;
gWindow = null;
gTab = null;
gDebuggee = null;
gAutoConnect = null;
});

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

@ -15,7 +15,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testAnonCall();
});

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

@ -14,7 +14,10 @@ function test() {
debug_tab_pane(TEST_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
let gDebugger = gPane.debuggerWindow;
let gDebugger = gPane.contentWindow;
is(gDebugger.document.getElementById("close").getAttribute("hidden"), "false",
"The close button should be visible in a normal content debugger.");
is(gDebugger.DebuggerController.activeThread.paused, false,
"Should be running after debug_tab_pane.");

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

@ -17,7 +17,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

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

@ -12,7 +12,7 @@ function test() {
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testPause();
});

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

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

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

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

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

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

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

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

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

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

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

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});
@ -25,6 +25,9 @@ function testSimpleCall() {
let globalScope = gDebugger.DebuggerView.Properties.globalScope;
let localScope = gDebugger.DebuggerView.Properties.localScope;
globalScope.empty();
localScope.empty();
let windowVar = globalScope.addVar("window");
let documentVar = globalScope.addVar("document");
let localVar0 = localScope.addVar("localVariable");
@ -79,10 +82,18 @@ function testSimpleCall() {
ok(localVar5, "The localVar5 hasn't been created correctly.");
for each (let elt in globalScope.querySelector(".details").childNodes) {
info("globalScope :: " + {
id: elt.id, className: elt.className }.toSource());
}
is(globalScope.querySelector(".details").childNodes.length, 2,
"The globalScope doesn't contain all the created variable elements.");
is(localScope.querySelector(".details").childNodes.length, 7,
for each (let elt in localScope.querySelector(".details").childNodes) {
info("localScope :: " + {
id: elt.id, className: elt.className }.toSource());
}
is(localScope.querySelector(".details").childNodes.length, 6,
"The localScope doesn't contain all the created variable elements.");

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

@ -17,7 +17,7 @@ function test()
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testFrameParameters();
});

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

@ -17,7 +17,7 @@ function test()
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testFrameParameters();
});

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

@ -25,7 +25,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {

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

@ -20,7 +20,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;

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

@ -22,7 +22,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;

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

@ -13,7 +13,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

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

@ -24,7 +24,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSelectLine();
});

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

@ -14,7 +14,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testSimpleCall();
});

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

@ -14,7 +14,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testEvalCall();
});

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

@ -14,7 +14,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testRecurse();
});

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

@ -14,7 +14,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
testEvalCallResume();
});

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

@ -22,7 +22,7 @@ function test() {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {
framesAdded = true;

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

@ -29,7 +29,7 @@ function test()
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
gDebugger = gPane.contentWindow;
resumed = true;
gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() {

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

@ -49,12 +49,16 @@ function removeTab(aTab) {
gBrowser.removeTab(aTab);
}
function closeDebuggerAndFinish(aTab) {
function closeDebuggerAndFinish(aTab, aRemoteFlag) {
DebuggerUI.chromeWindow.addEventListener("Debugger:Shutdown", function cleanup() {
DebuggerUI.chromeWindow.removeEventListener("Debugger:Shutdown", cleanup, false);
finish();
}, false);
DebuggerUI.getDebugger(aTab).close();
if (!aRemoteFlag) {
DebuggerUI.getDebugger(aTab).close();
} else {
DebuggerUI.getRemoteDebugger().close();
}
}
function get_tab_actor_for_url(aClient, aURL, aCallback) {
@ -99,20 +103,41 @@ function debug_tab_pane(aURL, aOnDebugging)
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
// Wait for the initial resume...
pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
aOnDebugging(tab, debuggee, pane);
});
}, true);
});
}
function remote_debug_tab_pane(aURL, aOnClosing, aOnDebugging)
function debug_remote(aURL, aOnDebugging, aBeforeTabAdded)
{
// Make any necessary preparations (start the debugger server etc.)
aBeforeTabAdded();
let tab = addTab(aURL, function() {
gBrowser.selectedTab = gTab;
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
let win = DebuggerUI.toggleRemoteDebugger();
win._dbgwin.addEventListener("Debugger:Connecting", function dbgConnected() {
win._dbgwin.removeEventListener("Debugger:Connecting", dbgConnected, true);
// Wait for the initial resume...
win.contentWindow.gClient.addOneTimeListener("resumed", function() {
aOnDebugging(tab, debuggee, win);
});
}, true);
});
}
function debug_chrome(aURL, aOnClosing, aOnDebugging)
{
let tab = addTab(aURL, function() {
gBrowser.selectedTab = gTab;
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
DebuggerUI.toggleRemoteDebugger(aOnClosing, function dbgRan(process) {
DebuggerUI.toggleChromeDebugger(aOnClosing, function dbgRan(process) {
// Wait for the remote debugging process to start...
aOnDebugging(tab, debuggee, process);

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

@ -61,6 +61,7 @@ Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource:///modules/PropertyPanel.jsm");
Cu.import("resource:///modules/source-editor.jsm");
Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
Cu.import("resource://gre/modules/jsdebugger.jsm");
const SCRATCHPAD_CONTEXT_CONTENT = 1;
@ -295,6 +296,7 @@ var Scratchpad = {
this._chromeSandbox = new Cu.Sandbox(this.browserWindow,
{ sandboxPrototype: this.browserWindow, wantXrays: false,
sandboxName: 'scratchpad-chrome'});
addDebuggerToGlobal(this._chromeSandbox);
this._previousBrowserWindow = this.browserWindow;
}

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

@ -229,7 +229,7 @@ gcli.addCommand({
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let files = [];
if (dbg) {
let scriptsView = dbg.debuggerWindow.DebuggerView.Scripts;
let scriptsView = dbg.contentWindow.DebuggerView.Scripts;
for each (let script in scriptsView.scriptLocations) {
files.push(script);
}

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

@ -73,8 +73,8 @@ function testCreateCommands() {
pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true);
// Wait for the initial resume.
pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() {
pane.debuggerWindow.gClient.activeThread.addOneTimeListener("framesadded", function() {
pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
pane.contentWindow.gClient.activeThread.addOneTimeListener("framesadded", function() {
type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0);
is(requisition.getStatus().toString(), "VALID", "break add line is VALID");
requisition.exec();
@ -83,7 +83,7 @@ function testCreateCommands() {
is(requisition.getStatus().toString(), "VALID", "break list is VALID");
requisition.exec();
pane.debuggerWindow.gClient.activeThread.resume(function() {
pane.contentWindow.gClient.activeThread.resume(function() {
type("break del 0");
is(requisition.getStatus().toString(), "VALID", "break del 0 is VALID");
requisition.exec();

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

@ -114,6 +114,10 @@ ifdef MOZ_JSDEBUGGER
DEFINES += -DMOZ_JSDEBUGGER
endif
ifdef NECKO_WIFI
DEFINES += -DNECKO_WIFI
endif
ifdef MOZ_PKG_MANIFEST_P
MOZ_PKG_MANIFEST = package-manifest

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

@ -17,7 +17,7 @@
<!-- LOCALIZATION NOTE (chromeDebuggerMenu.label): This is the label for the
- application menu item that opens the browser debugger UI. -->
<!ENTITY chromeDebuggerMenu.label "Browser Debugger">
<!ENTITY chromeDebuggerMenu.label "Browser Debugger">
<!-- LOCALIZATION NOTE (debuggerMenu.commandkey): This is the command key that
- launches the debugger UI. Do not translate this one! -->

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

@ -6,6 +6,30 @@
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (remoteDebuggerWindowTitle): The title displayed for the
# remote debugger window.
remoteDebuggerWindowTitle=Remote Debugger
# LOCALIZATION NOTE (remoteDebuggerPromptTitle): The title displayed on the
# debugger prompt asking for the remote host and port to connect to.
remoteDebuggerPromptTitle=Remote Connection
# LOCALIZATION NOTE (remoteDebuggerPromptMessage): The message displayed on the
# debugger prompt asking for the remote host and port to connect to.
remoteDebuggerPromptMessage=Enter hostname and port number (host:port)
# LOCALIZATION NOTE (remoteDebuggerPromptCheck): The message displayed on the
# debugger prompt asking if the prompt should be shown again next time.
remoteDebuggerPromptCheck=Don't ask me again
# LOCALIZATION NOTE (remoteDebuggerReconnectMessage): The message displayed on the
# debugger prompt asking for the remote host and port to connect to.
remoteDebuggerReconnectMessage=Server not found. Try again? (host:port)
# LOCALIZATION NOTE (remoteDebuggerReconnectMessage): The message displayed on the
# debugger prompt asking for the remote host and port to connect to.
remoteDebuggerConnectionFailedMessage=Could not find a server at the specified hostname and port number.
# LOCALIZATION NOTE (pauseLabel): The label that is displayed on the pause
# button when the debugger is in a running state.
pauseLabel=Pause

Двоичные данные
browser/themes/gnomestripe/actionicon-tab.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 293 B

После

Ширина:  |  Высота:  |  Размер: 244 B

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

@ -1069,6 +1069,7 @@ toolbar[iconsize="small"] #feed-button {
padding: 1px;
margin: -1px;
-moz-margin-end: 0;
font-size: .9em;
}
#identity-box:-moz-locale-dir(ltr) {
@ -1093,9 +1094,19 @@ toolbar[iconsize="small"] #feed-button {
#identity-box.verifiedIdentity {
background-color: #fff;
color: hsl(92,81%,16%);
-moz-border-end: 1px solid hsla(92,81%,16%,.2);
color: hsl(92,100%,30%);
-moz-margin-end: 4px;
background-image: -moz-linear-gradient(hsla(92,81%,16%,0),
hsla(92,81%,16%,.2) 25%,
hsla(92,81%,16%,.2) 75%,
hsla(92,81%,16%,0));
background-position: right;
background-size: 1px;
background-repeat: no-repeat;
}
#identity-box.verifiedIdentity:-moz-locale-dir(rtl) {
background-position: left;
}
/* Identity popup icons */
@ -1335,6 +1346,7 @@ toolbar[iconsize="small"] #feed-button {
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
padding: 0 3px;
}
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
@ -1730,7 +1742,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
.alltabs-item[tabIsVisible] {
/* box-shadow instead of background-color to work around native styling */
box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15);
box-shadow: inset -5px 0 ThreeDShadow;
}
/* Sidebar */

Двоичные данные
browser/themes/pinstripe/actionicon-tab.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 293 B

После

Ширина:  |  Высота:  |  Размер: 649 B

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

@ -980,6 +980,7 @@ toolbar[mode="icons"] #zoom-in-button {
padding-bottom: 1px;
-moz-padding-start: 4px;
-moz-padding-end: 0;
font-size: .9em;
}
#identity-box:-moz-locale-dir(ltr) {
@ -1025,9 +1026,19 @@ toolbar[mode="icons"] #zoom-in-button {
}
#identity-box.verifiedIdentity {
color: hsl(92,100%,20%);
-moz-border-end: 1px solid hsla(92,81%,16%,.2);
color: hsl(92,100%,30%);
-moz-padding-end: 4px;
background-image: -moz-linear-gradient(hsla(92,81%,16%,0),
hsla(92,81%,16%,.2) 25%,
hsla(92,81%,16%,.2) 75%,
hsla(92,81%,16%,0));
background-position: right;
background-size: 1px;
background-repeat: no-repeat;
}
#identity-box.verifiedIdentity:-moz-locale-dir(rtl) {
background-position: left;
}
#identity-box:-moz-focusring {
@ -1170,6 +1181,20 @@ richlistitem[selected="true"][current="true"] > hbox > .ac-result-type-bookmark,
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
-moz-image-region: rect(0, 16px, 16px, 0);
padding: 0 3px;
}
richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(16px, 16px, 32px, 0);
}
window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(16px, 32px, 32px, 16px);
}
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
@ -2171,7 +2196,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
.alltabs-item[tabIsVisible] {
/* box-shadow instead of background-color to work around native styling */
box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15);
box-shadow: inset -5px 0 ThreeDShadow;
}
/* Tabstrip close button */

Двоичные данные
browser/themes/winstripe/actionicon-tab.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 293 B

После

Ширина:  |  Высота:  |  Размер: 434 B

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

@ -1359,6 +1359,7 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
#identity-box {
padding: 2px;
font-size: .9em;
}
#identity-box:-moz-locale-dir(ltr) {
@ -1406,9 +1407,19 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
}
#identity-box.verifiedIdentity {
color: hsl(92,100%,20%);
-moz-border-end: 1px solid hsla(92,81%,16%,.2);
color: hsl(92,100%,30%);
-moz-margin-end: 4px;
background-image: -moz-linear-gradient(hsla(92,81%,16%,0),
hsla(92,81%,16%,.2) 25%,
hsla(92,81%,16%,.2) 75%,
hsla(92,81%,16%,0));
background-position: right;
background-size: 1px;
background-repeat: no-repeat;
}
#identity-box.verifiedIdentity:-moz-locale-dir(rtl) {
background-position: left;
}
#identity-box.verifiedIdentity:not(:-moz-lwtheme) {
@ -1536,6 +1547,12 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
list-style-image: url("chrome://browser/skin/actionicon-tab.png");
-moz-image-region: rect(0, 16px, 16px, 0);
padding: 0 3px;
}
richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-moz-image-region: rect(16px, 16px, 32px, 0);
}
.autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
@ -2069,7 +2086,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
.alltabs-item[tabIsVisible] {
/* box-shadow instead of background-color to work around native styling */
box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15);
box-shadow: inset -5px 0 ThreeDShadow;
}
/* Tabstrip close button */

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