--- a/accessible/public/nsIAccessibleEvent.idl
+++ b/accessible/public/nsIAccessibleEvent.idl
@@ -56,48 +56,51 @@ interface nsIDOMNode;
* using code something like this:
* nsCOMPtr<nsIObserverService> observerService =
* do_GetService("@mozilla.org/observer-service;1", &rv);
* if (NS_SUCCEEDED(rv))
* rv = observerService->AddObserver(this, "accessible-event", PR_TRUE);
*
* @status UNDER_REVIEW
*/
-[scriptable, uuid(18612bcb-79bd-45c1-92e9-07aded5fd0f5)]
+[scriptable, uuid(98f9e2d4-ec22-4601-b927-b9faf7a63248)]
interface nsIAccessibleEvent : nsISupports
{
/**
* An object has been created.
*/
- const unsigned long EVENT_CREATE = 0x0001;
+ const unsigned long EVENT_DOM_CREATE = 0x0001;
/**
* An object has been destroyed.
*/
- const unsigned long EVENT_DESTROY = 0x0002;
+ const unsigned long EVENT_DOM_DESTROY = 0x0002;
/**
- * A hidden object is shown.
+ * An object's properties or content have changed significantly so that the
+ * type of object has really changed, and therefore the accessible should be
+ * destroyed or recreated.
*/
- const unsigned long EVENT_SHOW = 0x0003;
+ const unsigned long EVENT_DOM_SIGNIFICANT_CHANGE = 0x0003;
/**
- * An object is hidden.
+ * A hidden object is shown -- this is a layout occurance and is thus asynchronous
*/
- const unsigned long EVENT_HIDE = 0x0004;
+ const unsigned long EVENT_ASYNCH_SHOW = 0x0004;
/**
- * A container object has added, removed, or reordered its children.
+ * An object is hidden -- this is a layout occurance and is thus asynchronous
*/
- const unsigned long EVENT_REORDER = 0x0005;
+ const unsigned long EVENT_ASYNCH_HIDE = 0x0005;
/**
- * An object has a new parent object.
+ * An object had a significant layout change which could affect
+ * the type of accessible object -- this is a layout occurance and is thus asynchronous
*/
- const unsigned long EVENT_PARENT_CHANGE = 0x0006;
+ const unsigned long EVENT_ASYNCH_SIGNIFICANT_CHANGE = 0x0006;
/**
* The active descendant of a component has changed. The active descendant
* is used in objects with transient children.
*/
const unsigned long EVENT_ACTIVE_DECENDENT_CHANGED = 0x0007;
/**
@@ -465,19 +468,24 @@ interface nsIAccessibleEvent : nsISuppor
const unsigned long EVENT_PAGE_CHANGED = 0x005A;
/**
* Used internally in Gecko.
*/
const unsigned long EVENT_INTERNAL_LOAD = 0x005B;
/**
+ * An object's children have changed
+ */
+ const unsigned long EVENT_REORDER = 0x005C;
+
+ /**
* Help make sure event map does not get out-of-line.
*/
- const unsigned long EVENT_LAST_ENTRY = 0x005C;
+ const unsigned long EVENT_LAST_ENTRY = 0x005D;
/**
* The type of event, based on the enumerated event values
* defined in this interface.
*/
readonly attribute unsigned long eventType;
/**
@@ -493,16 +501,22 @@ interface nsIAccessibleEvent : nsISuppor
*/
readonly attribute nsIAccessibleDocument accessibleDocument;
/**
* The nsIDOMNode associated with the event
* May return null if accessible for event has been shut down
*/
readonly attribute nsIDOMNode DOMNode;
+
+ /**
+ * Returns true if the event was caused by explicit user input,
+ * as opposed to purely originating from a timer or mouse movement
+ */
+ readonly attribute boolean isFromUserInput;
};
[scriptable, uuid(444db51a-05fd-4576-8a64-32dbb2a83884)]
interface nsIAccessibleStateChangeEvent : nsIAccessibleEvent
{
/**
* Returns the state of accessible (see constants declared
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -1115,34 +1115,37 @@ nsAccessibleWrap::FireAccessibleEvent(ns
nsAccEvent *event = reinterpret_cast<nsAccEvent*>(aEvent);
void *eventData = event->mEventData;
AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible);
// We don't create ATK objects for nsIAccessible plain text leaves,
// just return NS_OK in such case
if (!atkObj) {
- NS_ASSERTION(type == nsIAccessibleEvent::EVENT_SHOW ||
- type == nsIAccessibleEvent::EVENT_HIDE,
+ NS_ASSERTION(type == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
+ type == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+ type == nsIAccessibleEvent::EVENT_DOM_CREATE ||
+ type == nsIAccessibleEvent::EVENT_DOM_DESTROY,
"Event other than SHOW and HIDE fired for plain text leaves");
return NS_OK;
}
nsAccessibleWrap *accWrap = GetAccessibleWrap(atkObj);
if (!accWrap) {
return NS_OK; // Node is shut down
}
AtkTableChange * pAtkTableChange = nsnull;
switch (type) {
case nsIAccessibleEvent::EVENT_STATE_CHANGE:
return FireAtkStateChangeEvent(aEvent, atkObj);
- case nsIAccessibleEvent::EVENT_TEXT_CHANGED:
+ case nsIAccessibleEvent::EVENT_TEXT_REMOVED:
+ case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
return FireAtkTextChangedEvent(aEvent, atkObj);
case nsIAccessibleEvent::EVENT_PROPERTY_CHANGED:
return FireAtkPropChangedEvent(aEvent, atkObj);
case nsIAccessibleEvent::EVENT_FOCUS:
{
MAI_LOG_DEBUG(("\n\nReceived: EVENT_FOCUS\n"));
@@ -1286,20 +1289,22 @@ nsAccessibleWrap::FireAccessibleEvent(ns
MAI_LOG_DEBUG(("\n\nReceived: EVENT_HYPERTEXT_LINK_SELECTED\n"));
atk_focus_tracker_notify(atkObj);
g_signal_emit_by_name(atkObj,
"link_selected",
// Selected link index
*(gint *)eventData);
break;
- case nsIAccessibleEvent::EVENT_SHOW:
+ case nsIAccessibleEvent::EVENT_DOM_CREATE:
+ case nsIAccessibleEvent::EVENT_ASYNCH_SHOW:
return FireAtkShowHideEvent(aEvent, atkObj, PR_TRUE);
- case nsIAccessibleEvent::EVENT_HIDE:
+ case nsIAccessibleEvent::EVENT_DOM_DESTROY:
+ case nsIAccessibleEvent::EVENT_ASYNCH_HIDE:
return FireAtkShowHideEvent(aEvent, atkObj, PR_FALSE);
/*
* Because dealing with menu is very different between nsIAccessible
* and ATK, and the menu activity is important, specially transfer the
* following two event.
* Need more verification by AT test.
*/
@@ -1412,17 +1417,17 @@ nsAccessibleWrap::FireAtkStateChangeEven
return NS_OK;
}
nsresult
nsAccessibleWrap::FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject)
{
- MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_CHANGED\n"));
+ MAI_LOG_DEBUG(("\n\nReceived: EVENT_TEXT_REMOVED/INSERTED\n"));
nsCOMPtr<nsIAccessibleTextChangeEvent> event =
do_QueryInterface(aEvent);
NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
PRInt32 start = 0;
event->GetStart(&start);
@@ -1511,19 +1516,19 @@ nsAccessibleWrap::FireAtkPropChangedEven
return NS_OK;
}
nsresult
nsAccessibleWrap::FireAtkShowHideEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject, PRBool aIsAdded)
{
if (aIsAdded)
- MAI_LOG_DEBUG(("\n\nReceived: EVENT_SHOW\n"));
+ MAI_LOG_DEBUG(("\n\nReceived: Show event\n"));
else
- MAI_LOG_DEBUG(("\n\nReceived: EVENT_HIDE\n"));
+ MAI_LOG_DEBUG(("\n\nReceived: Hide event\n"));
nsCOMPtr<nsIAccessible> accessible;
aEvent->GetAccessible(getter_AddRefs(accessible));
NS_ENSURE_STATE(accessible);
nsCOMPtr<nsIAccessible> parentAccessible;
accessible->GetParent(getter_AddRefs(parentAccessible));
NS_ENSURE_STATE(parentAccessible);
@@ -1540,13 +1545,8 @@ nsAccessibleWrap::FireAtkShowHideEvent(n
"children_changed::remove",
indexInParent,
aObject,
NULL);
return NS_OK;
}
-PRBool nsAccessibleWrap::MustPrune(nsIAccessible *aAccessible)
-{
- PRUint32 role = Role(aAccessible);
- return role == nsIAccessibleRole::ROLE_GRAPHIC;
-}
--- a/accessible/src/atk/nsAccessibleWrap.h
+++ b/accessible/src/atk/nsAccessibleWrap.h
@@ -110,19 +110,16 @@ public:
void SetMaiHyperlink(MaiHyperlink* aMaiHyperlink);
static const char * ReturnString(nsAString &aString) {
static nsCString returnedString;
returnedString = NS_ConvertUTF16toUTF8(aString);
return returnedString.get();
}
- // Should this accessible be allowed to have any ATK children
- static PRBool MustPrune(nsIAccessible *aAccessible);
-
protected:
nsresult FireAtkStateChangeEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject);
nsresult FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject);
nsresult FireAtkPropChangedEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject);
nsresult FireAtkShowHideEvent(nsIAccessibleEvent *aEvent,
--- a/accessible/src/atk/nsAppRootAccessible.cpp
+++ b/accessible/src/atk/nsAppRootAccessible.cpp
@@ -38,28 +38,36 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsMai.h"
#include "nsAppRootAccessible.h"
#include "prlink.h"
+#include "prenv.h"
+#include "nsIPrefBranch.h"
#include "nsIServiceManager.h"
#include "nsAutoPtr.h"
#include <gtk/gtk.h>
#include <atk/atk.h>
typedef GType (* AtkGetTypeType) (void);
GType g_atk_hyperlink_impl_type = G_TYPE_INVALID;
static PRBool sATKChecked = PR_FALSE;
static PRLibrary *sATKLib = nsnull;
static const char sATKLibName[] = "libatk-1.0.so.0";
-static const char sATKHyperlinkImplGetTypeSymbol[] = "atk_hyperlink_impl_get_type";
+static const char sATKHyperlinkImplGetTypeSymbol[] =
+ "atk_hyperlink_impl_get_type";
+static const char sAccEnv [] = "GNOME_ACCESSIBILITY";
+static const char sSysPrefService [] =
+ "@mozilla.org/system-preference-service;1";
+static const char sAccessibilityKey [] =
+ "config.use_system_prefs.accessibility";
/* gail function pointer */
static guint (* gail_add_global_event_listener) (GSignalEmissionHook listener,
const gchar *event_type);
static void (* gail_remove_global_event_listener) (guint remove_listener);
static AtkObject * (*gail_get_root) (void);
/* maiutil */
@@ -501,38 +509,59 @@ nsApplicationAccessibleWrap::nsApplicati
nsApplicationAccessibleWrap::~nsApplicationAccessibleWrap()
{
MAI_LOG_DEBUG(("======Destory AppRootAcc=%p\n", (void*)this));
}
NS_IMETHODIMP
nsApplicationAccessibleWrap::Init()
{
- // load and initialize gail library
- nsresult rv = LoadGtkModule(sGail);
- if (NS_SUCCEEDED(rv)) {
- (*sGail.init)();
- }
- else {
- MAI_LOG_DEBUG(("Fail to load lib: %s\n", sGail.libName));
+ // XXX following code is copied from widget/src/gtk2/nsWindow.cpp
+ // we should put it to somewhere that can be used from both modules
+ // see bug 390761
+
+ // check if accessibility enabled/disabled by environment variable
+ PRBool isGnomeATEnabled = PR_FALSE;
+ const char *envValue = PR_GetEnv(sAccEnv);
+ if (envValue) {
+ isGnomeATEnabled = atoi(envValue);
+ } else {
+ //check gconf-2 setting
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> sysPrefService =
+ do_GetService(sSysPrefService, &rv);
+ if (NS_SUCCEEDED(rv) && sysPrefService) {
+ sysPrefService->GetBoolPref(sAccessibilityKey, &isGnomeATEnabled);
+ }
}
- MAI_LOG_DEBUG(("Mozilla Atk Implementation initializing\n"));
- // Initialize the MAI Utility class
- // it will overwrite gail_util
- g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL));
+ if (isGnomeATEnabled) {
+ // load and initialize gail library
+ nsresult rv = LoadGtkModule(sGail);
+ if (NS_SUCCEEDED(rv)) {
+ (*sGail.init)();
+ }
+ else {
+ MAI_LOG_DEBUG(("Fail to load lib: %s\n", sGail.libName));
+ }
- // load and initialize atk-bridge library
- rv = LoadGtkModule(sAtkBridge);
- if (NS_SUCCEEDED(rv)) {
- // init atk-bridge
- (*sAtkBridge.init)();
+ MAI_LOG_DEBUG(("Mozilla Atk Implementation initializing\n"));
+ // Initialize the MAI Utility class
+ // it will overwrite gail_util
+ g_type_class_unref(g_type_class_ref(MAI_TYPE_UTIL));
+
+ // load and initialize atk-bridge library
+ rv = LoadGtkModule(sAtkBridge);
+ if (NS_SUCCEEDED(rv)) {
+ // init atk-bridge
+ (*sAtkBridge.init)();
+ }
+ else
+ MAI_LOG_DEBUG(("Fail to load lib: %s\n", sAtkBridge.libName));
}
- else
- MAI_LOG_DEBUG(("Fail to load lib: %s\n", sAtkBridge.libName));
return nsApplicationAccessible::Init();
}
void
nsApplicationAccessibleWrap::Unload()
{
if (sAtkBridge.lib) {
--- a/accessible/src/atk/nsXULTreeAccessibleWrap.cpp
+++ b/accessible/src/atk/nsXULTreeAccessibleWrap.cpp
@@ -91,16 +91,33 @@ NS_IMETHODIMP nsXULTreeAccessibleWrap::G
{
nsresult rv = NS_OK;
nsCOMPtr<nsIAccessible> acc;
rv = nsAccessible::GetFirstChild(getter_AddRefs(acc));
NS_ENSURE_TRUE(acc, NS_ERROR_FAILURE);
rv = acc->GetChildCount(aColumns);
+
+ // The last child could be column picker. In that case, we need to minus the
+ // number of columns by 1
+ nsCOMPtr<nsIAccessible> lastChildAccessible;
+ acc->GetLastChild(getter_AddRefs(lastChildAccessible));
+ nsCOMPtr<nsIAccessNode> accessNode = do_QueryInterface(lastChildAccessible);
+ NS_ENSURE_TRUE(accessNode, NS_ERROR_FAILURE);
+ nsCOMPtr<nsIDOMNode> domNode;
+ accessNode->GetDOMNode(getter_AddRefs(domNode));
+ nsCOMPtr<nsIContent> content = do_QueryInterface(domNode);
+ NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
+ // it's menupopup inside column picker
+ if (content->NodeInfo()->Equals(nsAccessibilityAtoms::menupopup,
+ kNameSpaceID_XUL)) {
+ (*aColumns)--;
+ }
+
return *aColumns > 0 ? rv : NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsXULTreeAccessibleWrap::GetColumnHeader(nsIAccessibleTable **aColumnHeader)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIAccessible> acc;
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -152,34 +152,32 @@ nsRoleMapEntry nsARIAMap::gWAIRoleMap[]
{"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
{"expanded", kBoolState, nsIAccessibleStates::STATE_EXPANDED},
{"expanded", "false", nsIAccessibleStates::STATE_COLLAPSED}, kEndEntry},
{"rowheader", nsIAccessibleRole::ROLE_ROWHEADER, eNameOkFromChildren, eNoValue, kNoReqStates,
{"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
{"selected", kBoolState, nsIAccessibleStates::STATE_SELECTED | nsIAccessibleStates::STATE_SELECTABLE},
{"selected", "false", nsIAccessibleStates::STATE_SELECTABLE},
{"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
- {"secret", nsIAccessibleRole::ROLE_PASSWORD_TEXT, eNameLabelOrTitle, eNoValue, nsIAccessibleStates::STATE_PROTECTED,
- // Manually map EXT_STATE_SINGLE_LINE and EXT_STATE_MULTI_LINE FROM aaa:multiline
- {"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
{"section", nsIAccessibleRole::ROLE_SECTION, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
{"separator", nsIAccessibleRole::ROLE_SEPARATOR, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
{"slider", nsIAccessibleRole::ROLE_SLIDER, eNameLabelOrTitle, eHasValueMinMax, kNoReqStates,
{"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
{"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
{"spinbutton", nsIAccessibleRole::ROLE_SPINBUTTON, eNameLabelOrTitle, eHasValueMinMax, kNoReqStates,
{"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
{"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
{"status", nsIAccessibleRole::ROLE_STATUSBAR, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
{"tab", nsIAccessibleRole::ROLE_PAGETAB, eNameOkFromChildren, eNoValue, kNoReqStates,
{"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
{"tablist", nsIAccessibleRole::ROLE_PAGETABLIST, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
{"tabpanel", nsIAccessibleRole::ROLE_PROPERTYPAGE, eNameLabelOrTitle, eNoValue, kNoReqStates, kEndEntry},
{"textbox", nsIAccessibleRole::ROLE_ENTRY, eNameLabelOrTitle, eNoValue, kNoReqStates,
// Manually map EXT_STATE_SINGLE_LINE and EXT_STATE_MULTI_LINE FROM aaa:multiline
+ {"secret", kBoolState, nsIAccessibleStates::STATE_PROTECTED},
{"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
{"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY}, kEndEntry},
{"toolbar", nsIAccessibleRole::ROLE_TOOLBAR, eNameLabelOrTitle, eNoValue, kNoReqStates,
{"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE}, kEndEntry},
{"tooltip", nsIAccessibleRole::ROLE_TOOLTIP, eNameOkFromChildren, eNoValue, kNoReqStates, kEndEntry},
{"tree", nsIAccessibleRole::ROLE_OUTLINE, eNameLabelOrTitle, eNoValue, kNoReqStates,
{"disabled", kBoolState, nsIAccessibleStates::STATE_UNAVAILABLE},
{"readonly", kBoolState, nsIAccessibleStates::STATE_READONLY},
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -148,16 +148,17 @@ ACCESSIBILITY_ATOM(labelledby, "labelled
ACCESSIBILITY_ATOM(owns, "owns")
// Alphabetical list of attributes
ACCESSIBILITY_ATOM(acceltext, "acceltext")
ACCESSIBILITY_ATOM(accesskey, "accesskey")
ACCESSIBILITY_ATOM(alt, "alt")
ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL
ACCESSIBILITY_ATOM(autocomplete, "autocomplete") // Used as attribute value too
+ACCESSIBILITY_ATOM(contenteditable, "contenteditable")
ACCESSIBILITY_ATOM(control, "control")
ACCESSIBILITY_ATOM(cycles, "cycles") // used for XUL cycler attribute
ACCESSIBILITY_ATOM(curpos, "curpos") // XUL
ACCESSIBILITY_ATOM(data, "data")
ACCESSIBILITY_ATOM(disabled, "disabled")
ACCESSIBILITY_ATOM(droppable, "droppable") // XUL combo box
ACCESSIBILITY_ATOM(editable, "editable")
ACCESSIBILITY_ATOM(_for, "for")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1783,19 +1783,19 @@ NS_IMETHODIMP nsAccessibilityService::Re
#endif
}
// Called from layout when the frame tree owned by a node changes significantly
NS_IMETHODIMP nsAccessibilityService::InvalidateSubtreeFor(nsIPresShell *aShell,
nsIContent *aChangeContent,
PRUint32 aEvent)
{
- NS_ASSERTION(aEvent == nsIAccessibleEvent::EVENT_REORDER ||
- aEvent == nsIAccessibleEvent::EVENT_SHOW ||
- aEvent == nsIAccessibleEvent::EVENT_HIDE,
+ NS_ASSERTION(aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE ||
+ aEvent == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
+ aEvent == nsIAccessibleEvent::EVENT_ASYNCH_HIDE,
"Incorrect aEvent passed in");
nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aShell));
NS_ASSERTION(aShell, "No pres shell in call to InvalidateSubtreeFor");
nsCOMPtr<nsIAccessibleDocument> accessibleDoc =
nsAccessNode::GetDocAccessibleFor(weakShell);
nsCOMPtr<nsPIAccessibleDocument> privateAccessibleDoc =
do_QueryInterface(accessibleDoc);
--- a/accessible/src/base/nsAccessibilityUtils.cpp
+++ b/accessible/src/base/nsAccessibilityUtils.cpp
@@ -163,22 +163,42 @@ nsAccUtils::HasListener(nsIContent *aCon
NS_ENSURE_ARG_POINTER(aContent);
nsCOMPtr<nsIEventListenerManager> listenerManager;
aContent->GetListenerManager(PR_FALSE, getter_AddRefs(listenerManager));
return listenerManager && listenerManager->HasListenersFor(aEventType);
}
nsresult
-nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible)
+nsAccUtils::FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
+ PRBool aIsAsynch)
{
NS_ENSURE_ARG(aAccessible);
nsCOMPtr<nsPIAccessible> pAccessible(do_QueryInterface(aAccessible));
NS_ASSERTION(pAccessible, "Accessible doesn't implement nsPIAccessible");
nsCOMPtr<nsIAccessibleEvent> event =
- new nsAccEvent(aEventType, aAccessible, nsnull);
+ new nsAccEvent(aEventType, aAccessible, nsnull, aIsAsynch);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return pAccessible->FireAccessibleEvent(event);
}
+PRBool
+nsAccUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
+ nsIDOMNode *aPossibleDescendantNode)
+{
+ NS_ENSURE_ARG_POINTER(aPossibleAncestorNode);
+ NS_ENSURE_ARG_POINTER(aPossibleDescendantNode);
+
+ nsCOMPtr<nsIDOMNode> loopNode = aPossibleDescendantNode;
+ nsCOMPtr<nsIDOMNode> parentNode;
+ while (NS_SUCCEEDED(loopNode->GetParentNode(getter_AddRefs(parentNode))) &&
+ parentNode) {
+ if (parentNode == aPossibleAncestorNode) {
+ return PR_TRUE;
+ }
+ loopNode.swap(parentNode);
+ }
+ return PR_FALSE;
+}
+
--- a/accessible/src/base/nsAccessibilityUtils.h
+++ b/accessible/src/base/nsAccessibilityUtils.h
@@ -106,12 +106,23 @@ public:
* Return true if the given node has registered event listener of the given
* type.
*/
static PRBool HasListener(nsIContent *aContent, const nsAString& aEventType);
/**
* Fire accessible event of the given type for the given accessible.
*/
- static nsresult FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible);
+ static nsresult FireAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
+ PRBool aIsAsynch = PR_FALSE);
+
+ /**
+ * Is the first passed in node an ancestor of the second?
+ * Note: A node is not considered to be the ancestor of itself.
+ * @aPossibleAncestorNode -- node to test for ancestor-ness of aPossibleDescendantNode
+ * @aPossibleDescendantNode -- node to test for descendant-ness of aPossibleAncestorNode
+ * @return PR_TRUE if aPossibleAncestorNode is an ancestor of aPossibleDescendantNode
+ */
+ static PRBool IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
+ nsIDOMNode *aPossibleDescendantNode);
};
#endif
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -206,24 +206,26 @@ nsresult nsAccessible::QueryInterface(RE
static nsIContent::AttrValuesArray strings[] =
{&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
if (content->FindAttrValueIn(kNameSpaceID_WAIProperties ,
nsAccessibilityAtoms::multiselectable,
strings, eCaseMatters) ==
nsIContent::ATTR_VALUE_NO_MATCH) {
*aInstancePtr = static_cast<nsIAccessibleSelectable*>(this);
NS_ADDREF_THIS();
+ return NS_OK;
}
}
}
if (aIID.Equals(NS_GET_IID(nsIAccessibleValue))) {
if (mRoleMapEntry && mRoleMapEntry->valueRule != eNoValue) {
*aInstancePtr = static_cast<nsIAccessibleValue*>(this);
NS_ADDREF_THIS();
+ return NS_OK;
}
}
if (aIID.Equals(NS_GET_IID(nsIAccessibleHyperLink))) {
nsCOMPtr<nsIAccessible> parent(GetParent());
nsCOMPtr<nsIAccessibleHyperText> hyperTextParent(do_QueryInterface(parent));
if (hyperTextParent) {
*aInstancePtr = static_cast<nsIAccessibleHyperLink*>(this);
@@ -2078,16 +2080,18 @@ nsAccessible::GetAttributes(nsIPersisten
if (!mDOMNode)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIPersistentProperties> attributes =
do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
+ nsAccEvent::GetLastEventAttributes(mDOMNode, attributes);
+
nsresult rv = GetAttributesInternal(attributes);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIContent> content = GetRoleContent(mDOMNode);
if (content) {
nsAutoString id;
nsAutoString oldValueUnused;
if (content->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::id, id)) {
@@ -2116,27 +2120,23 @@ nsAccessible::GetAttributes(nsIPersisten
if (!nsAccUtils::HasAccGroupAttrs(attributes)) {
// The role of an accessible can be pointed by ARIA attribute but ARIA
// posinset, level, setsize may be skipped. Therefore we calculate here
// these properties to map them into description.
// If accessible is invisible we don't want to calculate group ARIA
// attributes for it.
- PRUint32 state = State(this);
- if (state & nsIAccessibleStates::STATE_INVISIBLE)
- return NS_OK;
-
PRUint32 role = Role(this);
- if (role == nsIAccessibleRole::ROLE_LISTITEM ||
+ if ((role == nsIAccessibleRole::ROLE_LISTITEM ||
role == nsIAccessibleRole::ROLE_MENUITEM ||
role == nsIAccessibleRole::ROLE_RADIOBUTTON ||
role == nsIAccessibleRole::ROLE_PAGETAB ||
- role == nsIAccessibleRole::ROLE_OUTLINEITEM) {
-
+ role == nsIAccessibleRole::ROLE_OUTLINEITEM) &&
+ 0 == (State(this) & nsIAccessibleStates::STATE_INVISIBLE)) {
nsCOMPtr<nsIAccessible> parent = GetParent();
NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
PRInt32 positionInGroup = 0;
PRInt32 setSize = 0;
nsCOMPtr<nsIAccessible> sibling, nextSibling;
parent->GetFirstChild(getter_AddRefs(sibling));
@@ -2716,16 +2716,21 @@ NS_IMETHODIMP nsAccessible::GetAccessibl
}
}
}
relatedNode = do_QueryInterface(buttonEl);
}
}
break;
}
+ case nsIAccessibleRelation::RELATION_MEMBER_OF:
+ {
+ relatedNode = nsAccEvent::GetLastEventAtomicRegion(mDOMNode);
+ break;
+ }
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
if (!relatedID.IsEmpty()) {
// In some cases we need to get the relatedNode from an ID-style attribute
nsCOMPtr<nsIDOMDocument> domDoc;
mDOMNode->GetOwnerDocument(getter_AddRefs(domDoc));
@@ -3263,8 +3268,21 @@ nsAccessible::GetAttrValue(PRUint32 aNam
PRInt32 result = NS_OK;
nsAutoString value;
if (content->GetAttr(aNameSpaceID, aName, value) && !value.IsEmpty())
*aValue = value.ToFloat(&result);
return result;
}
+PRBool nsAccessible::MustPrune(nsIAccessible *aAccessible)
+{
+ PRUint32 role = Role(aAccessible);
+ return role == nsIAccessibleRole::ROLE_MENUITEM ||
+ role == nsIAccessibleRole::ROLE_ENTRY ||
+ role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
+ role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
+ role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
+ role == nsIAccessibleRole::ROLE_GRAPHIC ||
+ role == nsIAccessibleRole::ROLE_SLIDER ||
+ role == nsIAccessibleRole::ROLE_PROGRESSBAR ||
+ role == nsIAccessibleRole::ROLE_SEPARATOR;
+}
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -150,23 +150,27 @@ public:
static PRBool IsCorrectFrameType(nsIFrame* aFrame, nsIAtom* aAtom);
static PRUint32 State(nsIAccessible *aAcc) { PRUint32 state; aAcc->GetFinalState(&state, nsnull); return state; }
static PRUint32 Role(nsIAccessible *aAcc) { PRUint32 role; aAcc->GetFinalRole(&role); return role; }
static PRBool IsText(nsIAccessible *aAcc) { PRUint32 role = Role(aAcc); return role == nsIAccessibleRole::ROLE_TEXT_LEAF || role == nsIAccessibleRole::ROLE_STATICTEXT; }
static PRBool IsEmbeddedObject(nsIAccessible *aAcc) { PRUint32 role = Role(aAcc); return role != nsIAccessibleRole::ROLE_TEXT_LEAF && role != nsIAccessibleRole::ROLE_WHITESPACE && role != nsIAccessibleRole::ROLE_STATICTEXT; }
static PRInt32 TextLength(nsIAccessible *aAccessible); // Returns -1 on failure
static PRBool IsLeaf(nsIAccessible *aAcc) { PRInt32 numChildren; aAcc->GetChildCount(&numChildren); return numChildren > 0; }
static PRBool IsNodeRelevant(nsIDOMNode *aNode); // Is node something that could have an attached accessible
+ /**
+ * When exposing to platform accessibility APIs, should the children be pruned off?
+ */
+ static PRBool MustPrune(nsIAccessible *aAccessible);
already_AddRefed<nsIAccessible> GetParent() {
nsIAccessible *parent = nsnull;
GetParent(&parent);
return parent;
}
-
+
protected:
PRBool MappedAttrState(nsIContent *aContent, PRUint32 *aStateInOut, nsStateMapEntry *aStateMapEntry);
virtual nsIFrame* GetBoundsFrame();
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
PRBool IsVisible(PRBool *aIsOffscreen);
// Relation helpers
nsresult GetTextFromRelationID(nsIAtom *aIDAttrib, nsString &aName);
--- a/accessible/src/base/nsAccessibleEventData.cpp
+++ b/accessible/src/base/nsAccessibleEventData.cpp
@@ -32,36 +32,197 @@
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsAccessibleEventData.h"
+#include "nsAccessibilityAtoms.h"
#include "nsIAccessibilityService.h"
#include "nsIAccessNode.h"
+#include "nsIDocument.h"
+#include "nsIDOMDocument.h"
+#include "nsIEventStateManager.h"
+#include "nsIPersistentProperties2.h"
#include "nsIServiceManager.h"
#ifdef MOZ_XUL
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsXULTreeAccessible.h"
#endif
+#include "nsIContent.h"
+#include "nsIPresShell.h"
+#include "nsPresContext.h"
+
+PRBool nsAccEvent::gLastEventFromUserInput = PR_FALSE;
+nsIDOMNode* nsAccEvent::gLastEventNodeWeak = 0;
NS_IMPL_ISUPPORTS1(nsAccEvent, nsIAccessibleEvent)
nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
- void *aEventData):
+ void *aEventData, PRBool aIsAsynch):
mEventType(aEventType), mAccessible(aAccessible), mEventData(aEventData)
{
+ CaptureIsFromUserInput(aIsAsynch);
}
nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
- void *aEventData):
+ void *aEventData, PRBool aIsAsynch):
mEventType(aEventType), mDOMNode(aDOMNode), mEventData(aEventData)
{
+ CaptureIsFromUserInput(aIsAsynch);
+}
+
+void nsAccEvent::GetLastEventAttributes(nsIDOMNode *aNode,
+ nsIPersistentProperties *aAttributes)
+{
+ if (aNode != gLastEventNodeWeak) {
+ return; // Passed-in node doesn't Change the last event's node
+ }
+ nsAutoString oldValueUnused;
+ aAttributes->SetStringProperty(NS_LITERAL_CSTRING("event-from-input"),
+ gLastEventFromUserInput ? NS_LITERAL_STRING("true") :
+ NS_LITERAL_STRING("false"),
+ oldValueUnused);
+
+ nsCOMPtr<nsIContent> lastEventContent = do_QueryInterface(aNode);
+ nsIContent *loopContent = lastEventContent;
+
+ nsAutoString atomic, live, relevant, channel, busy;
+
+ while (loopContent) {
+ if (relevant.IsEmpty()) {
+ loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::relevant, relevant);
+ }
+ if (live.IsEmpty()) {
+ loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::live, live);
+ }
+ if (channel.IsEmpty()) {
+ loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::channel, channel);
+ }
+ if (atomic.IsEmpty()) {
+ loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic);
+ }
+ if (busy.IsEmpty()) {
+ loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::busy, busy);
+ }
+ loopContent = loopContent->GetParent();
+ }
+
+ if (!relevant.IsEmpty()) {
+ aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-relevant"), relevant, oldValueUnused);
+ }
+ if (!live.IsEmpty()) {
+ aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-live"), live, oldValueUnused);
+ }
+ if (!channel.IsEmpty()) {
+ aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-channel"), channel, oldValueUnused);
+ }
+ if (!atomic.IsEmpty()) {
+ aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-atomic"), atomic, oldValueUnused);
+ }
+ if (!busy.IsEmpty()) {
+ aAttributes->SetStringProperty(NS_LITERAL_CSTRING("container-busy"), busy, oldValueUnused);
+ }
+}
+
+nsIDOMNode* nsAccEvent::GetLastEventAtomicRegion(nsIDOMNode *aNode)
+{
+ if (aNode != gLastEventNodeWeak) {
+ return nsnull; // Passed-in node doesn't Change the last changed node
+ }
+ nsCOMPtr<nsIContent> lastEventContent = do_QueryInterface(aNode);
+ nsIContent *loopContent = lastEventContent;
+ nsAutoString atomic;
+
+ while (loopContent) {
+ loopContent->GetAttr(kNameSpaceID_WAIProperties, nsAccessibilityAtoms::atomic, atomic);
+ if (!atomic.IsEmpty()) {
+ break;
+ }
+ loopContent = loopContent->GetParent();
+ }
+
+ nsCOMPtr<nsIDOMNode> atomicRegion;
+ if (atomic.EqualsLiteral("true")) {
+ atomicRegion = do_QueryInterface(loopContent);
+ }
+ return atomicRegion;
+}
+
+void nsAccEvent::CaptureIsFromUserInput(PRBool aIsAsynch)
+{
+ nsCOMPtr<nsIDOMNode> eventNode;
+ GetDOMNode(getter_AddRefs(eventNode));
+ if (!eventNode) {
+ NS_NOTREACHED("There should always be a DOM node for an event");
+ return;
+ }
+
+ if (aIsAsynch) {
+ // Cannot calculate, so use previous value
+ gLastEventNodeWeak = eventNode;
+ }
+ else {
+ PrepareForEvent(eventNode);
+ }
+
+ mIsFromUserInput = gLastEventFromUserInput;
+}
+
+NS_IMETHODIMP
+nsAccEvent::GetIsFromUserInput(PRBool *aIsFromUserInput)
+{
+ *aIsFromUserInput = mIsFromUserInput;
+ return NS_OK;
+}
+
+void nsAccEvent::PrepareForEvent(nsIAccessibleEvent *aEvent)
+{
+ nsCOMPtr<nsIDOMNode> eventNode;
+ aEvent->GetDOMNode(getter_AddRefs(eventNode));
+ PRBool isFromUserInput;
+ aEvent->GetIsFromUserInput(&isFromUserInput);
+ PrepareForEvent(eventNode, isFromUserInput);
+}
+
+void nsAccEvent::PrepareForEvent(nsIDOMNode *aEventNode,
+ PRBool aForceIsFromUserInput)
+{
+ gLastEventNodeWeak = aEventNode;
+ if (aForceIsFromUserInput) {
+ gLastEventFromUserInput = PR_TRUE;
+ return;
+ }
+
+ nsCOMPtr<nsIDOMDocument> domDoc;
+ aEventNode->GetOwnerDocument(getter_AddRefs(domDoc));
+ if (!domDoc) { // IF the node is a document itself
+ domDoc = do_QueryInterface(aEventNode);
+ }
+ nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
+ if (!doc) {
+ NS_NOTREACHED("There should always be a document for an event");
+ return;
+ }
+
+ nsCOMPtr<nsIPresShell> presShell = doc->GetPrimaryShell();
+ if (!presShell) {
+ NS_NOTREACHED("Threre should always be an pres shell for an event");
+ return;
+ }
+
+ nsIEventStateManager *esm = presShell->GetPresContext()->EventStateManager();
+ if (!esm) {
+ NS_NOTREACHED("Threre should always be an ESM for an event");
+ return;
+ }
+
+ gLastEventFromUserInput = esm->IsHandlingUserInputExternal();
}
NS_IMETHODIMP
nsAccEvent::GetEventType(PRUint32 *aEventType)
{
*aEventType = mEventType;
return NS_OK;
}
@@ -229,17 +390,18 @@ nsAccStateChangeEvent::IsEnabled(PRBool
// nsAccTextChangeEvent
NS_IMPL_ISUPPORTS_INHERITED1(nsAccTextChangeEvent, nsAccEvent,
nsIAccessibleTextChangeEvent)
nsAccTextChangeEvent::
nsAccTextChangeEvent(nsIAccessible *aAccessible,
PRInt32 aStart, PRUint32 aLength, PRBool aIsInserted):
- nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CHANGED, aAccessible, nsnull),
+ nsAccEvent(aIsInserted ? nsIAccessibleEvent::EVENT_TEXT_INSERTED : nsIAccessibleEvent::EVENT_TEXT_REMOVED,
+ aAccessible, nsnull),
mStart(aStart), mLength(aLength), mIsInserted(aIsInserted)
{
}
NS_IMETHODIMP
nsAccTextChangeEvent::GetStart(PRInt32 *aStart)
{
*aStart = mStart;
@@ -261,24 +423,24 @@ nsAccTextChangeEvent::IsInserted(PRBool
}
// nsAccCaretMoveEvent
NS_IMPL_ISUPPORTS_INHERITED1(nsAccCaretMoveEvent, nsAccEvent,
nsIAccessibleCaretMoveEvent)
nsAccCaretMoveEvent::
nsAccCaretMoveEvent(nsIAccessible *aAccessible, PRInt32 aCaretOffset) :
- nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, nsnull),
+ nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aAccessible, nsnull, PR_TRUE), // Currently always asynch
mCaretOffset(aCaretOffset)
{
}
nsAccCaretMoveEvent::
nsAccCaretMoveEvent(nsIDOMNode *aNode) :
- nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aNode, nsnull),
+ nsAccEvent(::nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED, aNode, nsnull, PR_TRUE), // Currently always asynch
mCaretOffset(-1)
{
}
NS_IMETHODIMP
nsAccCaretMoveEvent::GetCaretOffset(PRInt32* aCaretOffset)
{
NS_ENSURE_ARG_POINTER(aCaretOffset);
--- a/accessible/src/base/nsAccessibleEventData.h
+++ b/accessible/src/base/nsAccessibleEventData.h
@@ -41,39 +41,66 @@
#ifndef _nsAccessibleEventData_H_
#define _nsAccessibleEventData_H_
#include "nsCOMPtr.h"
#include "nsIAccessibleEvent.h"
#include "nsIAccessible.h"
#include "nsIAccessibleDocument.h"
#include "nsIDOMNode.h"
+class nsIPresShell;
class nsAccEvent: public nsIAccessibleEvent
{
public:
// Initialize with an nsIAccessible
- nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, void *aEventData);
+ nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, void *aEventData, PRBool aIsAsynch = PR_FALSE);
// Initialize with an nsIDOMNode
- nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, void *aEventData);
+ nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, void *aEventData, PRBool aIsAsynch = PR_FALSE);
virtual ~nsAccEvent() {}
NS_DECL_ISUPPORTS
NS_DECL_NSIACCESSIBLEEVENT
+ static void GetLastEventAttributes(nsIDOMNode *aNode,
+ nsIPersistentProperties *aAttributes);
+ static nsIDOMNode* GetLastEventAtomicRegion(nsIDOMNode *aNode);
+
protected:
already_AddRefed<nsIAccessible> GetAccessibleByNode();
+ void CaptureIsFromUserInput(PRBool aIsAsynch);
+ PRBool mIsFromUserInput;
+
private:
PRUint32 mEventType;
nsCOMPtr<nsIAccessible> mAccessible;
nsCOMPtr<nsIDOMNode> mDOMNode;
nsCOMPtr<nsIAccessibleDocument> mDocAccessible;
+ static PRBool gLastEventFromUserInput;
+ static nsIDOMNode* gLastEventNodeWeak;
+
public:
+ /**
+ * Find and cache the last input state. This will be called automatically
+ * for synchronous events. For asynchronous events it should be
+ * called from the synchronous code which is the true source of the event,
+ * before the event is fired.
+ */
+ static void PrepareForEvent(nsIDOMNode *aChangeNode,
+ PRBool aForceIsFromUserInput = PR_FALSE);
+
+ /**
+ * The input state was previously stored with the nsIAccessibleEvent,
+ * so use that state now -- call this when about to flush an event that
+ * was waiting in an event queue
+ */
+ static void PrepareForEvent(nsIAccessibleEvent *aEvent);
+
void *mEventData;
};
class nsAccStateChangeEvent: public nsAccEvent,
public nsIAccessibleStateChangeEvent
{
public:
nsAccStateChangeEvent(nsIAccessible *aAccessible,
--- a/accessible/src/base/nsCaretAccessible.cpp
+++ b/accessible/src/base/nsCaretAccessible.cpp
@@ -216,17 +216,17 @@ NS_IMETHODIMP nsCaretAccessible::NotifyS
}
mLastCaretOffset = caretOffset;
mLastTextAccessible = textAcc;
nsCOMPtr<nsIAccessibleCaretMoveEvent> event =
new nsAccCaretMoveEvent(focusNode);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
- return mRootAccessible->FireDelayedAccessibleEvent(event, PR_FALSE);
+ return mRootAccessible->FireDelayedAccessibleEvent(event, nsDocAccessible::eRemoveDupes);
}
nsRect
nsCaretAccessible::GetCaretRect(nsIWidget **aOutWidget)
{
nsRect caretRect;
NS_ENSURE_TRUE(aOutWidget, caretRect);
*aOutWidget = nsnull;
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -238,17 +238,18 @@ nsDocAccessible::GetState(PRUint32 *aSta
}
if (frame != nsnull) {
if (!CheckVisibilityInParentChain(mDocument, frame->GetViewExternal())) {
*aState |= nsIAccessibleStates::STATE_INVISIBLE;
}
}
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
if (!editor) {
*aState |= nsIAccessibleStates::STATE_READONLY;
}
else if (aExtraState) {
*aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE;
}
return NS_OK;
@@ -392,47 +393,43 @@ NS_IMETHODIMP nsDocAccessible::GetDocume
if (domDoc) {
NS_ADDREF(*aDOMDoc);
return NS_OK;
}
return NS_ERROR_FAILURE;
}
-void nsDocAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsDocAccessible::GetAssociatedEditor(nsIEditor **aEditor)
{
- mEditor = aEditor;
-}
+ NS_ENSURE_ARG_POINTER(aEditor);
-void nsDocAccessible::CheckForEditor()
-{
- if (mEditor) {
- return; // Already have editor, don't need to check
- }
- if (!mDocument) {
- return; // No document -- we've been shut down
+ *aEditor = nsnull;
+ NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
+
+ if (!mDocument->HasFlag(NODE_IS_EDITABLE)) {
+ return NS_OK; // Document not editable
}
nsCOMPtr<nsISupports> container = mDocument->GetContainer();
nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(container));
if (!editingSession)
- return; // No editing session interface
+ return NS_OK; // No editing session interface
nsCOMPtr<nsIEditor> editor;
- editingSession->GetEditorForWindow(mDocument->GetWindow(),
- getter_AddRefs(editor));
- SetEditor(editor);
- if (!editor)
- return;
-
- // State editable is now set, readonly is now clear
- nsCOMPtr<nsIAccessibleStateChangeEvent> event =
- new nsAccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
- PR_TRUE, PR_TRUE);
- FireAccessibleEvent(event);
+ editingSession->GetEditorForWindow(mDocument->GetWindow(), getter_AddRefs(editor));
+ if (!editor) {
+ return NS_OK;
+ }
+ PRBool isEditable;
+ editor->GetIsDocumentEditable(&isEditable);
+ if (isEditable) {
+ NS_ADDREF(*aEditor = editor);
+ }
+ return NS_OK;
}
NS_IMETHODIMP nsDocAccessible::GetCachedAccessNode(void *aUniqueID, nsIAccessNode **aAccessNode)
{
GetCacheEntry(mAccessNodeCache, aUniqueID, aAccessNode); // Addrefs for us
#ifdef DEBUG_A11Y
// All cached accessible nodes should be in the parent
// It will assert if not all the children were created
@@ -526,18 +523,16 @@ NS_IMETHODIMP nsDocAccessible::Shutdown(
{
if (!mWeakShell) {
return NS_OK; // Already shutdown
}
nsCOMPtr<nsIDocShellTreeItem> treeItem = GetDocShellTreeItemFor(mDOMNode);
ShutdownChildDocuments(treeItem);
- mEditor = nsnull;
-
if (mDocLoadTimer) {
mDocLoadTimer->Cancel();
mDocLoadTimer = nsnull;
}
RemoveEventListeners();
mWeakShell = nsnull; // Avoid reentrancy
@@ -648,24 +643,20 @@ nsresult nsDocAccessible::AddEventListen
// Make sure we're a content docshell
// We don't want to listen to chrome progress
PRInt32 itemType;
docShellTreeItem->GetItemType(&itemType);
PRBool isContent = (itemType == nsIDocShellTreeItem::typeContent);
if (isContent) {
- CheckForEditor();
-
- if (!mEditor) {
- // We're not an editor yet, but we might become one
- nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShellTreeItem);
- if (commandManager) {
- commandManager->AddCommandObserver(this, "obs_documentCreated");
- }
+ // We're not an editor yet, but we might become one
+ nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShellTreeItem);
+ if (commandManager) {
+ commandManager->AddCommandObserver(this, "obs_documentCreated");
}
}
nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
docShellTreeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem));
if (rootTreeItem) {
GetDocAccessibleFor(rootTreeItem, PR_TRUE); // Ensure root accessible is created;
nsRefPtr<nsRootAccessible> rootAccessible = GetRootAccessible();
@@ -893,19 +884,22 @@ NS_IMETHODIMP nsDocAccessible::ScrollPos
}
mScrollPositionChangedTicks = 1;
return NS_OK;
}
NS_IMETHODIMP nsDocAccessible::Observe(nsISupports *aSubject, const char *aTopic,
const PRUnichar *aData)
{
- if (!nsCRT::strcmp(aTopic,"obs_documentCreated")) {
- CheckForEditor();
- NS_ASSERTION(mEditor, "Should have editor if we see obs_documentCreated");
+ if (!nsCRT::strcmp(aTopic,"obs_documentCreated")) {
+ // State editable will now be set, readonly is now clear
+ nsCOMPtr<nsIAccessibleStateChangeEvent> event =
+ new nsAccStateChangeEvent(this, nsIAccessibleStates::EXT_STATE_EDITABLE,
+ PR_TRUE, PR_TRUE);
+ FireAccessibleEvent(event);
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////
// nsIDocumentObserver
@@ -945,16 +939,21 @@ nsDocAccessible::AttributeChanged(nsIDoc
}
nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aContent));
NS_ASSERTION(targetNode, "No node for attr modified");
if (!targetNode || !IsNodeRelevant(targetNode)) {
return;
}
+ // Since we're in synchronous code, we can store whether the current attribute
+ // change is from user input or not. If the attribute change causes an asynchronous
+ // layout change, that event can use the last known user input state
+ nsAccEvent::PrepareForEvent(targetNode);
+
// Universal boolean properties that don't require a role.
if (aAttribute == nsAccessibilityAtoms::disabled) {
// Fire the state change whether disabled attribute is
// set for XUL, HTML or ARIA namespace.
// Checking the namespace would not seem to gain us anything, because
// disabled really is going to mean the same thing in any namespace.
// We use the attribute instead of the disabled state bit because
// ARIA's aaa:disabled does not affect the disabled state bit
@@ -974,24 +973,24 @@ nsDocAccessible::AttributeChanged(nsIDoc
if (aNameSpaceID == kNameSpaceID_WAIProperties) {
ARIAAttributeChanged(aContent, aAttribute);
return;
}
if (aNameSpaceID == kNameSpaceID_XHTML2_Unofficial ||
aNameSpaceID == kNameSpaceID_XHTML) {
if (aAttribute == nsAccessibilityAtoms::role)
- InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
+ InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
return;
}
if (aAttribute == nsAccessibilityAtoms::href ||
aAttribute == nsAccessibilityAtoms::onclick ||
aAttribute == nsAccessibilityAtoms::droppable) {
- InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
+ InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
return;
}
if (aAttribute == nsAccessibilityAtoms::selected) {
// DHTML or XUL selection
nsCOMPtr<nsIAccessible> multiSelect = GetMultiSelectFor(targetNode);
// Multi selects use selection_add and selection_remove
// Single select widgets just mirror event_selection for
@@ -1002,17 +1001,17 @@ nsDocAccessible::AttributeChanged(nsIDoc
// Need to find the right event to use here, SELECTION_WITHIN would
// seem right but we had started using it for something else
nsCOMPtr<nsIAccessNode> multiSelectAccessNode =
do_QueryInterface(multiSelect);
nsCOMPtr<nsIDOMNode> multiSelectDOMNode;
multiSelectAccessNode->GetDOMNode(getter_AddRefs(multiSelectDOMNode));
NS_ASSERTION(multiSelectDOMNode, "A new accessible without a DOM node!");
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
- multiSelectDOMNode, nsnull, PR_TRUE);
+ multiSelectDOMNode, nsnull, eAllowDupes);
static nsIContent::AttrValuesArray strings[] =
{&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
if (aContent->FindAttrValueIn(kNameSpaceID_None,
nsAccessibilityAtoms::selected,
strings, eCaseMatters) !=
nsIContent::ATTR_VALUE_NO_MATCH) {
@@ -1020,16 +1019,25 @@ nsDocAccessible::AttributeChanged(nsIDoc
targetNode, nsnull);
return;
}
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_ADD,
targetNode, nsnull);
}
}
+
+ if (aAttribute == nsAccessibilityAtoms::contenteditable) {
+ nsCOMPtr<nsIAccessibleStateChangeEvent> editableChangeEvent =
+ new nsAccStateChangeEvent(targetNode,
+ nsIAccessibleStates::EXT_STATE_EDITABLE,
+ PR_TRUE);
+ FireDelayedAccessibleEvent(editableChangeEvent);
+ return;
+ }
}
void
nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
{
nsCOMPtr<nsIDOMNode> targetNode(do_QueryInterface(aContent));
if (!targetNode)
return;
@@ -1076,16 +1084,25 @@ nsDocAccessible::ARIAAttributeChanged(ns
nsCOMPtr<nsIAccessibleStateChangeEvent> event =
new nsAccStateChangeEvent(targetNode,
nsIAccessibleStates::STATE_CHECKED,
PR_FALSE);
FireDelayedAccessibleEvent(event);
return;
}
+ if (aAttribute == nsAccessibilityAtoms::pressed) {
+ nsCOMPtr<nsIAccessibleStateChangeEvent> event =
+ new nsAccStateChangeEvent(targetNode,
+ nsIAccessibleStates::STATE_PRESSED,
+ PR_FALSE);
+ FireDelayedAccessibleEvent(event);
+ return;
+ }
+
if (aAttribute == nsAccessibilityAtoms::expanded) {
nsCOMPtr<nsIAccessibleStateChangeEvent> event =
new nsAccStateChangeEvent(targetNode,
nsIAccessibleStates::STATE_EXPANDED,
PR_FALSE);
FireDelayedAccessibleEvent(event);
return;
}
@@ -1107,17 +1124,17 @@ nsDocAccessible::ARIAAttributeChanged(ns
if (aAttribute == nsAccessibilityAtoms::multiselectable) {
// This affects whether the accessible supports nsIAccessibleSelectable.
// COM says we cannot change what interfaces are supported on-the-fly,
// so invalidate this object. A new one will be created on demand.
if (HasRoleAttribute(aContent)) {
// The multiselectable and other waistate attributes only take affect
// when dynamic content role is present
- InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_REORDER);
+ InvalidateCacheSubtree(aContent, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
}
}
}
void nsDocAccessible::ContentAppended(nsIDocument *aDocument,
nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
{
@@ -1134,17 +1151,17 @@ void nsDocAccessible::ContentAppended(ns
nsCOMPtr<nsIContent> child(aContainer->GetChildAt(index));
FireTextChangedEventOnDOMNodeInserted(child, aContainer, index);
// InvalidateCacheSubtree will not fire the EVENT_SHOW for the new node
// unless an accessible can be created for the passed in node, which it
// can't do unless the node is visible. The right thing happens there so
// no need for an extra visibility check here.
- InvalidateCacheSubtree(child, nsIAccessibleEvent::EVENT_SHOW);
+ InvalidateCacheSubtree(child, nsIAccessibleEvent::EVENT_DOM_CREATE);
}
}
void nsDocAccessible::ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2,
PRInt32 aStateMask)
{
@@ -1168,27 +1185,27 @@ nsDocAccessible::ContentInserted(nsIDocu
nsIContent* aChild, PRInt32 aIndexInContainer)
{
FireTextChangedEventOnDOMNodeInserted(aChild, aContainer, aIndexInContainer);
// InvalidateCacheSubtree will not fire the EVENT_SHOW for the new node
// unless an accessible can be created for the passed in node, which it
// can't do unless the node is visible. The right thing happens there so
// no need for an extra visibility check here.
- InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_SHOW);
+ InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_DOM_CREATE);
}
void
nsDocAccessible::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
nsIContent* aChild, PRInt32 aIndexInContainer)
{
FireTextChangedEventOnDOMNodeRemoved(aChild, aContainer, aIndexInContainer);
// Invalidate the subtree of the removed element.
- InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_HIDE);
+ InvalidateCacheSubtree(aChild, nsIAccessibleEvent::EVENT_DOM_DESTROY);
}
void
nsDocAccessible::ParentChainChanged(nsIContent *aContent)
{
}
void
@@ -1359,45 +1376,84 @@ nsDocAccessible::FireTextChangedEventOnD
return;
textAccessible->FireAccessibleEvent(event);
}
nsresult nsDocAccessible::FireDelayedToolkitEvent(PRUint32 aEvent,
nsIDOMNode *aDOMNode,
void *aData,
- PRBool aAllowDupes)
+ EDupeEventRule aAllowDupes,
+ PRBool aIsAsynch)
{
- nsCOMPtr<nsIAccessibleEvent> event = new nsAccEvent(aEvent, aDOMNode, aData);
+ nsCOMPtr<nsIAccessibleEvent> event =
+ new nsAccEvent(aEvent, aDOMNode, aData, PR_TRUE);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
- return FireDelayedAccessibleEvent(event);
+ return FireDelayedAccessibleEvent(event, aAllowDupes, aIsAsynch);
}
nsresult
nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
- PRBool aAllowDupes)
+ EDupeEventRule aAllowDupes,
+ PRBool aIsAsynch)
{
PRBool isTimerStarted = PR_TRUE;
PRInt32 numQueuedEvents = mEventsToFire.Count();
if (!mFireEventTimer) {
// Do not yet have a timer going for firing another event.
mFireEventTimer = do_CreateInstance("@mozilla.org/timer;1");
NS_ENSURE_TRUE(mFireEventTimer, NS_ERROR_OUT_OF_MEMORY);
}
PRUint32 newEventType;
aEvent->GetEventType(&newEventType);
nsCOMPtr<nsIDOMNode> newEventDOMNode;
aEvent->GetDOMNode(getter_AddRefs(newEventDOMNode));
+ if (!aIsAsynch) {
+ // If already asynchronous don't call PrepareFromEvent() -- it
+ // should only be called while ESM still knows if the event occurred
+ // originally because of user input
+ nsAccEvent::PrepareForEvent(newEventDOMNode);
+ }
+
if (numQueuedEvents == 0) {
isTimerStarted = PR_FALSE;
- } else if (!aAllowDupes) {
+ } else if (aAllowDupes == eCoalesceFromSameSubtree) {
+ // Especially for mutation events, we will define a duplicate event
+ // as one on the same node or on a descendant node.
+ // This prevents a flood of events when a subtree is changed.
+ for (PRInt32 index = 0; index < numQueuedEvents; index ++) {
+ nsIAccessibleEvent *accessibleEvent = mEventsToFire[index];
+ NS_ASSERTION(accessibleEvent, "Array item is not an accessible event");
+ if (!accessibleEvent) {
+ continue;
+ }
+ PRUint32 eventType;
+ accessibleEvent->GetEventType(&eventType);
+ if (eventType == newEventType) {
+ nsCOMPtr<nsIDOMNode> domNode;
+ accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
+ if (newEventDOMNode == domNode || nsAccUtils::IsAncestorOf(newEventDOMNode, domNode)) {
+ mEventsToFire.RemoveObjectAt(index);
+ // The other event is the same type, but in a descendant of this
+ // event, so remove that one. The umbrella event in the ancestor
+ // is already enough
+ -- index;
+ -- numQueuedEvents;
+ }
+ else if (nsAccUtils::IsAncestorOf(domNode, newEventDOMNode)) {
+ // There is a better SHOW/HIDE event (it's in an ancestor)
+ return NS_OK;
+ }
+ }
+ }
+ } else if (aAllowDupes == eRemoveDupes) {
// Check for repeat events. If a redundant event exists remove
// original and put the new event at the end of the queue
// so it is fired after the others
for (PRInt32 index = 0; index < numQueuedEvents; index ++) {
nsIAccessibleEvent *accessibleEvent = mEventsToFire[index];
NS_ASSERTION(accessibleEvent, "Array item is not an accessible event");
if (!accessibleEvent) {
continue;
@@ -1465,41 +1521,51 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
NS_ENSURE_TRUE(caretMoveEvent, NS_ERROR_OUT_OF_MEMORY);
FireAccessibleEvent(caretMoveEvent);
PRInt32 selectionCount;
accessibleText->GetSelectionCount(&selectionCount);
if (selectionCount) { // There's a selection so fire selection change as well
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
- accessible);
+ accessible, PR_TRUE);
}
}
}
else {
+ // The input state was previously stored with the nsIAccessibleEvent,
+ // so use that state now when firing the event
+ nsAccEvent::PrepareForEvent(accessibleEvent);
FireAccessibleEvent(accessibleEvent);
+ // Post event processing
+ if (eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+ eventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
+ // Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in this subtree
+ nsCOMPtr<nsIDOMNode> hidingNode;
+ accessibleEvent->GetDOMNode(getter_AddRefs(hidingNode));
+ if (hidingNode) {
+ RefreshNodes(hidingNode); // Will this bite us with asynch events
+ }
+ }
}
}
}
mEventsToFire.Clear(); // Clear out array
return NS_OK;
}
void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
{
nsPIAccessibleDocument *accessibleDoc = static_cast<nsPIAccessibleDocument*>(aClosure);
NS_ASSERTION(accessibleDoc, "How did we get here without an accessible document?");
accessibleDoc->FlushPendingEvents();
}
-void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode, PRUint32 aChangeEvent)
+void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode)
{
- NS_ASSERTION(aChangeEvent != nsIAccessibleEvent::EVENT_SHOW,
- "nsDocAccessible::RefreshNodes isn't supposed to work with show event.");
-
nsCOMPtr<nsIDOMNode> iterNode(aStartNode), nextNode;
nsCOMPtr<nsIAccessNode> accessNode;
do {
GetCachedAccessNode(iterNode, getter_AddRefs(accessNode));
if (accessNode) {
// Accessibles that implement their own subtrees,
// like html combo boxes and xul trees must shutdown all of their own
@@ -1560,21 +1626,36 @@ void nsDocAccessible::RefreshNodes(nsIDO
} while (PR_TRUE);
}
while (iterNode && iterNode != aStartNode);
}
NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
PRUint32 aChangeEventType)
{
- NS_ASSERTION(aChangeEventType == nsIAccessibleEvent::EVENT_REORDER ||
- aChangeEventType == nsIAccessibleEvent::EVENT_SHOW ||
- aChangeEventType == nsIAccessibleEvent::EVENT_HIDE,
+ PRBool isHiding =
+ aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+ aChangeEventType == nsIAccessibleEvent::EVENT_DOM_DESTROY;
+
+ PRBool isShowing =
+ aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
+ aChangeEventType == nsIAccessibleEvent::EVENT_DOM_CREATE;
+
+ PRBool isChanging =
+ aChangeEventType == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE ||
+ aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE;
+
+ NS_ASSERTION(isChanging || isHiding || isShowing,
"Incorrect aChangeEventType passed in");
+ PRBool isAsynch =
+ aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+ aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW ||
+ aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE;
+
// Invalidate cache subtree
// We have to check for accessibles for each dom node by traversing DOM tree
// instead of just the accessible tree, although that would be faster
// Otherwise we might miss the nsAccessNode's that are not nsAccessible's.
NS_ENSURE_TRUE(mDOMNode, NS_ERROR_FAILURE);
nsCOMPtr<nsIDOMNode> childNode = aChild ? do_QueryInterface(aChild) : mDOMNode;
if (!IsNodeRelevant(childNode)) {
@@ -1586,51 +1667,61 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
// by not firing SHOW/HIDE/REORDER events for every document mutation
// caused by page load, since AT is not going to want to grab the
// document and listen to these changes until after the page is first loaded
// Leave early, and ensure mAccChildCount stays uninitialized instead of 0,
// which it is if anyone asks for its children right now.
return InvalidateChildren();
}
+ // Update last change state information
nsCOMPtr<nsIAccessNode> childAccessNode;
GetCachedAccessNode(childNode, getter_AddRefs(childAccessNode));
nsCOMPtr<nsIAccessible> childAccessible = do_QueryInterface(childAccessNode);
- if (!childAccessible && aChangeEventType != nsIAccessibleEvent::EVENT_HIDE) {
+ if (!childAccessible && !isHiding) {
// If not about to hide it, make sure there's an accessible so we can fire an
// event for it
GetAccService()->GetAccessibleFor(childNode, getter_AddRefs(childAccessible));
}
#ifdef DEBUG_A11Y
nsAutoString localName;
childNode->GetLocalName(localName);
const char *hasAccessible = childAccessible ? " (acc)" : "";
- if (aChangeEventType == nsIAccessibleEvent::EVENT_HIDE) {
+ if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE) {
printf("[Hide %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
- else if (aChangeEventType == nsIAccessibleEvent::EVENT_SHOW) {
+ else if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW) {
printf("[Show %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
- else if (aChangeEventType == nsIAccessibleEvent::EVENT_REORDER) {
- printf("[Reorder %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
+ else if (aChangeEventType == nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE) {
+ printf("[Layout change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
+ }
+ else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_CREATE) {
+ printf("[Create %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
+ }
+ else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
+ printf("[Destroy %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
+ }
+ else if (aChangeEventType == nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE) {
+ printf("[Type change %s %s]\n", NS_ConvertUTF16toUTF8(localName).get(), hasAccessible);
}
#endif
- if (aChangeEventType == nsIAccessibleEvent::EVENT_HIDE ||
- aChangeEventType == nsIAccessibleEvent::EVENT_REORDER) {
- // Fire EVENT_HIDE if previous accessible existed for node being hidden.
+ if (!isShowing) {
+ // Fire EVENT_ASYNCH_HIDE or EVENT_DOM_DESTROY if previous accessible existed for node being hidden.
// Fire this before the accessible goes away.
- if (childAccessible)
- nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_HIDE, childAccessible);
- }
-
- // Shutdown nsIAccessNode's or nsIAccessibles for any DOM nodes in this subtree
- if (aChangeEventType != nsIAccessibleEvent::EVENT_SHOW) {
- RefreshNodes(childNode, aChangeEventType);
+ if (childAccessible) {
+ PRUint32 removalEventType = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_HIDE :
+ nsIAccessibleEvent::EVENT_DOM_DESTROY;
+ nsCOMPtr<nsIAccessibleEvent> removalEvent =
+ new nsAccEvent(removalEventType, childAccessible, nsnull, PR_TRUE);
+ NS_ENSURE_TRUE(removalEvent, NS_ERROR_OUT_OF_MEMORY);
+ FireDelayedAccessibleEvent(removalEvent, eCoalesceFromSameSubtree, isAsynch);
+ }
}
// We need to get an accessible for the mutation event's container node
// If there is no accessible for that node, we need to keep moving up the parent
// chain so there is some accessible.
// We will use this accessible to fire the accessible mutation event.
// We're guaranteed success, because we will eventually end up at the doc accessible,
// and there is always one of those.
@@ -1641,62 +1732,61 @@ NS_IMETHODIMP nsDocAccessible::Invalidat
containerAccessible = this;
}
nsCOMPtr<nsPIAccessible> privateContainerAccessible =
do_QueryInterface(containerAccessible);
if (privateContainerAccessible) {
privateContainerAccessible->InvalidateChildren();
}
- // Fire an event so the assistive technology knows the objects it is holding onto
- // in this part of the subtree are no longer useful and should be released.
- // However, they still won't crash if the AT tries to use them, because a stub of the
- // object still exists as long as it is refcounted, even from outside of Gecko.
- nsCOMPtr<nsIAccessNode> containerAccessNode =
- do_QueryInterface(containerAccessible);
- if (containerAccessNode) {
- nsCOMPtr<nsIDOMNode> containerNode;
- containerAccessNode->GetDOMNode(getter_AddRefs(containerNode));
- if (containerNode) {
- FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_REORDER,
- containerNode, nsnull);
- }
- }
-
- if (aChild && (aChangeEventType == nsIAccessibleEvent::EVENT_SHOW ||
- aChangeEventType == nsIAccessibleEvent::EVENT_REORDER)) {
+ if (aChild && !isHiding) {
// Fire EVENT_SHOW, EVENT_MENUPOPUP_START for newly visible content.
// Fire after a short timer, because we want to make sure the view has been
// updated to make this accessible content visible. If we don't wait,
// the assistive technology may receive the event and then retrieve
// nsIAccessibleStates::STATE_INVISIBLE for the event's accessible object.
- FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SHOW, childNode, nsnull);
+ PRUint32 additionEvent = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_SHOW :
+ nsIAccessibleEvent::EVENT_DOM_CREATE;
+ FireDelayedToolkitEvent(additionEvent, childNode, nsnull,
+ eCoalesceFromSameSubtree, isAsynch);
+
+ // Check to see change occured in an ARIA menu, and fire an EVENT_MENUPOPUP_START if it did
nsAutoString role;
if (GetRoleAttribute(aChild, role) &&
StringEndsWith(role, NS_LITERAL_STRING(":menu"), nsCaseInsensitiveStringComparator())) {
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
- childNode, nsnull);
+ childNode, nsnull, eAllowDupes, isAsynch);
}
- }
- // Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
- if (aChangeEventType != nsIAccessibleEvent::EVENT_HIDE) {
+ // Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
nsIContent *ancestor = aChild;
- nsAutoString role;
while (ancestor) {
if (GetRoleAttribute(ancestor, role) &&
StringEndsWith(role, NS_LITERAL_STRING(":alert"), nsCaseInsensitiveStringComparator())) {
nsCOMPtr<nsIDOMNode> alertNode(do_QueryInterface(ancestor));
- FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode, nsnull);
+ FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode, nsnull,
+ eRemoveDupes, isAsynch);
break;
}
ancestor = ancestor->GetParent();
}
}
+ if (!isShowing) {
+ // Fire an event so the assistive technology knows the children have changed
+ // This is only used by older MSAA clients. Newer ones should derive this
+ // from SHOW and HIDE so that they don't fetch extra objects
+ if (childAccessible) {
+ nsCOMPtr<nsIAccessibleEvent> reorderEvent =
+ new nsAccEvent(nsIAccessibleEvent::EVENT_REORDER, containerAccessible, nsnull, PR_TRUE);
+ NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
+ FireDelayedAccessibleEvent(reorderEvent, eCoalesceFromSameSubtree, isAsynch);
+ }
+ }
+
return NS_OK;
}
NS_IMETHODIMP
nsDocAccessible::GetAccessibleInParentChain(nsIDOMNode *aNode,
nsIAccessible **aAccessible)
{
// Find accessible in parent chain of DOM nodes, or return null
@@ -1750,17 +1840,17 @@ void nsDocAccessible::DocLoadCallback(ns
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = do_QueryInterface(container);
if (!docShellTreeItem) {
return;
}
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
docShellTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
if (sameTypeRoot != docShellTreeItem) {
// A frame or iframe has finished loading new content
- docAcc->InvalidateCacheSubtree(nsnull, nsIAccessibleEvent::EVENT_REORDER);
+ docAcc->InvalidateCacheSubtree(nsnull, nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
return;
}
// Fire STATE_CHANGE event for doc load finish if focus is in same doc tree
if (gLastFocusedNode) {
nsCOMPtr<nsIDocShellTreeItem> focusedTreeItem =
GetDocShellTreeItemFor(gLastFocusedNode);
if (focusedTreeItem) {
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -94,43 +94,64 @@ class nsDocAccessible : public nsHyperTe
// nsIAccessNode
NS_IMETHOD Shutdown();
NS_IMETHOD Init();
// nsPIAccessNode
NS_IMETHOD_(nsIFrame *) GetFrame(void);
- // Non-virtual
+ // nsIAccessibleText
+ NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
+
+ enum EDupeEventRule { eAllowDupes, eCoalesceFromSameSubtree, eRemoveDupes };
+
+ /**
+ * Non-virtual method to fire a delayed event after a 0 length timeout
+ *
+ * @param aEvent - the nsIAccessibleEvent event ype
+ * @param aDOMNode - DOM node the accesible event should be fired for
+ * @param aData - any additional data for the event
+ * @param aAllowDupes - eAllowDupes: more than one event of the same type is allowed.
+ * eCoalesceFromSameSubtree: if two events are in the same subtree,
+ * only the event on ancestor is used
+ * eRemoveDupes (default): events of the same type are discarded
+ * (the last one is used)
+ *
+ * @param aIsAsyn - set to PR_TRUE if this is not being called from code
+ * synchronous with a DOM event
+ */
nsresult FireDelayedToolkitEvent(PRUint32 aEvent, nsIDOMNode *aDOMNode,
- void *aData, PRBool aAllowDupes = PR_FALSE);
+ void *aData, EDupeEventRule aAllowDupes = eRemoveDupes,
+ PRBool aIsAsynch = PR_FALSE);
/**
* Fire accessible event in timeout.
*
+ * @param aEvent - the event to fire
* @param aAllowDupes - if false then delayed events of the same type and
* for the same DOM node in the event queue won't
* be fired.
+ * @param aIsAsych - set to PR_TRUE if this is being called from
+ * an event asynchronous with the DOM
*/
nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
- PRBool aAllowDupes = PR_FALSE);
+ EDupeEventRule aAllowDupes = eRemoveDupes,
+ PRBool aIsAsynch = PR_FALSE);
void ShutdownChildDocuments(nsIDocShellTreeItem *aStart);
protected:
virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame);
virtual nsresult AddEventListeners();
virtual nsresult RemoveEventListeners();
void AddScrollListener();
void RemoveScrollListener();
- void RefreshNodes(nsIDOMNode *aStartNode, PRUint32 aChangeEvent);
+ void RefreshNodes(nsIDOMNode *aStartNode);
static void ScrollTimerCallback(nsITimer *aTimer, void *aClosure);
- void CheckForEditor();
- virtual void SetEditor(nsIEditor *aEditor);
- virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
/**
* Fires accessible events when ARIA attribute is chaned.
*
* @param aContent - node that attribute is changed for
* @param aAttribute - changed attribute
*/
void ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute);
@@ -159,17 +180,16 @@ class nsDocAccessible : public nsHyperTe
nsAccessNodeHashtable mAccessNodeCache;
void *mWnd;
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsITimer> mScrollWatchTimer;
nsCOMPtr<nsITimer> mFireEventTimer;
PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
PRPackedBool mIsContentLoaded;
nsCOMArray<nsIAccessibleEvent> mEventsToFire;
- nsCOMPtr<nsIEditor> mEditor;
protected:
PRBool mIsAnchor;
PRBool mIsAnchorJumped;
private:
static void DocLoadCallback(nsITimer *aTimer, void *aClosure);
nsCOMPtr<nsITimer> mDocLoadTimer;
--- a/accessible/src/base/nsRootAccessible.cpp
+++ b/accessible/src/base/nsRootAccessible.cpp
@@ -414,23 +414,24 @@ void nsRootAccessible::TryFireEarlyLoadE
if (state & nsIAccessibleStates::STATE_BUSY) {
// Don't fire page load events on subdocuments for initial page load of entire page
return;
}
}
// No frames or iframes, so we can fire the doc load finished event early
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode,
- nsnull, PR_FALSE);
+ nsnull, eRemoveDupes);
}
PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
nsIDOMNode *aNode,
nsIDOMEvent *aFocusEvent,
- PRBool aForceEvent)
+ PRBool aForceEvent,
+ PRBool aIsAsynch)
{
if (mCaretAccessible) {
nsCOMPtr<nsIDOMNSEvent> nsevent(do_QueryInterface(aFocusEvent));
if (nsevent) {
// Use the originally focused node where the selection lives.
// For example, use the anonymous HTML:input instead of the containing
// XUL:textbox. In this case, sometimes it is a later focus event
// which points to the actual anonymous child with focus, so to be safe
@@ -505,17 +506,17 @@ PRBool nsRootAccessible::FireAccessibleF
// Suppress document focus, because real DOM focus will be fired next,
// and that's what we care about
// Make sure we never fire focus for the nsRootAccessible (mDOMNode)
return PR_FALSE;
}
}
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_FOCUS,
- finalFocusNode, nsnull);
+ finalFocusNode, nsnull, eRemoveDupes, aIsAsynch);
return PR_TRUE;
}
void nsRootAccessible::FireCurrentFocusEvent()
{
nsCOMPtr<nsIDOMNode> focusedNode = GetCurrentFocus();
if (!focusedNode) {
@@ -602,22 +603,22 @@ nsresult nsRootAccessible::HandleEventWi
if (eventType.EqualsLiteral("DOMContentLoaded")) {
// Don't create the doc accessible until load scripts have a chance to set
// role attribute for <body> or <html> element, because the value of
// role attribute will be cached when the doc accessible is Init()'d
TryFireEarlyLoadEvent(aTargetNode);
return NS_OK;
}
- if (eventType.EqualsLiteral("TreeViewChanged")) {
+ if (eventType.EqualsLiteral("TreeViewChanged")) { // Always asynch, always from user input
NS_ENSURE_TRUE(localName.EqualsLiteral("tree"), NS_OK);
nsCOMPtr<nsIContent> treeContent = do_QueryInterface(aTargetNode);
-
+ nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
return accService->InvalidateSubtreeFor(eventShell, treeContent,
- nsIAccessibleEvent::EVENT_REORDER);
+ nsIAccessibleEvent::EVENT_ASYNCH_SIGNIFICANT_CHANGE);
}
nsCOMPtr<nsIAccessible> accessible;
accService->GetAccessibleInShell(aTargetNode, eventShell,
getter_AddRefs(accessible));
nsCOMPtr<nsPIAccessible> privAcc(do_QueryInterface(accessible));
if (!privAcc)
return NS_OK;
@@ -759,17 +760,17 @@ nsresult nsRootAccessible::HandleEventWi
if (role == nsIAccessibleRole::ROLE_MENUPOPUP) {
event = nsIAccessibleEvent::EVENT_MENUPOPUP_START;
}
else if (role == nsIAccessibleRole::ROLE_TOOLTIP) {
// There is a single <xul:tooltip> node which Mozilla moves around.
// The accessible for it stays the same no matter where it moves.
// AT's expect to get an EVENT_SHOW for the tooltip.
// In event callback the tooltip's accessible will be ready.
- event = nsIAccessibleEvent::EVENT_SHOW;
+ event = nsIAccessibleEvent::EVENT_ASYNCH_SHOW;
}
if (event) {
nsAccUtils::FireAccEvent(event, accessible);
}
}
else if (eventType.EqualsLiteral("popuphiding")) {
// If accessible focus was on or inside popup that closes,
@@ -817,23 +818,26 @@ nsresult nsRootAccessible::HandleEventWi
accessible->GetParent(getter_AddRefs(containerAccessible));
NS_ENSURE_TRUE(containerAccessible, NS_ERROR_FAILURE);
// It is not top level menuitem
// Only fire focus event if it is not inside collapsed popup
if (State(containerAccessible) & nsIAccessibleStates::STATE_COLLAPSED)
return NS_OK;
}
}
- FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE);
+ nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE); // Always asynch, always from user input
+ FireAccessibleFocusEvent(accessible, aTargetNode, aEvent, PR_TRUE, PR_TRUE);
}
- else if (eventType.EqualsLiteral("DOMMenuBarActive")) {
- nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible);
+ else if (eventType.EqualsLiteral("DOMMenuBarActive")) { // Always asynch, always from user input
+ nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
+ nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_START, accessible, PR_TRUE);
}
- else if (eventType.EqualsLiteral("DOMMenuBarInactive")) {
- nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_END, accessible);
+ else if (eventType.EqualsLiteral("DOMMenuBarInactive")) { // Always asynch, always from user input
+ nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
+ nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_MENU_END, accessible, PR_TRUE);
FireCurrentFocusEvent();
}
else if (eventType.EqualsLiteral("ValueChange")) {
nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE, accessible);
}
return NS_OK;
}
--- a/accessible/src/base/nsRootAccessible.h
+++ b/accessible/src/base/nsRootAccessible.h
@@ -96,17 +96,18 @@ class nsRootAccessible : public nsDocAcc
* @param aFocusNode The DOM Node which has received focus.
* @param aFocusEvent DOM focus event that caused the node/accessible to receive focus
* @param aForceEvent Fire a focus event even if the last focused item was the same
* @return Boolean -- was a focus event actually fired
*/
PRBool FireAccessibleFocusEvent(nsIAccessible *aFocusAccessible,
nsIDOMNode *aFocusNode,
nsIDOMEvent *aFocusEvent,
- PRBool aForceEvent = PR_FALSE);
+ PRBool aForceEvent = PR_FALSE,
+ PRBool aIsAsynch = PR_FALSE);
nsCaretAccessible *GetCaretAccessible();
private:
nsCOMPtr<nsITimer> mFireFocusTimer;
static void FireFocusCallback(nsITimer *aTimer, void *aClosure);
protected:
--- a/accessible/src/html/Makefile.in
+++ b/accessible/src/html/Makefile.in
@@ -42,17 +42,18 @@ srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = accessibility
LIBRARY_NAME = accessibility_html_s
LIBXUL_LIBRARY = 1
-REQUIRES = content \
+REQUIRES = composer \
+ content \
docshell \
dom \
editor \
gfx \
imglib2 \
intl \
js \
layout \
--- a/accessible/src/html/nsHTMLFormControlAccessible.cpp
+++ b/accessible/src/html/nsHTMLFormControlAccessible.cpp
@@ -43,16 +43,17 @@
#include "nsIDOMDocument.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMNSHTMLElement.h"
#include "nsIDOMNSEditableElement.h"
#include "nsIDOMNSHTMLButtonElement.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIDOMHTMLLegendElement.h"
#include "nsIDOMHTMLTextAreaElement.h"
+#include "nsIEditor.h"
#include "nsIFrame.h"
#include "nsINameSpaceManager.h"
#include "nsISelectionController.h"
#include "jsapi.h"
#include "nsIJSContextStack.h"
#include "nsIServiceManager.h"
#include "nsITextControlFrame.h"
@@ -367,31 +368,16 @@ nsHTML4ButtonAccessible::GetState(PRUint
// --- textfield -----
nsHTMLTextFieldAccessible::nsHTMLTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell):
nsHyperTextAccessibleWrap(aNode, aShell)
{
}
-NS_IMPL_ISUPPORTS_INHERITED1(nsHTMLTextFieldAccessible, nsHyperTextAccessibleWrap,
- nsIAccessibleText)
-
-NS_IMETHODIMP nsHTMLTextFieldAccessible::Init()
-{
- CheckForEditor();
- return nsHyperTextAccessibleWrap::Init();
-}
-
-NS_IMETHODIMP nsHTMLTextFieldAccessible::Shutdown()
-{
- mEditor = nsnull;
- return nsHyperTextAccessibleWrap::Shutdown();
-}
-
NS_IMETHODIMP nsHTMLTextFieldAccessible::GetRole(PRUint32 *aRole)
{
*aRole = nsIAccessibleRole::ROLE_ENTRY;
nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
if (content &&
content->AttrValueIs(kNameSpaceID_None, nsAccessibilityAtoms::type,
nsAccessibilityAtoms::password, eIgnoreCase)) {
*aRole = nsIAccessibleRole::ROLE_PASSWORD_TEXT;
@@ -537,46 +523,39 @@ NS_IMETHODIMP nsHTMLTextFieldAccessible:
if ( element ) {
return element->Focus();
}
return NS_ERROR_FAILURE;
}
return NS_ERROR_INVALID_ARG;
}
-void nsHTMLTextFieldAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsHTMLTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor)
{
- mEditor = aEditor;
-}
-
-void nsHTMLTextFieldAccessible::CheckForEditor()
-{
+ *aEditor = nsnull;
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(mDOMNode));
- if (!editableElt) {
- return;
- }
+ NS_ENSURE_TRUE(editableElt, NS_ERROR_FAILURE);
// nsGenericHTMLElement::GetEditor has a security check.
// Make sure we're not restricted by the permissions of
// whatever script is currently running.
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
PRBool pushed = stack && NS_SUCCEEDED(stack->Push(nsnull));
nsCOMPtr<nsIEditor> editor;
- nsresult rv = editableElt->GetEditor(getter_AddRefs(editor));
- if (NS_SUCCEEDED(rv)) {
- SetEditor(editor);
- }
+ nsresult rv = editableElt->GetEditor(aEditor);
if (pushed) {
JSContext* cx;
stack->Pop(&cx);
NS_ASSERTION(!cx, "context should be null");
}
+
+ return rv;
}
// --- groupbox -----
/*
* The HTML for this is <fieldset> <legend>box-title</legend> form elements </fieldset>
*/
--- a/accessible/src/html/nsHTMLFormControlAccessible.h
+++ b/accessible/src/html/nsHTMLFormControlAccessible.h
@@ -97,36 +97,28 @@ public:
};
class nsHTMLTextFieldAccessible : public nsHyperTextAccessibleWrap
{
public:
enum { eAction_Click = 0 };
- NS_DECL_ISUPPORTS_INHERITED
-
nsHTMLTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
- NS_IMETHOD Init();
- NS_IMETHOD Shutdown();
NS_IMETHOD GetRole(PRUint32 *_retval);
NS_IMETHOD GetName(nsAString& aName);
NS_IMETHOD GetValue(nsAString& _retval);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
NS_IMETHOD GetNumActions(PRUint8 *_retval);
NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
NS_IMETHOD DoAction(PRUint8 index);
-protected:
- // Editor helpers, subclasses of nsHyperTextAccessible may have editor
- virtual void SetEditor(nsIEditor *aEditor);
- virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
- void CheckForEditor();
- nsCOMPtr<nsIEditor> mEditor;
+ // nsIAccessibleEditableText
+ NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
};
class nsHTMLGroupboxAccessible : public nsHyperTextAccessibleWrap
{
public:
nsHTMLGroupboxAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
NS_IMETHOD GetRole(PRUint32 *aRole);
NS_IMETHOD GetName(nsAString& aName);
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -42,35 +42,39 @@
#include "nsAccessibilityService.h"
#include "nsAccessibleTreeWalker.h"
#include "nsPIAccessNode.h"
#include "nsIClipboard.h"
#include "nsContentCID.h"
#include "nsIDOMAbstractView.h"
#include "nsIDOMCharacterData.h"
#include "nsIDOMDocument.h"
+#include "nsPIDOMWindow.h"
#include "nsIDOMDocumentView.h"
#include "nsIDOMRange.h"
#include "nsIDOMWindowInternal.h"
#include "nsIDOMXULDocument.h"
+#include "nsIEditingSession.h"
+#include "nsIEditor.h"
#include "nsIFontMetrics.h"
#include "nsIFrame.h"
+#include "nsIInterfaceRequestorUtils.h"
#include "nsIPlaintextEditor.h"
#include "nsIServiceManager.h"
#include "nsTextFragment.h"
#include "gfxSkipChars.h"
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
// ------------
// nsHyperTextAccessible
// ------------
-NS_IMPL_ADDREF_INHERITED(nsHyperTextAccessible, nsAccessible)
-NS_IMPL_RELEASE_INHERITED(nsHyperTextAccessible, nsAccessible)
+NS_IMPL_ADDREF_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
+NS_IMPL_RELEASE_INHERITED(nsHyperTextAccessible, nsAccessibleWrap)
nsresult nsHyperTextAccessible::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
*aInstancePtr = nsnull;
if (aIID.Equals(NS_GET_IID(nsHyperTextAccessible))) {
*aInstancePtr = static_cast<nsHyperTextAccessible*>(this);
NS_ADDREF_THIS();
@@ -164,17 +168,18 @@ NS_IMETHODIMP
nsHyperTextAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
{
nsresult rv = nsAccessibleWrap::GetState(aState, aExtraState);
NS_ENSURE_SUCCESS(rv, rv);
if (!aExtraState)
return NS_OK;
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
if (editor) {
PRUint32 flags;
editor->GetFlags(&flags);
if (0 == (flags & nsIPlaintextEditor::eEditorReadonlyMask)) {
*aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE;
}
}
@@ -190,18 +195,26 @@ nsHyperTextAccessible::GetState(PRUint32
void nsHyperTextAccessible::CacheChildren()
{
if (!mWeakShell) {
// This node has been shut down
mAccChildCount = eChildCountUninitialized;
return;
}
+ // Special case for text entry fields, go directly to editor's root for children
if (mAccChildCount == eChildCountUninitialized) {
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ PRUint32 role;
+ GetRole(&role);
+ if (role != nsIAccessibleRole::ROLE_ENTRY && role != nsIAccessibleRole::ROLE_PASSWORD_TEXT) {
+ nsAccessible::CacheChildren();
+ return;
+ }
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
if (!editor) {
nsAccessible::CacheChildren();
return;
}
nsCOMPtr<nsIDOMElement> editorRoot;
editor->GetRootElement(getter_AddRefs(editorRoot));
nsCOMPtr<nsIDOMNode> editorRootDOMNode = do_QueryInterface(editorRoot);
if (!editorRootDOMNode) {
@@ -295,18 +308,20 @@ nsIntRect nsHyperTextAccessible::GetBoun
}
return screenRect;
}
/*
* Gets the specified text.
*/
-nsIFrame* nsHyperTextAccessible::GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset, nsAString *aText,
- nsIFrame **aEndFrame, nsIntRect *aBoundsRect)
+nsIFrame*
+nsHyperTextAccessible::GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset,
+ nsAString *aText, nsIFrame **aEndFrame,
+ nsIntRect *aBoundsRect)
{
PRInt32 startOffset = aStartOffset;
PRInt32 endOffset = aEndOffset;
// Clear out parameters and set up loop
if (aText) {
aText->Truncate();
}
@@ -335,54 +350,63 @@ nsIFrame* nsHyperTextAccessible::GetPosA
// Loop through children and collect valid offsets, text and bounds
// depending on what we need for out parameters
while (NextChild(accessible)) {
nsCOMPtr<nsPIAccessNode> accessNode(do_QueryInterface(accessible));
nsIFrame *frame = accessNode->GetFrame();
if (!frame) {
continue;
}
+ nsIFrame *primaryFrame = frame;
if (IsText(accessible)) {
- // We only need info up to rendered offset -- that is what we're converting to content offset
+ // We only need info up to rendered offset -- that is what we're
+ // converting to content offset
PRInt32 substringEndOffset;
nsresult rv = frame->GetRenderedText(nsnull, &skipChars, &iter);
PRUint32 ourRenderedStart = iter.GetSkippedOffset();
PRInt32 ourContentStart = iter.GetOriginalOffset();
if (NS_SUCCEEDED(rv)) {
- substringEndOffset = iter.ConvertOriginalToSkipped(skipChars.GetOriginalCharCount() + ourContentStart) -
- ourRenderedStart;
+ substringEndOffset =
+ iter.ConvertOriginalToSkipped(skipChars.GetOriginalCharCount() +
+ ourContentStart) -
+ ourRenderedStart;
}
else {
- // XXX for non-textframe text like list bullets, should go away after list bullet rewrite
+ // XXX for non-textframe text like list bullets,
+ // should go away after list bullet rewrite
substringEndOffset = TextLength(accessible);
}
if (startOffset < substringEndOffset) {
// Our start is within this substring
if (startOffset > 0 || endOffset < substringEndOffset) {
// We don't want the whole string for this accessible
// Get out the continuing text frame with this offset
PRInt32 outStartLineUnused;
- PRInt32 contentOffset = iter.ConvertSkippedToOriginal(startOffset) + ourRenderedStart - ourContentStart;
- frame->GetChildFrameContainingOffset(contentOffset, PR_TRUE, &outStartLineUnused, &frame);
+ PRInt32 contentOffset = iter.ConvertSkippedToOriginal(startOffset) +
+ ourRenderedStart - ourContentStart;
+ frame->GetChildFrameContainingOffset(contentOffset, PR_TRUE,
+ &outStartLineUnused, &frame);
if (aEndFrame) {
*aEndFrame = frame; // We ended in the current frame
}
if (substringEndOffset > endOffset) {
// Need to stop before the end of the available text
substringEndOffset = endOffset;
}
aEndOffset = endOffset;
}
if (aText) {
nsCOMPtr<nsPIAccessible> pAcc(do_QueryInterface(accessible));
- pAcc->AppendTextTo(*aText, startOffset, substringEndOffset - startOffset);
+ pAcc->AppendTextTo(*aText, startOffset,
+ substringEndOffset - startOffset);
}
if (aBoundsRect) { // Caller wants the bounds of the text
- aBoundsRect->UnionRect(*aBoundsRect, GetBoundsForString(frame, startOffset,
- substringEndOffset));
+ aBoundsRect->UnionRect(*aBoundsRect,
+ GetBoundsForString(primaryFrame, startOffset,
+ substringEndOffset));
}
if (!startFrame) {
startFrame = frame;
aStartOffset = startOffset;
}
// We already started copying in this accessible's string,
// for the next accessible we'll start at offset 0
startOffset = 0;
@@ -403,17 +427,18 @@ nsIFrame* nsHyperTextAccessible::GetPosA
}
else {
if (endOffset > 0) {
if (aText) {
*aText += (frame->GetType() == nsAccessibilityAtoms::brFrame) ?
kForcedNewLineChar : kEmbeddedObjectChar;
}
if (aBoundsRect) {
- aBoundsRect->UnionRect(*aBoundsRect, frame->GetScreenRectExternal());
+ aBoundsRect->UnionRect(*aBoundsRect,
+ frame->GetScreenRectExternal());
}
}
if (!startFrame) {
startFrame = frame;
aStartOffset = 0;
}
}
-- endOffset;
@@ -515,22 +540,27 @@ nsresult nsHyperTextAccessible::DOMPoint
}
else {
// For non-text nodes, aNodeOffset comes in as a child node index
nsCOMPtr<nsIContent> parentContent(do_QueryInterface(aNode));
// Should not happen, but better to protect against crash if doc node is somehow passed in
NS_ENSURE_TRUE(parentContent, NS_ERROR_FAILURE);
// findNode could be null if aNodeOffset == # of child nodes, which means one of two things:
// 1) we're at the end of the children, keep findNode = null, so that we get the last possible offset
- // 2) there are no children, use parentContent for the node to find. In this case parentContent can't be
- // the nsIAccessibleText, because an accesible text must have children
+ // 2) there are no children and the passed-in node is mDOMNode, which means we're an aempty nsIAccessibleText
+ // 3) there are no children, and the passed-in node is not mDOMNode -- use parentContent for the node to find
findNode = do_QueryInterface(parentContent->GetChildAt(aNodeOffset));
if (!findNode && !aNodeOffset) {
- NS_ASSERTION(!SameCOMIdentity(parentContent, mDOMNode), "Cannot find child for DOMPointToHypertextOffset search");
+ if (SameCOMIdentity(parentContent, mDOMNode)) {
+ // There are no children, which means this is an empty nsIAccessibleText, in which
+ // case we can only be at hypertext offset 0
+ *aHyperTextOffset = 0;
+ return NS_OK;
+ }
findNode = do_QueryInterface(parentContent); // Case #2: there are no children
}
}
// Get accessible for this findNode, or if that node isn't accessible, use the
// accessible for the next DOM node which has one (based on forward depth first search)
nsCOMPtr<nsIAccessible> descendantAccessible;
if (findNode) {
@@ -1130,69 +1160,91 @@ NS_IMETHODIMP nsHyperTextAccessible::Set
return InsertText(aText, 0);
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsHyperTextAccessible::InsertText(const nsAString &aText, PRInt32 aPosition)
{
if (NS_SUCCEEDED(SetCaretOffset(aPosition))) {
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
nsCOMPtr<nsIPlaintextEditor> peditor(do_QueryInterface(editor));
return peditor ? peditor->InsertText(aText) : NS_ERROR_FAILURE;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsHyperTextAccessible::CopyText(PRInt32 aStartPos, PRInt32 aEndPos)
{
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
return editor->Copy();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsHyperTextAccessible::CutText(PRInt32 aStartPos, PRInt32 aEndPos)
{
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
return editor->Cut();
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsHyperTextAccessible::DeleteText(PRInt32 aStartPos, PRInt32 aEndPos)
{
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
if (editor && NS_SUCCEEDED(SetSelectionRange(aStartPos, aEndPos)))
return editor->DeleteSelection(nsIEditor::eNone);
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsHyperTextAccessible::PasteText(PRInt32 aPosition)
{
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
if (editor && NS_SUCCEEDED(SetCaretOffset(aPosition)))
return editor->Paste(nsIClipboard::kGlobalClipboard);
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsHyperTextAccessible::GetAssociatedEditor(nsIEditor **aEditor)
{
NS_ENSURE_ARG_POINTER(aEditor);
- nsCOMPtr<nsIEditor> editor(GetEditor());
- NS_IF_ADDREF(*aEditor = editor);
+ *aEditor = nsnull;
+ nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
+ NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
+
+ if (!content->HasFlag(NODE_IS_EDITABLE)) {
+ return NS_OK;
+ }
- return NS_OK;
+ nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = GetDocShellTreeItemFor(mDOMNode);
+ nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(docShellTreeItem));
+ if (!editingSession)
+ return NS_OK; // No editing session interface
+
+ nsCOMPtr<nsIPresShell> shell = GetPresShell();
+ NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIDocument> doc = shell->GetDocument();
+ NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIEditor> editor;
+ return editingSession->GetEditorForWindow(doc->GetWindow(), aEditor);
}
/**
* =================== Caret & Selection ======================
*/
nsresult nsHyperTextAccessible::SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos)
{
@@ -1254,17 +1306,18 @@ nsresult nsHyperTextAccessible::GetSelec
{
if (aSelCon) {
*aSelCon = nsnull;
}
if (aDomSel) {
*aDomSel = nsnull;
}
- nsCOMPtr<nsIEditor> editor = GetEditor();
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
if (editor) {
if (aSelCon) {
editor->GetSelectionController(aSelCon);
NS_ENSURE_TRUE(*aSelCon, NS_ERROR_FAILURE);
}
if (aDomSel) {
editor->GetSelection(aDomSel);
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -40,17 +40,16 @@
#ifndef _nsHyperTextAccessible_H_
#define _nsHyperTextAccessible_H_
#include "nsAccessibleWrap.h"
#include "nsIAccessibleText.h"
#include "nsIAccessibleHyperText.h"
#include "nsIAccessibleEditableText.h"
#include "nsAccessibleEventData.h"
-#include "nsIEditor.h"
#include "nsFrameSelection.h"
#include "nsISelectionController.h"
enum EGetTextType { eGetBefore=-1, eGetAt=0, eGetAfter=1 };
// This character marks where in the text returned via nsIAccessibleText(),
// that embedded object characters exist
const PRUnichar kEmbeddedObjectChar = 0xfffc;
@@ -152,20 +151,16 @@ protected:
* @param aBoundsRect (optional), return the bounds rectangle for this substring
* @return the start frame for this substring
*/
nsIFrame* GetPosAndText(PRInt32& aStartOffset, PRInt32& aEndOffset, nsAString *aText = nsnull,
nsIFrame **aEndFrame = nsnull, nsIntRect *aBoundsRect = nsnull);
nsIntRect GetBoundsForString(nsIFrame *aFrame, PRUint32 aStartRenderedOffset, PRUint32 aEndRenderedOffset);
- // Editor helpers, subclasses of nsHyperTextAccessible may have editor
- virtual void SetEditor(nsIEditor *aEditor) { return; }
- virtual already_AddRefed<nsIEditor> GetEditor() { return nsnull; }
-
// Selection helpers
nsresult GetSelections(nsISelectionController **aSelCon, nsISelection **aDomSel);
nsresult SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos);
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
NS_HYPERTEXTACCESSIBLE_IMPL_CID)
--- a/accessible/src/mac/nsAccessibleWrap.h
+++ b/accessible/src/mac/nsAccessibleWrap.h
@@ -73,29 +73,16 @@ class nsAccessibleWrap : public nsAccess
// returns a pointer to the native window for this accessible tree.
void GetNativeWindow (void **aOutNativeWindow);
virtual nsresult Shutdown ();
virtual nsresult InvalidateChildren ();
NS_IMETHOD FireAccessibleEvent(nsIAccessibleEvent *aEvent);
-
- // we'll flatten buttons and checkboxes. usually they have a text node
- // child, that is their title. Works in conjunction with IsPruned() below.
- // XXX There is no IsPruned() method, so what does that comment mean?
- PRBool IsFlat() {
- PRUint32 role = Role(this);
- return (role == nsIAccessibleRole::ROLE_CHECKBUTTON ||
- role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
- role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
- role == nsIAccessibleRole::ROLE_SPLITBUTTON ||
- role == nsIAccessibleRole::ROLE_ENTRY ||
- role == nsIAccessibleRole::ROLE_GRAPHIC);
- }
// ignored means that the accessible might still have children, but is not displayed
// to the user. it also has no native accessible object represented for it.
PRBool IsIgnored();
PRInt32 GetUnignoredChildCount(PRBool aDeepCount);
PRBool HasPopup () {
@@ -114,20 +101,21 @@ class nsAccessibleWrap : public nsAccess
// we don't create a native object if we're child of a "flat" accessible; for example, on OS X buttons
// shouldn't have any children, because that makes the OS confused.
//
// to maintain a scripting environment where the XPCOM accessible hierarchy look the same
// on all platforms, we still let the C++ objects be created though.
nsCOMPtr<nsIAccessible> curParent = GetParent();
while (curParent) {
- nsAccessibleWrap *ancestorWrap = static_cast<nsAccessibleWrap*>((nsIAccessible*)curParent.get());
- if (ancestorWrap->IsFlat())
+ if (MustPrune(curParent))
return PR_TRUE;
- curParent = static_cast<nsAccessibleWrap*>((nsIAccessible*)curParent.get())->GetParent();
+ nsCOMPtr<nsIAccessible> newParent;
+ curParent->GetParent(getter_AddRefs(newParent));
+ curParent.swap(newParent);
}
// no parent was flat
return PR_FALSE;
}
// Wrapper around our native object.
AccessibleWrapper *mNativeWrapper;
};
--- a/accessible/src/mac/nsAccessibleWrap.mm
+++ b/accessible/src/mac/nsAccessibleWrap.mm
@@ -201,33 +201,33 @@ nsAccessibleWrap::InvalidateChildren ()
}
return nsAccessible::InvalidateChildren();
}
PRInt32
nsAccessibleWrap::GetUnignoredChildCount(PRBool aDeepCount)
{
// if we're flat, we have no children.
- if (IsFlat())
+ if (MustPrune(this))
return 0;
PRInt32 childCount = 0;
GetChildCount(&childCount);
nsCOMPtr<nsIAccessible> curAcc;
while (NextChild(curAcc)) {
nsAccessibleWrap *childWrap = static_cast<nsAccessibleWrap*>((nsIAccessible*)curAcc.get());
// if the current child is not ignored, count it.
if (!childWrap->IsIgnored())
++childCount;
// if it's flat, we don't care to inspect its children.
- if (childWrap->IsFlat())
+ if (MustPrune(childWrap))
continue;
if (aDeepCount) {
// recursively count the unignored children of our children since it's a deep count.
childCount += childWrap->GetUnignoredChildCount(PR_TRUE);
} else {
// no deep counting, but if the child is ignored, we want to substitute it for its
// children.
@@ -248,24 +248,24 @@ nsAccessibleWrap::IsIgnored()
}
void
nsAccessibleWrap::GetUnignoredChildren(nsTArray<nsRefPtr<nsAccessibleWrap> > &aChildrenArray)
{
nsCOMPtr<nsIAccessible> curAcc;
// we're flat; there are no children.
- if (IsFlat())
+ if (MustPrune(this))
return;
while (NextChild(curAcc)) {
nsAccessibleWrap *childWrap = static_cast<nsAccessibleWrap*>((nsIAccessible*)curAcc.get());
if (childWrap->IsIgnored()) {
// element is ignored, so try adding its children as substitutes, if it has any.
- if (!childWrap->IsFlat()) {
+ if (!MustPrune(childWrap)) {
nsTArray<nsRefPtr<nsAccessibleWrap> > children;
childWrap->GetUnignoredChildren(children);
if (!children.IsEmpty()) {
// add the found unignored descendants to the array.
aChildrenArray.AppendElements(children);
}
}
} else
--- a/accessible/src/msaa/nsAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsAccessibleWrap.cpp
@@ -1524,17 +1524,18 @@ nsAccessibleWrap::FireAccessibleEvent(ns
}
PRInt32 childID = GetChildIDFor(accessible); // get the id for the accessible
if (!childID)
return NS_OK; // Can't fire an event without a child ID
// See if we're in a scrollable area with its own window
nsCOMPtr<nsIAccessible> newAccessible;
- if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
+ if (eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
+ eventType == nsIAccessibleEvent::EVENT_DOM_DESTROY) {
// Don't use frame from current accessible when we're hiding that
// accessible.
accessible->GetParent(getter_AddRefs(newAccessible));
} else {
newAccessible = accessible;
}
HWND hWnd = GetHWNDFor(accessible);
@@ -1709,19 +1710,8 @@ void nsAccessibleWrap::UpdateSystemCaret
if (::CreateCaret(caretWnd, caretBitMap, 1, caretRect.height)) { // Also destroys the last caret
::ShowCaret(caretWnd);
RECT windowRect;
::GetWindowRect(caretWnd, &windowRect);
::SetCaretPos(caretRect.x - windowRect.left, caretRect.y - windowRect.top);
::DeleteObject(caretBitMap);
}
}
-
-PRBool nsAccessibleWrap::MustPrune(nsIAccessible *aAccessible)
-{
- PRUint32 role = Role(aAccessible);
- return role == nsIAccessibleRole::ROLE_MENUITEM ||
- role == nsIAccessibleRole::ROLE_ENTRY ||
- role == nsIAccessibleRole::ROLE_PASSWORD_TEXT ||
- role == nsIAccessibleRole::ROLE_PUSHBUTTON ||
- role == nsIAccessibleRole::ROLE_TOGGLE_BUTTON ||
- role == nsIAccessibleRole::ROLE_GRAPHIC;
-}
--- a/accessible/src/msaa/nsAccessibleWrap.h
+++ b/accessible/src/msaa/nsAccessibleWrap.h
@@ -317,19 +317,16 @@ class nsAccessibleWrap : public nsAccess
static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible);
protected:
// mEnumVARIANTPosition not the current accessible's position, but a "cursor" of
// where we are in the current list of children, with respect to
// nsIEnumVariant::Reset(), Skip() and Next().
PRUint16 mEnumVARIANTPosition;
- // Should this accessible be allowed to have any MSAA children
- static PRBool MustPrune(nsIAccessible *aAccessible);
-
enum navRelations {
NAVRELATION_CONTROLLED_BY = 0x1000,
NAVRELATION_CONTROLLER_FOR = 0x1001,
NAVRELATION_LABEL_FOR = 0x1002,
NAVRELATION_LABELLED_BY = 0x1003,
NAVRELATION_MEMBER_OF = 0x1004,
NAVRELATION_NODE_CHILD_OF = 0x1005,
NAVRELATION_FLOWS_TO = 0x1006,
--- a/accessible/src/msaa/nsEventMap.h
+++ b/accessible/src/msaa/nsEventMap.h
@@ -41,22 +41,22 @@
#include "winable.h"
#include "AccessibleEventId.h"
const PRUint32 kEVENT_WIN_UNKNOWN = 0x00000000;
const PRUint32 kEVENT_LAST_ENTRY = 0xffffffff;
static const PRUint32 gWinEventMap[] = {
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent doesn't have 0 constant
- kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_CREATE
- kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_DESTROY
- EVENT_OBJECT_SHOW, // nsIAccessibleEvent::EVENT_SHOW
- EVENT_OBJECT_HIDE, // nsIAccessibleEvent::EVENT_HIDE
- EVENT_OBJECT_REORDER, // nsIAccessibleEvent::EVENT_REORDER
- kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_PARENT_CHANGE
+ EVENT_OBJECT_SHOW, // nsIAccessibleEvent::EVENT_DOM_CREATE
+ EVENT_OBJECT_HIDE, // nsIAccessibleEvent::EVENT_DOM_DESTROY
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE
+ EVENT_OBJECT_SHOW, // nsIAccessibleEvent::EVENT_ASYNCH_SHOW
+ EVENT_OBJECT_HIDE, // nsIAccessibleEvent::EVENT_ASYNCH_HIDE
+ kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_ASYNCH_LAYOUT_CHANGE
IA2_EVENT_ACTIVE_DECENDENT_CHANGED, // nsIAccessibleEvent::EVENT_ACTIVE_DECENDENT_CHANGED
EVENT_OBJECT_FOCUS, // nsIAccessibleEvent::EVENT_FOCUS
EVENT_OBJECT_STATECHANGE, // nsIAccessibleEvent::EVENT_STATE_CHANGE
EVENT_OBJECT_LOCATIONCHANGE, // nsIAccessibleEvent::EVENT_LOCATION_CHANGE
EVENT_OBJECT_NAMECHANGE, // nsIAccessibleEvent::EVENT_NAME_CHANGE
EVENT_OBJECT_DESCRIPTIONCHANGE, // nsIAccessibleEvent::EVENT_DESCRIPTION_CHANGE
EVENT_OBJECT_VALUECHANGE, // nsIAccessibleEvent::EVENT_VALUE_CHANGE
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_HELP_CHANGE
@@ -132,11 +132,12 @@ static const PRUint32 gWinEventMap[] = {
IA2_EVENT_HYPERTEXT_LINK_ACTIVATED, // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_ACTIVATED
IA2_EVENT_HYPERTEXT_LINK_SELECTED, // nsIAccessibleEvent::EVENT_HYPERTEXT_LINK_SELECTED
IA2_EVENT_HYPERLINK_START_INDEX_CHANGED, // nsIAccessibleEvent::EVENT_HYPERLINK_START_INDEX_CHANGED
IA2_EVENT_HYPERTEXT_CHANGED, // nsIAccessibleEvent::EVENT_HYPERTEXT_CHANGED
IA2_EVENT_HYPERTEXT_NLINKS_CHANGED, // nsIAccessibleEvent::EVENT_HYPERTEXT_NLINKS_CHANGED
IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED, // nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED
IA2_EVENT_PAGE_CHANGED, // nsIAccessibleEvent::EVENT_PAGE_CHANGED
kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_INTERNAL_LOAD
+ EVENT_OBJECT_REORDER, // nsIAccessibleEvent::EVENT_REORDER
kEVENT_LAST_ENTRY // nsIAccessibleEvent::EVENT_LAST_ENTRY
};
--- a/accessible/src/msaa/nsHyperTextAccessibleWrap.cpp
+++ b/accessible/src/msaa/nsHyperTextAccessibleWrap.cpp
@@ -49,17 +49,18 @@ IMPL_IUNKNOWN_INHERITED2(nsHyperTextAcce
CAccessibleEditableText);
NS_IMETHODIMP
nsHyperTextAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
{
PRUint32 eventType;
aEvent->GetEventType(&eventType);
- if (eventType == nsIAccessibleEvent::EVENT_TEXT_CHANGED) {
+ if (eventType == nsIAccessibleEvent::EVENT_TEXT_REMOVED ||
+ eventType == nsIAccessibleEvent::EVENT_TEXT_INSERTED) {
nsCOMPtr<nsIAccessible> accessible;
aEvent->GetAccessible(getter_AddRefs(accessible));
if (accessible) {
nsCOMPtr<nsIWinAccessNode> winAccessNode(do_QueryInterface(accessible));
if (winAccessNode) {
void *instancePtr = NULL;
nsresult rv = winAccessNode->QueryNativeInterface(IID_IAccessibleText,
&instancePtr);
--- a/accessible/src/xforms/nsXFormsAccessible.cpp
+++ b/accessible/src/xforms/nsXFormsAccessible.cpp
@@ -37,16 +37,17 @@
* ***** END LICENSE BLOCK ***** */
#include "nsXFormsAccessible.h"
#include "nscore.h"
#include "nsServiceManagerUtils.h"
#include "nsIDOMElement.h"
#include "nsIDOMNodeList.h"
+#include "nsIEditor.h"
#include "nsIMutableArray.h"
#include "nsIXFormsUtilityService.h"
#include "nsIPlaintextEditor.h"
// nsXFormsAccessibleBase
nsIXFormsUtilityService *nsXFormsAccessibleBase::sXFormsService = nsnull;
@@ -304,72 +305,50 @@ nsXFormsEditableAccessible::
NS_IMETHODIMP
nsXFormsEditableAccessible::GetState(PRUint32 *aState, PRUint32 *aExtraState)
{
NS_ENSURE_ARG_POINTER(aState);
nsresult rv = nsXFormsAccessible::GetState(aState, aExtraState);
NS_ENSURE_SUCCESS(rv, rv);
- if (!aExtraState || !mEditor)
+ if (!aExtraState)
return NS_OK;
PRBool isReadonly = PR_FALSE;
rv = sXFormsService->IsReadonly(mDOMNode, &isReadonly);
NS_ENSURE_SUCCESS(rv, rv);
if (!isReadonly) {
PRBool isRelevant = PR_FALSE;
rv = sXFormsService->IsRelevant(mDOMNode, &isRelevant);
NS_ENSURE_SUCCESS(rv, rv);
if (isRelevant) {
*aExtraState |= nsIAccessibleStates::EXT_STATE_EDITABLE |
nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT;
}
}
+ nsCOMPtr<nsIEditor> editor;
+ GetAssociatedEditor(getter_AddRefs(editor));
+ NS_ENSURE_TRUE(editor, NS_ERROR_FAILURE);
PRUint32 flags;
- mEditor->GetFlags(&flags);
+ editor->GetFlags(&flags);
if (flags & nsIPlaintextEditor::eEditorSingleLineMask)
*aExtraState |= nsIAccessibleStates::EXT_STATE_SINGLE_LINE;
else
*aExtraState |= nsIAccessibleStates::EXT_STATE_MULTI_LINE;
return NS_OK;
}
NS_IMETHODIMP
-nsXFormsEditableAccessible::Init()
-{
- nsCOMPtr<nsIEditor> editor;
- sXFormsService->GetEditor(mDOMNode, getter_AddRefs(editor));
- SetEditor(editor);
-
- return nsXFormsAccessible::Init();
-}
-
-NS_IMETHODIMP
-nsXFormsEditableAccessible::Shutdown()
+nsXFormsEditableAccessible::GetAssociatedEditor(nsIEditor **aEditor)
{
- SetEditor(nsnull);
- return nsXFormsAccessible::Shutdown();
-}
-
-already_AddRefed<nsIEditor>
-nsXFormsEditableAccessible::GetEditor()
-{
- nsIEditor *editor = mEditor;
- NS_IF_ADDREF(editor);
- return editor;
-}
-
-void
-nsXFormsEditableAccessible::SetEditor(nsIEditor *aEditor)
-{
- mEditor = aEditor;
+ return sXFormsService->GetEditor(mDOMNode, aEditor);
}
// nsXFormsSelectableAccessible
NS_IMPL_ISUPPORTS_INHERITED1(nsXFormsSelectableAccessible,
nsXFormsEditableAccessible,
nsIAccessibleSelectable)
--- a/accessible/src/xforms/nsXFormsAccessible.h
+++ b/accessible/src/xforms/nsXFormsAccessible.h
@@ -142,25 +142,18 @@ public:
*/
class nsXFormsEditableAccessible : public nsXFormsAccessible
{
public:
nsXFormsEditableAccessible(nsIDOMNode *aNode, nsIWeakReference *aShell);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
- NS_IMETHOD Init();
- NS_IMETHOD Shutdown();
-
-protected:
- virtual void SetEditor(nsIEditor *aEditor);
- virtual already_AddRefed<nsIEditor> GetEditor();
-
-private:
- nsCOMPtr<nsIEditor> mEditor;
+ // nsIAccessibleEditableText
+ NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
};
/**
* The class is base for accessible objects for XForms select and XForms
* select1 elements.
*/
class nsXFormsSelectableAccessible : public nsXFormsEditableAccessible
--- a/accessible/src/xul/nsXULFormControlAccessible.cpp
+++ b/accessible/src/xul/nsXULFormControlAccessible.cpp
@@ -45,16 +45,17 @@
#include "nsXULMenuAccessible.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMNSEditableElement.h"
#include "nsIDOMXULButtonElement.h"
#include "nsIDOMXULCheckboxElement.h"
#include "nsIDOMXULMenuListElement.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIDOMXULTextboxElement.h"
+#include "nsIEditor.h"
#include "nsIFrame.h"
#include "nsINameSpaceManager.h"
#include "nsITextControlFrame.h"
#include "nsIPresShell.h"
/**
* XUL Button: can contain arbitrary HTML content
*/
@@ -758,31 +759,16 @@ nsXULToolbarSeparatorAccessible::GetStat
* XUL Textfield
*/
nsXULTextFieldAccessible::nsXULTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell) :
nsHyperTextAccessibleWrap(aNode, aShell)
{
}
-NS_IMPL_ISUPPORTS_INHERITED1(nsXULTextFieldAccessible, nsHyperTextAccessible,
- nsIAccessibleText)
-
-NS_IMETHODIMP nsXULTextFieldAccessible::Init()
-{
- CheckForEditor();
- return nsHyperTextAccessibleWrap::Init();
-}
-
-NS_IMETHODIMP nsXULTextFieldAccessible::Shutdown()
-{
- mEditor = nsnull;
- return nsHyperTextAccessibleWrap::Shutdown();
-}
-
NS_IMETHODIMP nsXULTextFieldAccessible::GetValue(nsAString& aValue)
{
PRUint32 state;
GetState(&state, nsnull);
if (state & nsIAccessibleStates::STATE_PROTECTED) // Don't return password text!
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDOMXULTextBoxElement> textBox(do_QueryInterface(mDOMNode));
@@ -930,27 +916,16 @@ NS_IMETHODIMP nsXULTextFieldAccessible::
NS_IMETHODIMP
nsXULTextFieldAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren)
{
*aAllowsAnonChildren = PR_FALSE;
return NS_OK;
}
-void nsXULTextFieldAccessible::SetEditor(nsIEditor* aEditor)
+NS_IMETHODIMP nsXULTextFieldAccessible::GetAssociatedEditor(nsIEditor **aEditor)
{
- mEditor = aEditor;
-}
-
-void nsXULTextFieldAccessible::CheckForEditor()
-{
+ *aEditor = nsnull;
nsCOMPtr<nsIDOMNode> inputField = GetInputField();
nsCOMPtr<nsIDOMNSEditableElement> editableElt(do_QueryInterface(inputField));
- if (!editableElt) {
- return;
- }
-
- nsCOMPtr<nsIEditor> editor;
- nsresult rv = editableElt->GetEditor(getter_AddRefs(editor));
- if (NS_SUCCEEDED(rv)) {
- SetEditor(editor);
- }
+ NS_ENSURE_TRUE(editableElt, NS_ERROR_FAILURE);
+ return editableElt->GetEditor(aEditor);
}
--- a/accessible/src/xul/nsXULFormControlAccessible.h
+++ b/accessible/src/xul/nsXULFormControlAccessible.h
@@ -156,35 +156,28 @@ public:
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
};
class nsXULTextFieldAccessible : public nsHyperTextAccessibleWrap
{
public:
enum { eAction_Click = 0 };
- NS_DECL_ISUPPORTS_INHERITED
-
nsXULTextFieldAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
- NS_IMETHOD Init();
- NS_IMETHOD Shutdown();
NS_IMETHOD GetValue(nsAString& aValue);
NS_IMETHOD GetState(PRUint32 *aState, PRUint32 *aExtraState);
NS_IMETHOD GetRole(PRUint32 *aRole);
NS_IMETHOD GetNumActions(PRUint8 *_retval);
NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
NS_IMETHOD DoAction(PRUint8 index);
NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren);
+ // nsIAccessibleEditableText
+ NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
+
protected:
already_AddRefed<nsIDOMNode> GetInputField();
-
- // Editor helpers, subclasses of nsHyperTextAccessible may have editor
- virtual void SetEditor(nsIEditor *aEditor);
- virtual already_AddRefed<nsIEditor> GetEditor() { nsIEditor *editor = mEditor; NS_IF_ADDREF(editor); return editor; }
- void CheckForEditor();
- nsCOMPtr<nsIEditor> mEditor;
};
#endif
--- a/allmakefiles.sh
+++ b/allmakefiles.sh
@@ -139,21 +139,16 @@ MAKEFILES_expat="
parser/expat/Makefile
parser/expat/lib/Makefile
"
MAKEFILES_extensions="
extensions/Makefile
"
-MAKEFILES_gc="
-gc/boehm/Makefile
-gc/boehm/leaksoup/Makefile
-"
-
MAKEFILES_gfx="
gfx/Makefile
gfx/idl/Makefile
gfx/public/Makefile
gfx/src/Makefile
gfx/src/beos/Makefile
gfx/src/psshared/Makefile
gfx/src/photon/Makefile
@@ -315,17 +310,16 @@ content/html/document/src/Makefile
content/xml/Makefile
content/xml/content/Makefile
content/xml/content/src/Makefile
content/xml/document/Makefile
content/xml/document/public/Makefile
content/xml/document/src/Makefile
content/xul/Makefile
content/xul/content/Makefile
-content/xul/content/public/Makefile
content/xul/content/src/Makefile
content/xul/document/Makefile
content/xul/document/public/Makefile
content/xul/document/src/Makefile
content/xul/templates/public/Makefile
content/xul/templates/src/Makefile
content/xbl/Makefile
content/xbl/public/Makefile
@@ -560,17 +554,16 @@ webshell/public/Makefile
MAKEFILES_widget="
widget/Makefile
widget/public/Makefile
widget/src/Makefile
widget/src/beos/Makefile
widget/src/build/Makefile
widget/src/gtkxtbin/Makefile
widget/src/photon/Makefile
-widget/src/mac/Makefile
widget/src/cocoa/Makefile
widget/src/os2/Makefile
widget/src/windows/Makefile
widget/src/xpwidgets/Makefile
widget/src/support/Makefile
"
MAKEFILES_xpcom="
@@ -1259,17 +1252,16 @@ add_makefiles "
$MAKEFILES_docshell
$MAKEFILES_dom
$MAKEFILES_editor
$MAKEFILES_codesighs
$MAKEFILES_composer
$MAKEFILES_embedding
$MAKEFILES_expat
$MAKEFILES_extensions
-$MAKEFILES_gc
$MAKEFILES_gfx
$MAKEFILES_accessible
$MAKEFILES_htmlparser
$MAKEFILES_intl
$MAKEFILES_javaxpcom
$MAKEFILES_ldap
$MAKEFILES_leaky
$MAKEFILES_jpeg
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -234,16 +234,20 @@ pref("browser.search.openintab", false);
pref("browser.search.update", true);
// disable logging for the search service update system by default
pref("browser.search.update.log", false);
// Check whether we need to perform engine updates every 6 hours
pref("browser.search.updateinterval", 6);
+// Whether or not microsummary and generator updates are enabled
+pref("browser.microsummary.enabled", true);
+pref("browser.microsummary.updateGenerators", true);
+
// enable search suggestions by default
pref("browser.search.suggest.enabled", true);
pref("browser.history.grouping", "day");
pref("browser.history.showSessions", false);
pref("browser.sessionhistory.max_entries", 50);
pref("browser.history_expire_days", 180);
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -587,8 +587,146 @@ var PlacesMenuDNDController = {
// Whether or not drag and drop to menus is supported on this platform
// Dragging in menus is disabled on OS X due to various repainting issues.
#ifdef XP_MACOSX
_dragSupported: false
#else
_dragSupported: true
#endif
};
+
+var PlacesStarButton = {
+ init: function PSB_init() {
+ PlacesUtils.bookmarks.addObserver(this, false);
+ },
+
+ uninit: function PSB_uninit() {
+ PlacesUtils.bookmarks.removeObserver(this);
+ },
+
+ QueryInterface: function PSB_QueryInterface(aIID) {
+ if (aIID.equals(Ci.nsIDOMEventListener) ||
+ aIID.equals(Ci.nsINavBookmarkObserver) ||
+ aIID.equals(Ci.nsISupports))
+ return this;
+
+ throw Cr.NS_NOINTERFACE;
+ },
+
+ get panel() {
+ return document.getElementById("editBookmarkPanel");
+ },
+
+ _starred: false,
+ _batching: false,
+
+ updateState: function PSB_updateState() {
+ var uri = getBrowser().currentURI;
+ this._starred = uri && PlacesUtils.bookmarks.isBookmarked(uri);
+ if (this._starred)
+ document.getElementById("star-icon").setAttribute("starred", "true");
+ else
+ document.getElementById("star-icon").removeAttribute("starred");
+ },
+
+ _star: function PSB_star(aBrowser) {
+ var uri = aBrowser.currentURI;
+ if (!uri)
+ throw "No URL";
+
+ var title = PlacesUtils.history.getPageTitle(uri);
+
+ var descAnno = {
+ name: DESCRIPTION_ANNO,
+ value: PlacesUtils.getDescriptionFromDocument(aBrowser.contentDocument)
+ };
+ var txn = PlacesUtils.ptm.createItem(uri, PlacesUtils.placesRootId, -1,
+ title, null, [descAnno]);
+ PlacesUtils.ptm.commitTransaction(txn);
+ },
+
+ // nsIDOMEventListener
+ handleEvent: function PSB_handleEvent(aEvent) {
+ if (aEvent.originalTarget != this.panel)
+ return;
+
+ // This only happens for auto-hide. When the panel is closed from within
+ // itself, doneCallback removes the listener and only then hides the popup
+ gAddBookmarksPanel.saveItem();
+ gAddBookmarksPanel.uninitPanel();
+ },
+
+ showBookmarkPagePopup: function PSB_showBookmarkPagePopup(aBrowser) {
+ const bms = PlacesUtils.bookmarks;
+
+ var dockTo = document.getElementById("star-icon");
+ if (!dockTo)
+ dockTo = getBrowser();
+
+ var panel = this.panel;
+ panel.showPopup(dockTo, -1, -1, "popup", "bottomright", "topright");
+
+ var uri = aBrowser.currentURI;
+
+ var itemId = -1;
+ var bmkIds = bms.getBookmarkIdsForURI(uri, {});
+ for each (var bk in bmkIds) {
+ // Find the first folder which isn't a tag container
+ var folder = bms.getFolderIdForItem(bk);
+ if (folder == PlacesUtils.placesRootId ||
+ bms.getFolderIdForItem(folder) != PlacesUtils.tagRootId) {
+ itemId = bk;
+ break;
+ }
+ }
+ if (itemId == -1) {
+ // if we're called before the URI is bookmarked, or if the remaining
+ // items for this url are under tag containers, star the page first
+ itemId = this._star(aBrowser);
+ }
+ gAddBookmarksPanel.initPanel(itemId, PlacesUtils.tm, this.doneCallback,
+ { hiddenRows: "description" });
+ panel.addEventListener("popuphiding", this, false);
+ },
+
+ onClick: function PSB_onClick(aEvent) {
+ if (this._starred)
+ this.showBookmarkPagePopup(getBrowser());
+ else
+ this._star(getBrowser());
+ },
+
+ doneCallback: function PSB_doneCallback(aSavedChanges) {
+ var panel = PlacesStarButton.panel;
+ panel.removeEventListener("popuphiding", PlacesStarButton, false);
+ gAddBookmarksPanel.uninitPanel();
+ panel.hidePopup();
+ },
+
+ // nsINavBookmarkObserver
+ onBeginUpdateBatch: function PSB_onBeginUpdateBatch() {
+ this._batching = true;
+ },
+
+ onEndUpdateBatch: function PSB_onEndUpdateBatch() {
+ this.updateState();
+ this._batching = false;
+ },
+
+ onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex) {
+ if (!this._batching && !this._starred)
+ this.updateState();
+ },
+
+ onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex) {
+ if (!this._batching)
+ this.updateState();
+ },
+
+ onItemChanged: function PSB_onItemChanged(aItemId, aProperty,
+ aIsAnnotationProperty, aValue) {
+ if (!this._batching && aProperty == "uri")
+ this.updateState();
+ },
+
+ onItemVisited: function() { },
+ onItemMoved: function() { }
+};
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -12,26 +12,19 @@ searchbar {
}
/* ::::: print preview toolbar ::::: */
toolbar[printpreview="true"] {
-moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
}
menuitem.spell-suggestion {
- font-weight:bold;
+ font-weight: bold;
}
#sidebar-box toolbarbutton.tabs-closebutton {
-moz-user-focus: normal;
}
/* apply Fitts' law to the notification bar's close button */
window[sizemode="maximized"] #content .notification-inner {
- border-right: 0px !important;
+ border-right: 0px !important;
}
-
-/* ::::: Tooltips (multi-line) from content ::::: */
-.htmltooltip-label {
- max-width: 40em;
- margin: 0;
- white-space: -moz-pre-wrap;
-}
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1012,16 +1012,17 @@ function delayedStartup()
// add bookmark options to context menu for tabs
addBookmarkMenuitems();
PlacesMenuDNDController.init();
initBookmarksToolbar();
PlacesUtils.bookmarks.addObserver(gBookmarksObserver, false);
+ PlacesStarButton.init();
// called when we go into full screen, even if it is
// initiated by a web page script
window.addEventListener("fullscreen", onFullScreen, true);
if (gIsLoadingBlank && gURLBar && isElementVisible(gURLBar))
focusElement(gURLBar);
else
@@ -1152,16 +1153,17 @@ function BrowserShutdown()
os.removeObserver(gXPInstallObserver, "xpinstall-install-blocked");
try {
gBrowser.removeProgressListener(window.XULBrowserWindow);
} catch (ex) {
}
PlacesUtils.bookmarks.removeObserver(gBookmarksObserver);
+ PlacesStarButton.uninit();
try {
gPrefService.removeObserver(gAutoHideTabbarPrefListener.domain,
gAutoHideTabbarPrefListener);
gPrefService.removeObserver(gHomeButton.prefDomain, gHomeButton);
} catch (ex) {
Components.utils.reportError(ex);
}
@@ -1653,31 +1655,25 @@ function BrowserCloseTabOrWindow()
#ifdef XP_MACOSX
// If we're not a browser window, just close the window
if (window.location.href != getBrowserURL()) {
closeWindow(true);
return;
}
#endif
- if (gBrowser.tabContainer.childNodes.length > 1) {
- // Just close up a tab.
+ if (gBrowser.tabContainer.childNodes.length > 1 ||
+ window.toolbar.visible && !gPrefService.getBoolPref("browser.tabs.autoHide")) {
+ // Just close the tab (and focus the address bar if it was the last one).
+ var isLastTab = gBrowser.tabContainer.childNodes.length == 1;
gBrowser.removeCurrentTab();
- return;
- }
-#ifndef XP_MACOSX
- if (window.toolbar.visible &&
- !gPrefService.getBoolPref("browser.tabs.autoHide")) {
- // Replace the remaining tab with a blank one and focus the address bar
- gBrowser.removeCurrentTab();
- if (gURLBar)
+ if (isLastTab && gURLBar)
setTimeout(function() { gURLBar.focus(); }, 0);
return;
}
-#endif
closeWindow(true);
}
function BrowserTryToCloseWindow()
{
if (WindowIsClosing())
window.close(); // WindowIsClosing does all the necessary checks
@@ -3520,16 +3516,19 @@ nsBrowserStatusHandler.prototype =
// Setting the urlBar value in some cases causes userTypedValue to
// become set because of oninput, so reset it to its old value.
browser.userTypedValue = userTypedValue;
} else {
gURLBar.value = userTypedValue;
SetPageProxyState("invalid");
}
+
+ // Update starring UI
+ PlacesStarButton.updateState(aLocationURI);
}
}
UpdateBackForwardCommands(gBrowser.webNavigation);
if (gFindBar.findMode != gFindBar.FIND_NORMAL) {
// Close the Find toolbar if we're in old-style TAF mode
gFindBar.close();
}
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -48,16 +48,17 @@
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://global/skin/toolbar.css" type="text/css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
+<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
# All DTD information is stored in a separate file so that it can be shared by
# hiddenWindow.xul.
#include browser-doctype.inc
<window id="main-window"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
@@ -93,17 +94,22 @@
onclick="checkForMiddleClick(this, event);"/>
<popup id="forwardMenu"
position="after_start"
onpopupshowing="return BrowserForwardMenu(event);"
oncommand="gotoHistoryIndex(event);"
onclick="checkForMiddleClick(this, event);"/>
<tooltip id="aHTMLTooltip" onpopupshowing="return FillInHTMLTooltip(document.tooltipNode);"/>
- <panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete"/>
+ <panel type="autocomplete" chromedir="&locale.dir;" id="PopupAutoComplete" noautofocus="true"/>
+
+ <panel id="editBookmarkPanel"
+ position="after_end">
+ <vbox id="editBookmarkPanelContent" flex="1"/>
+ </panel>
<popup id="toolbar-context-menu"
onpopupshowing="onViewToolbarsPopupShowing(event);">
<menuseparator/>
<menuitem command="cmd_CustomizeToolbars"
label="&viewCustomizeToolbar.label;"
accesskey="&viewCustomizeToolbar.accesskey;"/>
</popup>
@@ -244,16 +250,17 @@
onclick="checkForMiddleClick(this, event);"/>
</button>
<image id="lock-icon" onclick="if (event.button == 0) displaySecurityInfo(); event.stopPropagation();"/>
#ifdef MOZ_SAFE_BROWSING
<image id="safebrowsing-urlbar-icon" tooltiptext="&safeb.urlbaricon.tooltip;"
level="safe"
onclick="goDoCommand('safebrowsing-show-warning')" />
#endif
+ <image id="star-icon" onclick="if (event.button == 0) PlacesStarButton.onClick(event);"/>
</hbox>
</textbox>
<stack id="go-button-stack">
<vbox>
<!-- These image segments allow the button to stretch nicely
in larger urlbars. -->
<image id="go-button-top"
class="go-button-background"
--- a/browser/base/content/credits.xhtml
+++ b/browser/base/content/credits.xhtml
@@ -460,32 +460,35 @@
<li>Radiant Core</li>
<li>silverorange</li>
<li>Revver</li>
<li></li>
<li>MozillaZine Community</li>
</ul>
</div>
- <p id="gecko" class="center">&credit.poweredByGecko;</p>
+ <p id="gecko" class="center">&credit.poweredByGecko;®</p>
<p class="footnote">
&brandFullName;™ &license.part0; ©1998-2007 &license.part1;
<a href="" link="about:credits" onclick="visitLink(event);">&license.contrib;</a>,
&license.part2;
<a href="" link="about:license" onclick="visitLink(event);">about:license</a>
&license.part3;</p>
<p class="footnote">
- Mozilla Firefox™ and the Firefox logo are trademarks of the Mozilla
- Foundation. You are not granted rights or licenses to the trademarks
+ Mozilla Firefox® and the Firefox logo are registered trademarks of the
+ Mozilla Foundation. You are not granted rights or licenses to the trademarks
of the Mozilla Foundation or any party, including without limitation the
Firefox name or logo.</p>
<p class="footnote">
+ Gecko® is a registered trademark of Netscape Communications Corporation.</p>
+
+ <p class="footnote">
U.S. GOVERNMENT END USERS. The Software is a “commercial item,”
as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of
“commercial computer software” and “commercial computer software
documentation,” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995).
Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through
227.7202-4 (June 1995), all U.S. Government End Users acquire the
Software with only those rights set forth herein.</p>
--- a/browser/components/feeds/src/FeedWriter.js
+++ b/browser/components/feeds/src/FeedWriter.js
@@ -561,23 +561,23 @@ FeedWriter.prototype = {
/* Bug 351263: Make sure to not steal focus if the "Choose
* Application" item is being selected with the keyboard. We do this
* by ignoring command events while the dropdown is closed (user
* arrowing through the combobox), but handling them while the
* combobox dropdown is open (user pressed enter when an item was
* selected). If we don't show the filepicker here, it will be shown
* when clicking "Subscribe Now".
*/
- if (this._document.getElementById("handlersMenuList")
- .getAttribute("open") == "true") {
- if (!this._chooseClientApp()) {
- // Select the (per-prefs) selected handler if no application was
- // selected
- this._setSelectedHandler();
- }
+ var popupbox = this._document.getElementById("handlersMenuList")
+ .firstChild.boxObject;
+ popupbox.QueryInterface(Components.interfaces.nsIPopupBoxObject);
+ if (popupbox.popupState == "hiding" && !this._chooseClientApp()) {
+ // Select the (per-prefs) selected handler if no application was
+ // selected
+ this._setSelectedHandler();
}
break;
default:
this._setAlwaysUseLabel();
}
}
},
--- a/browser/components/feeds/src/WebContentConverter.js
+++ b/browser/components/feeds/src/WebContentConverter.js
@@ -171,17 +171,16 @@ var WebContentConverterRegistrar = {
return this.stringBundle.formatStringFromName(key, params, params.length);
},
_getString: function WCCR_getString(key) {
return this.stringBundle.GetStringFromName(key);
},
_contentTypes: { },
- _protocols: { },
/**
* Track auto handlers for various content types using a content-type to
* handler map.
*/
_autoHandleContentTypes: { },
/**
@@ -260,23 +259,33 @@ var WebContentConverterRegistrar = {
null, null, null);
}
},
/**
* See nsIWebContentConverterService
*/
removeProtocolHandler:
- function WCCR_removeProtocolHandler(protocol, uri) {
- function notURI(currentURI) {
- return currentURI != uri;
+ function WCCR_removeProtocolHandler(aProtocol, aURITemplate) {
+ var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
+ getService(Ci.nsIExternalProtocolService);
+ var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
+ var handlers = handlerInfo.possibleApplicationHandlers;
+ for (let i = 0; i < handlers.length; i++) {
+ try { // We only want to test web handlers
+ let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
+ if (handler.uriTemplate == aURITemplate) {
+ handlers.removeElementAt(i);
+ var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
+ getService(Ci.nsIHandlerService);
+ hs.store(handlerInfo);
+ return;
+ }
+ } catch (e) { /* it wasn't a web handler */ }
}
-
- if (protocol in this._protocols)
- this._protocols[protocol] = this._protocols[protocol].filter(notURI);
},
/**
* See nsIWebContentConverterService
*/
removeContentHandler:
function WCCR_removeContentHandler(contentType, uri) {
function notURI(serviceInfo) {
@@ -319,23 +328,128 @@ var WebContentConverterRegistrar = {
},
_makeURI: function(aURL, aOriginCharset, aBaseURI) {
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
return ioService.newURI(aURL, aOriginCharset, aBaseURI);
},
+ _checkAndGetURI:
+ function WCCR_checkAndGetURI(aURIString)
+ {
+ try {
+ var uri = this._makeURI(aURIString);
+ } catch (ex) {
+ // not supposed to throw according to spec
+ return;
+ }
+
+ // If the uri doesn't contain '%s', it won't be a good handler
+ if (uri.spec.indexOf("%s") < 0)
+ throw NS_ERROR_DOM_SYNTAX_ERR;
+
+ return uri;
+ },
+
+ /**
+ * Determines if a web handler is already registered.
+ *
+ * @param aProtocol
+ * The scheme of the web handler we are checking for.
+ * @param aURITemplate
+ * The URI template that the handler uses to handle the protocol.
+ * @return true if it is already registered, false otherwise.
+ */
+ _protocolHandlerRegistered:
+ function WCCR_protocolHandlerRegistered(aProtocol, aURITemplate) {
+ var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
+ getService(Ci.nsIExternalProtocolService);
+ var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
+ var handlers = handlerInfo.possibleApplicationHandlers;
+ for (let i = 0; i < handlers.length; i++) {
+ try { // We only want to test web handlers
+ let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
+ if (handler.uriTemplate == aURITemplate)
+ return true;
+ } catch (e) { /* it wasn't a web handler */ }
+ }
+ return false;
+ },
+
/**
* See nsIWebContentHandlerRegistrar
*/
registerProtocolHandler:
- function WCCR_registerProtocolHandler(aProtocol, aURI, aTitle, aContentWindow) {
- // not yet implemented
- return;
+ function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) {
+ LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
+
+ // First, check to make sure this isn't already handled internally (we don't
+ // want to let them take over, say "chrome").
+ var ios = Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService);
+ var handler = ios.getProtocolHandler(aProtocol);
+ if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
+ // This is handled internally, so we don't want them to register
+ // XXX this should be a "security exception" according to spec, but that
+ // isn't defined yet.
+ throw("Permission denied to add " + aURIString + "as a protocol handler");
+ }
+
+ var uri = this._checkAndGetURI(aURIString);
+
+ var buttons, message;
+ if (this._protocolHandlerRegistered(aProtocol, uri.spec))
+ message = this._getFormattedString("protocolHandlerRegistered",
+ [aTitle, aProtocol]);
+ else {
+ // Now Ask the user and provide the proper callback
+ message = this._getFormattedString("addProtocolHandler",
+ [aTitle, uri.host, aProtocol]);
+ var fis = Cc["@mozilla.org/browser/favicon-service;1"].
+ getService(Ci.nsIFaviconService);
+ var notificationIcon = fis.getFaviconLinkForIcon(uri);
+ var notificationValue = "Protocol Registration: " + aProtocol;
+ var addButton = {
+ label: this._getString("addProtocolHandlerAddButton"),
+ accessKey: this._getString("addHandlerAddButtonAccesskey"),
+ protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
+
+ callback:
+ function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) {
+ var protocol = aButtonInfo.protocolInfo.protocol;
+ var uri = aButtonInfo.protocolInfo.uri;
+ var name = aButtonInfo.protocolInfo.name;
+
+ var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
+ createInstance(Ci.nsIWebHandlerApp);
+ handler.name = name;
+ handler.uriTemplate = uri;
+
+ var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
+ getService(Ci.nsIExternalProtocolService);
+ var handlerInfo = eps.getProtocolHandlerInfo(protocol);
+ handlerInfo.possibleApplicationHandlers.appendElement(handler, false);
+
+ var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
+ getService(Ci.nsIHandlerService);
+ hs.store(handlerInfo);
+ }
+ };
+ buttons = [addButton];
+ }
+
+ var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
+ var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
+ var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
+ notificationBox.appendNotification(message,
+ notificationValue,
+ notificationIcon,
+ notificationBox.PRIORITY_INFO_LOW,
+ buttons);
},
/**
* See nsIWebContentHandlerRegistrar
* This is the web front end into the registration system, so a prompt to
* confirm the registration is provided, and the result is saved to
* preferences.
*/
@@ -345,26 +459,17 @@ var WebContentConverterRegistrar = {
// We only support feed types at present.
// XXX this should be a "security exception" according to spec, but that
// isn't defined yet.
var contentType = this._resolveContentType(aContentType);
if (contentType != TYPE_MAYBE_FEED)
return;
- try {
- var uri = this._makeURI(aURIString);
- } catch (ex) {
- // not supposed to throw according to spec
- return;
- }
-
- // If the uri doesn't contain '%s', it won't be a good content handler
- if (uri.spec.indexOf("%s") < 0)
- throw NS_ERROR_DOM_SYNTAX_ERR;
+ var uri = this._checkAndGetURI(aURIString);
// For security reasons we reject non-http(s) urls (see bug Bug 354316),
// we may need to revise this once we support more content types
// XXX this should be a "security exception" according to spec, but that
// isn't defined yet.
if (uri.scheme != "http" && uri.scheme != "https")
throw("Permission denied to add " + uri.spec + "as a content handler");
--- a/browser/components/microsummaries/src/nsMicrosummaryService.js
+++ b/browser/components/microsummaries/src/nsMicrosummaryService.js
@@ -1555,26 +1555,19 @@ MicrosummarySet.prototype = {
// Unlike the "href" attribute, the "href" property contains
// an absolute URI spec, so we use it here to create the URI.
var generatorURI = this._ios.newURI(link.href,
resource.content.characterSet,
null);
- try {
- const securityManager = Cc["@mozilla.org/scriptsecuritymanager;1"].
- getService(Ci.nsIScriptSecurityManager);
- securityManager.checkLoadURI(resource.uri,
- generatorURI,
- Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
- }
- catch(e) {
+ if (!/^https?$/i.test(generatorURI.scheme)) {
LOG("can't load generator " + generatorURI.spec + " from page " +
- resource.uri.spec + ": " + e);
+ resource.uri.spec);
continue;
}
var generator = new MicrosummaryGenerator(generatorURI, null, linkTitle);
var microsummary = new Microsummary(resource.uri, generator);
if (!this.hasItemForMicrosummary(microsummary))
this.AppendElement(microsummary);
}
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -390,22 +390,22 @@ var MigrationWizard = {
// When importing bookmarks, show only bookmarks
if (this._bookmarks)
this._itemsFlags = 32;
this._listItems("migratingItems");
setTimeout(this.onMigratingMigrate, 0, this);
},
-
+
onMigratingMigrate: function (aOuter)
{
aOuter._migrator.migrate(aOuter._itemsFlags, aOuter._autoMigrate, aOuter._selectedProfile);
},
-
+
_listItems: function (aID)
{
var items = document.getElementById(aID);
while (items.hasChildNodes())
items.removeChild(items.firstChild);
var bundle = document.getElementById("bundle");
var brandBundle = document.getElementById("brandBundle");
--- a/browser/components/migration/public/nsIBrowserProfileMigrator.idl
+++ b/browser/components/migration/public/nsIBrowserProfileMigrator.idl
@@ -52,27 +52,27 @@ interface nsIBrowserProfileMigrator : ns
const unsigned short FORMDATA = 0x0008;
const unsigned short PASSWORDS = 0x0010;
const unsigned short BOOKMARKS = 0x0020;
const unsigned short OTHERDATA = 0x0040;
/**
* Copy user profile information to the current active profile.
* @param aItems list of data items to migrate. see above for values.
- * @param aReplace replace or append current data where applicable.
+ * @param aStartup helper interface which is non-null if called during startup.
* @param aProfile profile to migrate from, if there is more than one.
*/
void migrate(in unsigned short aItems, in nsIProfileStartup aStartup, in wstring aProfile);
/**
* A bit field containing profile items that this migrator
* offers for import.
* @param aProfile the profile that we are looking for available data
* to import
- * @param aStarting "true" if the profile is not currently being used.
+ * @param aDoingStartup "true" if the profile is not currently being used.
* @returns bit field containing profile items (see above)
*/
unsigned short getMigrateData(in wstring aProfile, in boolean aDoingStartup);
/**
* Whether or not there is any data that can be imported from this
* browser (i.e. whether or not it is installed, and there exists
* a user profile)
--- a/browser/components/migration/src/nsIEProfileMigrator.cpp
+++ b/browser/components/migration/src/nsIEProfileMigrator.cpp
@@ -497,30 +497,40 @@ nsIEProfileMigrator::GetSourceHomePageUR
aResult.Assign(homePageURL);
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// nsIEProfileMigrator
-NS_IMPL_ISUPPORTS1(nsIEProfileMigrator, nsIBrowserProfileMigrator);
+NS_IMPL_ISUPPORTS2(nsIEProfileMigrator, nsIBrowserProfileMigrator, nsINavHistoryBatchCallback);
nsIEProfileMigrator::nsIEProfileMigrator()
{
mObserverService = do_GetService("@mozilla.org/observer-service;1");
}
nsIEProfileMigrator::~nsIEProfileMigrator()
{
}
nsresult
nsIEProfileMigrator::CopyHistory(PRBool aReplace)
{
+ nsresult rv;
+ nsCOMPtr<nsINavHistoryService> history = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return history->RunInBatchMode(this, nsnull);
+}
+
+NS_IMETHODIMP
+nsIEProfileMigrator::RunBatched(nsISupports* aUserData)
+{
nsCOMPtr<nsIBrowserHistory> hist(do_GetService(NS_GLOBALHISTORY2_CONTRACTID));
nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID));
// First, Migrate standard IE History entries...
::CoInitialize(NULL);
IUrlHistoryStg2* ieHistory;
HRESULT hr = ::CoCreateInstance(CLSID_CUrlHistory,
--- a/browser/components/migration/src/nsIEProfileMigrator.h
+++ b/browser/components/migration/src/nsIEProfileMigrator.h
@@ -41,29 +41,32 @@
#ifndef ieprofilemigrator___h___
#define ieprofilemigrator___h___
#include <time.h>
#include <windows.h>
#include "nsIBrowserProfileMigrator.h"
#include "nsIObserverService.h"
#include "nsVoidArray.h"
+#include "nsINavHistoryService.h"
class nsIFile;
class nsICookieManager2;
class nsIRDFResource;
class nsINavBookmarksService;
class nsIPrefBranch;
#import PSTOREC_DLL raw_interfaces_only
using namespace PSTORECLib;
-class nsIEProfileMigrator : public nsIBrowserProfileMigrator {
+class nsIEProfileMigrator : public nsIBrowserProfileMigrator,
+ public nsINavHistoryBatchCallback {
public:
NS_DECL_NSIBROWSERPROFILEMIGRATOR
+ NS_DECL_NSINAVHISTORYBATCHCALLBACK
NS_DECL_ISUPPORTS
nsIEProfileMigrator();
virtual ~nsIEProfileMigrator();
protected:
nsresult CopyPreferences(PRBool aReplace);
nsresult CopyStyleSheet(PRBool aReplace);
--- a/browser/components/migration/src/nsSafariProfileMigrator.cpp
+++ b/browser/components/migration/src/nsSafariProfileMigrator.cpp
@@ -828,16 +828,26 @@ nsSafariProfileMigrator::CopyCookies(PRB
::CFRelease(safariCookies);
return NS_OK;
}
nsresult
nsSafariProfileMigrator::CopyHistory(PRBool aReplace)
{
+ nsresult rv;
+ nsCOMPtr<nsINavHistoryService> history = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return history->RunInBatchMode(this, nsnull);
+}
+
+NS_IMETHODIMP
+nsSafariProfileMigrator::RunBatched(nsISupports* aUserData)
+{
nsCOMPtr<nsIProperties> fileLocator(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
nsCOMPtr<nsILocalFile> safariHistoryFile;
fileLocator->Get(NS_MAC_USER_LIB_DIR, NS_GET_IID(nsILocalFile),
getter_AddRefs(safariHistoryFile));
safariHistoryFile->Append(NS_LITERAL_STRING("Safari"));
safariHistoryFile->Append(SAFARI_HISTORY_FILE_NAME);
CFDictionaryRef safariHistory = (CFDictionaryRef)CopyPListFromFile(safariHistoryFile);
--- a/browser/components/migration/src/nsSafariProfileMigrator.h
+++ b/browser/components/migration/src/nsSafariProfileMigrator.h
@@ -38,25 +38,28 @@
#ifndef safariprofilemigrator___h___
#define safariprofilemigrator___h___
#include "nsIBrowserProfileMigrator.h"
#include "nsIObserverService.h"
#include "nsISupportsArray.h"
#include "nsStringAPI.h"
+#include "nsINavHistoryService.h"
#include <CoreFoundation/CoreFoundation.h>
class nsIRDFDataSource;
-class nsSafariProfileMigrator : public nsIBrowserProfileMigrator
+class nsSafariProfileMigrator : public nsIBrowserProfileMigrator,
+ public nsINavHistoryBatchCallback
{
public:
NS_DECL_NSIBROWSERPROFILEMIGRATOR
+ NS_DECL_NSINAVHISTORYBATCHCALLBACK
NS_DECL_ISUPPORTS
nsSafariProfileMigrator();
virtual ~nsSafariProfileMigrator();
typedef enum { STRING, INT, BOOL } PrefType;
typedef nsresult(*prefConverter)(void*, nsIPrefBranch*);
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -569,22 +569,19 @@ var BookmarkPropertiesPanel = {
}
var itemToSelect = userEnteredNameField;
try {
this._microsummaries = this._mss.getMicrosummaries(this._bookmarkURI,
this._bookmarkId);
}
catch(ex) {
- // getMicrosummaries will throw an exception in at least two cases:
- // 1. the bookmarked URI contains a scheme that the service won't
- // download for security reasons (currently it only handles http,
- // https, and file);
- // 2. the page to which the URI refers isn't HTML or XML (the only two
- // content types the service knows how to summarize).
+ // getMicrosummaries will throw an exception if the page to which the URI
+ // refers isn't HTML or XML (the only two content types the service knows
+ // how to summarize).
this._microsummaries = null;
}
if (this._microsummaries) {
var enumerator = this._microsummaries.Enumerate();
if (enumerator.hasMoreElements()) {
// Show the drop marker if there are microsummaries
namePicker.setAttribute("droppable", "true");
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -99,17 +99,17 @@ PlacesController.prototype = {
case "cmd_cut":
case "cmd_delete":
return this._hasRemovableSelection(false);
case "placesCmd_moveBookmarks":
return this._hasRemovableSelection(true);
case "cmd_copy":
return this._view.hasSelection;
case "cmd_paste":
- return this._canInsert() && this._canPaste();
+ return this._canInsert() && this._isClipboardDataPasteable();
case "cmd_selectAll":
if (this._view.selType != "single") {
var result = this._view.getResult();
if (result) {
var container = asContainer(result.root);
if (container.childCount > 0);
return true;
}
@@ -376,77 +376,73 @@ PlacesController.prototype = {
var root = this._view.getResultNode();
for (var i = 0; i < nodes.length; ++i) {
if (nodes[i] == root)
return true;
}
}
return false;
},
-
+
/**
* Looks at the data on the clipboard to see if it is paste-able.
* Paste-able data is:
* - in a format that the view can receive
- * @returns true if the data is paste-able, false if the clipboard data
- * cannot be pasted
+ * @returns true if: - clipboard data is of a TYPE_X_MOZ_PLACE_* flavor,
+ - clipboard data is of type TEXT_UNICODE and
+ is a valid URI.
*/
- _canPaste: function PC__canPaste() {
- var types = this._view.peerDropTypes;
- var flavors =
- Cc["@mozilla.org/supports-array;1"].
- createInstance(Ci.nsISupportsArray);
- for (var i = 0; i < types.length; ++i) {
- var cstring =
- Cc["@mozilla.org/supports-cstring;1"].
- createInstance(Ci.nsISupportsCString);
- cstring.data = types[i];
+ _isClipboardDataPasteable: function PC__isClipboardDataPasteable() {
+ // if the clipboard contains TYPE_X_MOZ_PLACE_* data, it is definitely
+ // pasteable, with no need to unwrap all the nodes.
+
+ var placeTypes = [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
+ PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR,
+ PlacesUtils.TYPE_X_MOZ_PLACE];
+ var flavors = Cc["@mozilla.org/supports-array;1"].
+ createInstance(Ci.nsISupportsArray);
+ for (var i = 0; i < placeTypes.length; ++i) {
+ var cstring = Cc["@mozilla.org/supports-cstring;1"].
+ createInstance(Ci.nsISupportsCString);
+ cstring.data = placeTypes[i];
flavors.AppendElement(cstring);
}
-
- var clipboard =
- Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
- var hasClipboardData = clipboard.hasDataMatchingFlavors(flavors,
+ var clipboard = Cc["@mozilla.org/widget/clipboard;1"].
+ getService(Ci.nsIClipboard);
+ var hasPlacesData = clipboard.hasDataMatchingFlavors(flavors,
Ci.nsIClipboard.kGlobalClipboard);
- if (!hasClipboardData)
- return false;
+ if (hasPlacesData)
+ return this._view.insertionPoint != null;
+
+ // if the clipboard doesn't have TYPE_X_MOZ_PLACE_* data, we also allow
+ // pasting of valid "text/unicode" and "text/x-moz-url" data
+ var xferable = Cc["@mozilla.org/widget/transferable;1"].
+ createInstance(Ci.nsITransferable);
- // XXX todo
- // see bug #387007 for an idea on how to make this more efficient
- // right now, we are pulling data off the clipboard and using
- // unwrapNodes() to verify it.
-
- var xferable =
- Cc["@mozilla.org/widget/transferable;1"].
- createInstance(Ci.nsITransferable);
-
- for (var j = 0; j < types.length; ++j) {
- xferable.addDataFlavor(types[j]);
- }
+ xferable.addDataFlavor(PlacesUtils.TYPE_X_MOZ_URL);
+ xferable.addDataFlavor(PlacesUtils.TYPE_UNICODE);
clipboard.getData(xferable, Ci.nsIClipboard.kGlobalClipboard);
-
+
try {
- // getAnyTransferData can throw if no data is available.
+ // getAnyTransferData will throw if no data is available.
var data = { }, type = { };
xferable.getAnyTransferData(type, data, { });
data = data.value.QueryInterface(Ci.nsISupportsString).data;
- if (this._view.peerDropTypes.indexOf(type.value) == -1)
+ if (type.value != PlacesUtils.TYPE_X_MOZ_URL &&
+ type.value != PlacesUtils.TYPE_UNICODE)
return false;
- // unwrapNodes() will throw if the data blob is malformed.
+ // unwrapNodes() will throw if the data blob is malformed.
var unwrappedNodes = PlacesUtils.unwrapNodes(data, type.value);
return this._view.insertionPoint != null;
}
catch (e) {
- // unwrapeNodes() failed, possibly because a field that should have
- // contained a URI did not actually contain something that is
- // parse-able as a URI.
+ // getAnyTransferData or unwrapNodes failed
return false;
}
- return false;
},
/**
* Gathers information about the selected nodes according to the following
* rules:
* "link" node is a URI
* "bookmark" node is a bookamrk
* "folder" node is a folder
new file mode 100644
--- /dev/null
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -0,0 +1,581 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Places Bookmark Properties dialog.
+ *
+ * The Initial Developer of the Original Code is Google Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Asaf Romano <mano@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const LAST_USED_ANNO = "bookmarkPropertiesDialog/lastUsed";
+const MAX_FOLDER_ITEM_IN_MENU_LIST = 5;
+
+var gAddBookmarksPanel = {
+ /**
+ * The Microsummary Service for displaying microsummaries.
+ */
+ __mss: null,
+ get _mss() {
+ if (!this.__mss)
+ this.__mss = Cc["@mozilla.org/microsummary/service;1"].
+ getService(Ci.nsIMicrosummaryService);
+ return this.__mss;
+ },
+
+ _uri: null,
+ _itemId: -1,
+ _itemType: -1,
+ _microsummaries: null,
+ _doneCallback: null,
+ _currentTags: [],
+ _hiddenRows: [],
+
+ /**
+ * Determines the initial data for the item edited or added by this dialog
+ */
+ _determineInfo: function ABP__determineInfo(aInfo) {
+ const bms = PlacesUtils.bookmarks;
+ this._itemType = bms.getItemType(this._itemId);
+ if (this._itemType == Ci.nsINavBookmarksService.TYPE_BOOKMARK)
+ this._currentTags = PlacesUtils.tagging.getTagsForURI(this._uri);
+ else
+ this._currentTags.splice(0);
+
+ // hidden rows
+ if (aInfo && aInfo.hiddenRows)
+ this._hiddenRows = aInfo.hiddenRows;
+ else
+ this._hiddenRows.splice(0);
+ },
+
+ _showHideRows: function EBP__showHideRows() {
+ this._element("nameRow").hidden = this._hiddenRows.indexOf("name") != -1;
+ this._element("folderRow").hidden =
+ this._hiddenRows.indexOf("folderPicker") != -1;
+ this._element("tagsRow").hidden = this._hiddenRows.indexOf("tags") != -1 ||
+ this._itemType != Ci.nsINavBookmarksService.TYPE_BOOKMARK;
+ this._element("descriptionRow").hidden =
+ this._hiddenRows.indexOf("description") != -1;
+ },
+
+ /**
+ * Initialize the panel
+ */
+ initPanel: function ABP_initPanel(aItemId, aTm, aDoneCallback, aInfo) {
+ this._folderMenuList = this._element("folderMenuList");
+ this._folderTree = this._element("folderTree");
+ this._tm = aTm;
+ this._itemId = aItemId;
+ this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
+ this._doneCallback = aDoneCallback;
+ this._determineInfo(aInfo);
+
+ // folder picker
+ this._initFolderMenuList();
+
+ // name picker
+ this._initNamePicker();
+
+ // tags field
+ this._element("tagsField").value = this._currentTags.join(", ");
+
+ // description field
+ this._element("descriptionField").value =
+ PlacesUtils.getItemDescription(this._itemId);
+
+ this._showHideRows();
+ },
+
+ /**
+ * Appends a menu-item representing a bookmarks folder to a menu-popup.
+ * @param aMenupopup
+ * The popup to which the menu-item should be added.
+ * @param aFolderId
+ * The identifier of the bookmarks folder.
+ * @return the new menu item.
+ */
+ _appendFolderItemToMenupopup:
+ function BPP__appendFolderItemToMenuList(aMenupopup, aFolderId) {
+ // First make sure the folders-separator is visible
+ this._element("foldersSeparator").hidden = false;
+
+ var folderMenuItem = document.createElement("menuitem");
+ var folderTitle = PlacesUtils.bookmarks.getItemTitle(aFolderId)
+ folderMenuItem.folderId = aFolderId;
+ folderMenuItem.setAttribute("label", folderTitle);
+ folderMenuItem.className = "menuitem-iconic folder-icon";
+ aMenupopup.appendChild(folderMenuItem);
+ return folderMenuItem;
+ },
+
+ _initFolderMenuList: function BPP__initFolderMenuList() {
+ // clean up first
+ var menupopup = this._folderMenuList.menupopup;
+ while (menupopup.childNodes.length > 4)
+ menupopup.removeChild(menupopup.lastChild);
+
+ var container = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId);
+
+ // only show "All Bookmarks" if the url isn't bookmarked somewhere else
+ this._element("placesRootItem").hidden = container != PlacesUtils.placesRootId;
+
+ // List of recently used folders:
+ var annos = PlacesUtils.annotations;
+ var folderIds = annos.getItemsWithAnnotation(LAST_USED_ANNO, { });
+
+ /**
+ * The value of the LAST_USED_ANNO annotation is the time (in the form of
+ * Date.getTime) at which the folder has been last used.
+ *
+ * First we build the annotated folders array, each item has both the
+ * folder identifier and the time at which it was last-used by this dialog
+ * set. Then we sort it descendingly based on the time field.
+ */
+ var folders = [];
+ for (var i=0; i < folderIds.length; i++) {
+ var lastUsed = annos.getItemAnnotation(folderIds[i], LAST_USED_ANNO);
+ folders.push({ folderId: folderIds[i], lastUsed: lastUsed });
+ }
+ folders.sort(function(a, b) {
+ if (b.lastUsed < a.lastUsed)
+ return -1;
+ if (b.lastUsed > a.lastUsed)
+ return 1;
+ return 0;
+ });
+
+ var numberOfItems = Math.min(MAX_FOLDER_ITEM_IN_MENU_LIST, folders.length);
+ for (i=0; i < numberOfItems; i++) {
+ this._appendFolderItemToMenupopup(menupopup, folders[i].folderId);
+ }
+
+ var defaultItem = this._getFolderMenuItem(container, true);
+ this._folderMenuList.selectedItem = defaultItem;
+
+ // Hide the folders-separator if no folder is annotated as recently-used
+ this._element("foldersSeparator").hidden = (menupopup.childNodes.length <= 4);
+ },
+
+ QueryInterface: function BPP_QueryInterface(aIID) {
+ if (aIID.equals(Ci.nsIMicrosummaryObserver) ||
+ aIID.equals(Ci.nsIDOMEventListener) ||
+ aIID.eqauls(Ci.nsISupports))
+ return this;
+
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ },
+
+ _element: function BPP__element(aID) {
+ return document.getElementById("editBMPanel_" + aID);
+ },
+
+ _createMicrosummaryMenuItem:
+ function BPP__createMicrosummaryMenuItem(aMicrosummary) {
+ var menuItem = document.createElement("menuitem");
+
+ // Store a reference to the microsummary in the menu item, so we know
+ // which microsummary this menu item represents when it's time to
+ // save changes or load its content.
+ menuItem.microsummary = aMicrosummary;
+
+ // Content may have to be generated asynchronously; we don't necessarily
+ // have it now. If we do, great; otherwise, fall back to the generator
+ // name, then the URI, and we trigger a microsummary content update. Once
+ // the update completes, the microsummary will notify our observer to
+ // update the corresponding menu-item.
+ // XXX Instead of just showing the generator name or (heaven forbid)
+ // its URI when we don't have content, we should tell the user that
+ // we're loading the microsummary, perhaps with some throbbing to let
+ // her know it is in progress.
+ if (aMicrosummary.content)
+ menuItem.setAttribute("label", aMicrosummary.content);
+ else {
+ menuItem.setAttribute("label", aMicrosummary.generator.name ||
+ aMicrosummary.generator.uri.spec);
+ aMicrosummary.update();
+ }
+
+ return menuItem;
+ },
+
+ _initNamePicker: function ABP_initNamePicker() {
+ var userEnteredNameField = this._element("userEnteredName");
+ var namePicker = this._element("namePicker");
+ var droppable = false;
+
+ userEnteredNameField.label =
+ PlacesUtils.bookmarks.getItemTitle(this._itemId);
+
+ // clean up old entries
+ var menupopup = namePicker.menupopup;
+ while (menupopup.childNodes.length > 2)
+ menupopup.removeChild(menupopup.lastChild);
+
+ var itemToSelect = userEnteredNameField;
+ try {
+ this._microsummaries = this._mss.getMicrosummaries(this._uri, -1);
+ }
+ catch(ex) {
+ // getMicrosummaries will throw an exception in at least two cases:
+ // 1. the bookmarked URI contains a scheme that the service won't
+ // download for security reasons (currently it only handles http,
+ // https, and file);
+ // 2. the page to which the URI refers isn't HTML or XML (the only two
+ // content types the service knows how to summarize).
+ this._microsummaries = null;
+ }
+ if (this._microsummaries) {
+ var enumerator = this._microsummaries.Enumerate();
+
+ if (enumerator.hasMoreElements()) {
+ // Show the drop marker if there are microsummaries
+ droppable = true;
+ while (enumerator.hasMoreElements()) {
+ var microsummary = enumerator.getNext()
+ .QueryInterface(Ci.nsIMicrosummary);
+ var menuItem = this._createMicrosummaryMenuItem(microsummary);
+ menupopup.appendChild(menuItem);
+ }
+ }
+
+ this._microsummaries.addObserver(this);
+ }
+
+ if (namePicker.selectedItem == itemToSelect)
+ namePicker.value = itemToSelect.label;
+ else
+ namePicker.selectedItem = itemToSelect;
+
+ namePicker.setAttribute("droppable", droppable);
+ },
+
+ // nsIMicrosummaryObserver
+ onContentLoaded: function ABP_onContentLoaded(aMicrosummary) {
+ var namePicker = this._element("namePicker");
+ var childNodes = namePicker.menupopup.childNodes;
+
+ // 0: user-entered item; 1: separator
+ for (var i = 2; i < childNodes.length; i++) {
+ if (childNodes[i].microsummary == aMicrosummary) {
+ var newLabel = aMicrosummary.content;
+ // XXXmano: non-editable menulist would do this for us, see bug 360220
+ // We should fix editable-menulists to set the DOMAttrModified handler
+ // as well.
+ //
+ // Also note the order importance: if the label of the menu-item is
+ // set to something different than the menulist's current value,
+ // the menulist no longer has selectedItem set
+ if (namePicker.selectedItem == childNodes[i])
+ namePicker.value = newLabel;
+
+ childNodes[i].label = newLabel;
+ return;
+ }
+ }
+ },
+
+ onElementAppended: function BPP_onElementAppended(aMicrosummary) {
+ var namePicker = this._element("namePicker");
+ namePicker.menupopup
+ .appendChild(this._createMicrosummaryMenuItem(aMicrosummary));
+
+ // Make sure the drop-marker is shown
+ namePicker.setAttribute("droppable", "true");
+ },
+
+ uninitPanel: function ABP_uninitPanel() {
+ if (this._microsummaries)
+ this._microsummaries.removeObserver(this);
+
+ // hide the folder tree if it was previously visible
+ if (!this._folderTree.collapsed)
+ this.toggleFolderTreeVisibility();
+
+ // hide the tag selector if it was previously visible
+ var tagsSelector = this._element("tagsSelector");
+ if (!tagsSelector.collapsed)
+ tagsSelector.collapsed = true;
+ },
+
+ saveItem: function ABP_saveItem() {
+ var container = this._getFolderIdFromMenuList();
+ const bms = PlacesUtils.bookmarks;
+ const ptm = PlacesUtils.ptm;
+ var txns = [];
+
+ // container
+ if (bms.getFolderIdForItem(this._itemId) != container)
+ txns.push(ptm.moveItem(this._itemId, container, -1));
+
+ // title
+ var newTitle = this._element("userEnteredName").label;
+ if (bms.getItemTitle(this._itemId) != newTitle)
+ txns.push(ptm.editItemTitle(this._itemId, newTitle));
+
+ // description
+ var newDescription = this._element("descriptionField").value;
+ if (newDescription != PlacesUtils.getItemDescription(this._itemId))
+ txns.push(ptm.editItemDescription(this._itemId, newDescription));
+
+ // Tags, NOT YET UNDOABLE
+ var tags = this._getTagsArrayFromTagField();
+ if (tags.length > 0 || this._currentTags.length > 0) {
+ var tagsToRemove = [];
+ var tagsToAdd = [];
+ var t;
+ for each (t in this._currentTags) {
+ if (tags.indexOf(t) == -1)
+ tagsToRemove.push(t);
+ }
+ for each (t in tags) {
+ if (this._currentTags.indexOf(t) == -1)
+ tagsToAdd.push(t);
+ }
+
+ if (tagsToAdd.length > 0)
+ PlacesUtils.tagging.tagURI(this._uri, tagsToAdd);
+ if (tagsToRemove.length > 0)
+ PlacesUtils.tagging.untagURI(this._uri, tagsToRemove);
+ }
+
+ if (txns.length > 0) {
+ // Mark the containing folder as recently-used if it isn't the
+ // "All Bookmarks" root
+ if (container != PlacesUtils.placesRootId)
+ this._markFolderAsRecentlyUsed(container);
+ }
+
+ if (txns.length > 0)
+ ptm.commitTransaction(ptm.aggregateTransactions("Edit Item", txns));
+ },
+
+ onNamePickerInput: function ABP_onNamePickerInput() {
+ this._element("userEnteredName").label = this._element("namePicker").value;
+ },
+
+ toggleFolderTreeVisibility: function ABP_toggleFolderTreeVisibility() {
+ var expander = this._element("foldersExpander");
+ if (!this._folderTree.collapsed) {
+ expander.className = "expander-down";
+ expander.setAttribute("tooltiptext",
+ expander.getAttribute("tooltiptextdown"));
+ this._folderTree.collapsed = true;
+ }
+ else {
+ expander.className = "expander-up"
+ expander.setAttribute("tooltiptext",
+ expander.getAttribute("tooltiptextup"));
+ if (!this._folderTree.treeBoxObject.view.isContainerOpen(0))
+ this._folderTree.treeBoxObject.view.toggleOpenState(0);
+ this._folderTree.selectFolders([this._getFolderIdFromMenuList()]);
+ this._folderTree.collapsed = false;
+ this._folderTree.focus();
+ }
+ },
+
+ _getFolderIdFromMenuList:
+ function BPP__getFolderIdFromMenuList() {
+ var selectedItem = this._folderMenuList.selectedItem
+ switch (selectedItem.id) {
+ case "editBMPanel_placesRootItem":
+ return PlacesUtils.placesRootId;
+ case "editBMPanel_bmRootItem":
+ return PlacesUtils.bookmarksRootId;
+ case "editBMPanel_toolbarFolderItem":
+ return PlacesUtils.toolbarFolderId;
+ }
+
+ NS_ASSERT("folderId" in selectedItem,
+ "Invalid menuitem in the folders-menulist");
+ return selectedItem.folderId;
+ },
+
+ /**
+ * Get the corresponding menu-item in the folder-menu-list for a bookmarks
+ * folder if such an item exists. Otherwise, this creates a menu-item for the
+ * folder. If the items-count limit (see MAX_FOLDERS_IN_MENU_LIST) is reached,
+ * the new item replaces the last menu-item.
+ * @param aFolderId
+ * The identifier of the bookmarks folder
+ * @param aCheckStaticFolderItems
+ * whether or not to also treat the static items at the top of
+ * menu-list. Note dynamic items get precedence even if this is set to
+ * true.
+ */
+ _getFolderMenuItem:
+ function BPP__getFolderMenuItem(aFolderId, aCheckStaticFolderItems) {
+ var menupopup = this._folderMenuList.menupopup;
+
+ // 0: All Bookmarks, 1: Bookmarks root, 2: toolbar folder, 3: separator
+ for (var i=4; i < menupopup.childNodes.length; i++) {
+ if (menupopup.childNodes[i].folderId == aFolderId)
+ return menupopup.childNodes[i];
+ }
+
+ if (aCheckStaticFolderItems) {
+ if (aFolderId == PlacesUtils.placesRootId)
+ return this._element("placesRootItem");
+ if (aFolderId == PlacesUtils.bookmarksRootId)
+ return this._element("bmRootItem")
+ if (aFolderId == PlacesUtils.toolbarFolderId)
+ return this._element("toolbarFolderItem")
+ }
+
+ // 3 special folders + separator + folder-items-count limit
+ if (menupopup.childNodes.length == 4 + MAX_FOLDER_ITEM_IN_MENU_LIST)
+ menupopup.removeChild(menupopup.lastChild);
+
+ return this._appendFolderItemToMenupopup(menupopup, aFolderId);
+ },
+
+ onMenuListFolderSelect: function BPP_onMenuListFolderSelect(aEvent) {
+ if (this._folderTree.hidden)
+ return;
+
+ this._folderTree.selectFolders([this._getFolderIdFromMenuList()]);
+ },
+
+ onFolderTreeSelect: function BPP_onFolderTreeSelect() {
+ var selectedNode = this._folderTree.selectedNode;
+ if (!selectedNode)
+ return;
+
+ var folderId = selectedNode.itemId;
+ // Don't set the selected item if the static item for the folder is
+ // already selected
+ var oldSelectedItem = this._folderMenuList.selectedItem;
+ if ((oldSelectedItem.id == "editBMPanel_toolbarFolderItem" &&
+ folderId == PlacesUtils.bookmarks.toolbarFolder) ||
+ (oldSelectedItem.id == "editBMPanel_bmRootItem" &&
+ folderId == PlacesUtils.bookmarks.bookmarksRoot))
+ return;
+
+ var folderItem = this._getFolderMenuItem(folderId, false);
+ this._folderMenuList.selectedItem = folderItem;
+ },
+
+ _markFolderAsRecentlyUsed:
+ function ABP__markFolderAsRecentlyUsed(aFolderId) {
+ // We'll figure out when/if to expire the annotation if it turns out
+ // we keep this recently-used-folders implementation
+ PlacesUtils.annotations
+ .setItemAnnotation(aFolderId, LAST_USED_ANNO,
+ new Date().getTime(), 0,
+ Ci.nsIAnnotationService.EXPIRE_NEVER);
+ },
+
+ accept: function ABP_accept() {
+ this.saveItem();
+ if (typeof(this._doneCallback) == "function")
+ this._doneCallback();
+ },
+
+ deleteAndClose: function ABP_deleteAndClose() {
+ // remove the item
+ if (this._itemId != -1)
+ PlacesUtils.bookmarks.removeItem(this._itemId);
+
+ // remove all tags for the associated url
+ PlacesUtils.tagging.untagURI(this._uri, null);
+
+ if (typeof(this._doneCallback) == "function")
+ this._doneCallback();
+ },
+
+ toggleTagsSelector: function ABP_toggleTagsSelector() {
+ var tagsSelector = this._element("tagsSelector");
+ var expander = this._element("tagsSelectorExpander");
+ if (tagsSelector.collapsed) {
+ expander.className = "expander-down";
+ expander.setAttribute("tooltiptext",
+ expander.getAttribute("tooltiptextdown"));
+
+ // rebuild the tag list
+ while (tagsSelector.hasChildNodes())
+ tagsSelector.removeChild(tagsSelector.lastChild);
+
+ var tagsInField = this._getTagsArrayFromTagField();
+ var allTags = PlacesUtils.tagging.allTags;
+ for each (var tag in allTags) {
+ var elt = document.createElement("listitem");
+ elt.setAttribute("type", "checkbox");
+ elt.setAttribute("label", tag);
+ if (tagsInField.indexOf(tag) != -1)
+ elt.setAttribute("checked", "true");
+
+ tagsSelector.appendChild(elt);
+ }
+
+ // This is a no-op if we've added the listener.
+ tagsSelector.addEventListener("CheckboxStateChange", this, false);
+ }
+ else {
+ expander.className = "expander-down";
+ expander.setAttribute("tooltiptext",
+ expander.getAttribute("tooltiptextdown"));
+ }
+
+ tagsSelector.collapsed = !tagsSelector.collapsed;
+ },
+
+ _getTagsArrayFromTagField: function() {
+ // we don't require the leading space (after each comma)
+ var tags = this._element("tagsField").value.split(",");
+ for (var i=0; i < tags.length; i++) {
+ // remove trailing and leading spaces
+ tags[i] = tags[i].replace(/^\s+/, "").replace(/\s+$/, "");
+
+ // remove empty entries from the array.
+ if (tags[i] == "") {
+ tags.splice(i, 1);
+ i--;
+ }
+ }
+ return tags;
+ },
+
+ // nsIDOMEventListener
+ handleEvent: function ABP_nsIDOMEventListener(aEvent) {
+ if (aEvent.type == "CheckboxStateChange") {
+ // Update the tags field when items are checked/unchecked in the listbox
+ var tags = this._getTagsArrayFromTagField();
+
+ if (aEvent.target.checked)
+ tags.push(aEvent.target.label);
+ else {
+ var indexOfItem = tags.indexOf(aEvent.target.label);
+ if (indexOfItem != -1)
+ tags.splice(indexOfItem, 1);
+ }
+ this._element("tagsField").value = tags.join(", ");
+ }
+ }
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/places/content/editBookmarkOverlay.xul
@@ -0,0 +1,150 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Places Edit Bookmarks Panel code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2007
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Asaf Romano <mano@mozilla.com> (Original Author)
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+<!DOCTYPE overlay [
+<!ENTITY % placesDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
+%placesDTD;
+]>
+
+<?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
+
+<overlay id="editBookmarkOverlay"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://browser/content/places/editBookmarkOverlay.js"/>
+
+ <vbox id="editBookmarkPanelContent">
+ <grid id="editBookmarkPanelGrid" flex="1">
+ <columns>
+ <column/>
+ <column flex="1"/>
+ </columns>
+ <rows>
+ <row align="center" id="editBMPanel_nameRow">
+ <label value="&editBookmarkOverlay.name.label;"
+ contorl="editBMPanel_namePicker"/>
+ <menulist id="editBMPanel_namePicker"
+ flex="1"
+ editable="true"
+ droppable="false"
+ oninput="gAddBookmarksPanel.onNamePickerInput();">
+ <menupopup>
+ <menuitem id="editBMPanel_userEnteredName"/>
+ <menuitem disabled="true">
+ <menuseparator flex="1"/>
+ <label value="&editBookmarkOverlay.liveTitlesSeparator.label;"/>
+ </menuitem>
+ </menupopup>
+ </menulist>
+ </row>
+ <row align="center" id="editBMPanel_folderRow">
+ <label value="&editBookmarkOverlay.folder.label;"
+ control="editBMPanel_folderMenuList"/>
+ <menulist id="editBMPanel_folderMenuList"
+ class="folder-icon"
+ oncommand="gAddBookmarksPanel.onMenuListFolderSelect();">
+ <menupopup>
+ <!-- Static item for special folders -->
+ <menuitem id="editBMPanel_placesRootItem"
+ label="&editBookmarkOverlay.allBookmarksFolderItem.label;"
+ class="menuitem-iconic folder-icon"/>
+ <menuitem id="editBMPanel_bmRootItem"
+ label="&editBookmarkOverlay.bookmarksMenuFolderItem.label;"
+ class="menuitem-iconic folder-icon"/>
+ <menuitem id="editBMPanel_toolbarFolderItem"
+ label="&editBookmarkOverlay.toolbarFolderItem.label;"
+ class="menuitem-iconic folder-icon"/>
+ <menuseparator id="editBMPanel_foldersSeparator" hidden="true"/>
+ </menupopup>
+ </menulist>
+ <button id="editBMPanel_foldersExpander"
+ class="expander-down"
+ tooltiptext="&editBookmarkOverlay.foldersExpanderDown.tooltip;"
+ tooltiptextdown="&editBookmarkOverlay.foldersExpanderDown.tooltip;"
+ tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
+ oncommand="gAddBookmarksPanel.toggleFolderTreeVisibility();"/>
+ </row>
+ <tree id="editBMPanel_folderTree"
+ class="placesTree"
+ type="places"
+ height="150"
+ collapsed="true"
+ onselect="gAddBookmarksPanel.onFolderTreeSelect();"
+ showRoot="true"
+ place="place:folder=2&group=3&excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1"
+ hidecolumnpicker="true">
+ <treecols>
+ <treecol anonid="title" flex="1" primary="true" hideheader="true"/>
+ </treecols>
+ <treechildren flex="1"/>
+ </tree>
+ <row align="center" id="editBMPanel_tagsRow">
+ <label value="&editBookmarkOverlay.tags.label;"
+ control="tagsField"/>
+ <textbox id="editBMPanel_tagsField"/>
+ <button id="editBMPanel_tagsSelectorExpander"
+ class="expander-down"
+ tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
+ tooltiptextdown="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
+ tooltiptextup="&editBookmarkOverlay.expanderUp.tooltip;"
+ oncommand="gAddBookmarksPanel.toggleTagsSelector();"/>
+ </row>
+
+ <!-- XXX: Temporary workaround -->
+ </rows></grid>
+ <listbox id="editBMPanel_tagsSelector" height="150" collapsed="true"/>
+ <grid flex="1"><columns><column/><column flex="1"/></columns><rows>
+
+ <row id="editBMPanel_descriptionRow" align="center">
+ <label value="&editBookmarkOverlay.description.label;"
+ control="editBMPanel_descriptionField"/>
+ <textbox id="editBMPanel_descriptionField"/>
+ </row>
+ </rows>
+ </grid>
+
+ <hbox>
+ <spacer flex="1"/>
+ <button label="&editBookmarkOverlay.delete.label;"
+ oncommand="gAddBookmarksPanel.deleteAndClose();"/>
+ <button label="&editBookmarkOverlay.ok.label;"
+ default="true"
+ oncommand="gAddBookmarksPanel.accept();"/>
+ </hbox>
+ </vbox>
+</overlay>
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -422,17 +422,18 @@ PlacesTreeView.prototype = {
COLUMN_TYPE_DATE: 3,
COLUMN_TYPE_VISITCOUNT: 4,
COLUMN_TYPE_KEYWORD: 5,
COLUMN_TYPE_DESCRIPTION: 6,
COLUMN_TYPE_DATEADDED: 7,
COLUMN_TYPE_LASTMODIFIED: 8,
_getColumnType: function PTV__getColumnType(aColumn) {
- switch (aColumn.id) {
+ var columnType = aColumn.id || aColumn.element.getAttribute("anonid");
+ switch (columnType) {
case "title":
return this.COLUMN_TYPE_TITLE;
case "url":
return this.COLUMN_TYPE_URI;
case "date":
return this.COLUMN_TYPE_DATE;
case "visitCount":
return this.COLUMN_TYPE_VISITCOUNT;
@@ -871,17 +872,18 @@ PlacesTreeView.prototype = {
break;
case this.SESSION_STATUS_CONTINUE:
aProperties.AppendElement(this._sessionContinueAtom);
break
}
},
getCellProperties: function PTV_getCellProperties(aRow, aColumn, aProperties) {
- if (aColumn.id != "title")
+ var columnType = aColumn.id || aColumn.element.getAttribute("anonid") ;
+ if (columnType != "title")
return;
this._ensureValidRow(aRow);
var node = this._visibleElements[aRow];
if (PlacesUtils.nodeIsSeparator(node))
aProperties.AppendElement(this._separatorAtom);
},
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -154,16 +154,26 @@ var PlacesUtils = {
_microsummaries: null,
get microsummaries() {
if (!this._microsummaries)
this._microsummaries = Cc["@mozilla.org/microsummary/service;1"].
getService(Ci.nsIMicrosummaryService);
return this._microsummaries;
},
+ /**
+ * The Places Tagging Service
+ */
+ get tagging() {
+ if (!this._tagging)
+ this._tagging = Cc["@mozilla.org/browser/tagging-service;1"].
+ getService(Ci.nsITaggingService);
+ return this._tagging;
+ },
+
_RDF: null,
get RDF() {
if (!this._RDF)
this._RDF = Cc["@mozilla.org/rdf/rdf-service;1"].
getService(Ci.nsIRDFService);
return this._RDF;
},
@@ -1344,48 +1354,52 @@ var PlacesUtils = {
* @param aAnnotations
* Array of objects, each containing the following properties:
* name, flags, expires, type, mimeType (only used for binary
* annotations) value.
*/
setAnnotationsForURI: function PU_setAnnotationsForURI(aURI, aAnnos) {
var annosvc = this.annotations;
aAnnos.forEach(function(anno) {
+ var flags = ("flags" in anno) ? anno.flags : 0;
+ var expires = ("expires" in anno) ?
+ anno.expires : Ci.nsIAnnotationService.EXPIRE_NEVER;
if (anno.type == annosvc.TYPE_BINARY) {
annosvc.setPageAnnotationBinary(aURI, anno.name, anno.value,
anno.value.length, anno.mimeType,
- anno.flags, anno.expires);
+ flags, expires);
}
- else {
- annosvc.setPageAnnotation(aURI, anno.name, anno.value,
- anno.flags, anno.expires);
- }
+ else
+ annosvc.setPageAnnotation(aURI, anno.name, anno.value, flags, expires);
});
},
/**
* Annotate an item with a batch of annotations.
* @param aItemId
* The identifier of the item for which annotations are to be set
* @param aAnnotations
* Array of objects, each containing the following properties:
* name, flags, expires, type, mimeType (only used for binary
* annotations) value.
*/
setAnnotationsForItem: function PU_setAnnotationsForItem(aItemId, aAnnos) {
var annosvc = this.annotations;
aAnnos.forEach(function(anno) {
+ var flags = ("flags" in anno) ? anno.flags : 0;
+ var expires = ("expires" in anno) ?
+ anno.expires : Ci.nsIAnnotationService.EXPIRE_NEVER;
if (anno.type == annosvc.TYPE_BINARY) {
annosvc.setItemAnnotationBinary(aItemId, anno.name, anno.value,
anno.value.length, anno.mimeType,
- anno.flags, anno.expires);
+ flags, expires);
}
else {
- annosvc.setItemAnnotation(aItemId, anno.name, anno.value,
- anno.flags, anno.expires);
+ annosvc.setItemAnnotation(aItemId, anno.name, anno.value, flags,
+ expires);
}
});
},
/**
* Helper for getting a serialized Places query for a particular folder.
* @param aFolderId The folder id to get a query for.
* @return string serialized place URI
@@ -1434,16 +1448,23 @@ var PlacesUtils = {
get toolbarFolderId() {
if (!("_toolbarFolderId" in this))
this._toolbarFolderId = this.bookmarks.toolbarFolder;
return this._toolbarFolderId;
},
+ get tagRootId() {
+ if (!("_tagRootId" in this))
+ this._tagRootId = this.bookmarks.tagRoot;
+
+ return this._tagRootId;
+ },
+
/**
* Set the POST data associated with a URI, if any.
* Used by POST keywords.
* @param aURI
* @returns string of POST data
*/
setPostDataForURI: function PU_setPostDataForURI(aURI, aPostData) {
const annos = this.annotations;
@@ -1462,16 +1483,29 @@ var PlacesUtils = {
const annos = this.annotations;
if (annos.pageHasAnnotation(aURI, POST_DATA_ANNO))
return annos.getPageAnnotation(aURI, POST_DATA_ANNO);
return null;
},
/**
+ * Retrieve the description of an item
+ * @param aItemId
+ * item identifier
+ * @returns the description of the given item, or an empty string if it is
+ * not set.
+ */
+ getItemDescription: function PU_getItemDescription(aItemId) {
+ if (this.annotations.itemHasAnnotation(aItemId, DESCRIPTION_ANNO))
+ return this.annotations.getItemAnnotation(aItemId, DESCRIPTION_ANNO);
+ return "";
+ },
+
+ /**
* Converts a JavaScript object into a JSON string
* (see http://www.json.org/ for the full grammar).
*
* The inverse operation consists of eval("(" + JSON_string + ")");
* and should be provably safe.
*
* @param aJSObject is the object to be converted
* @return the object's JSON representation
--- a/browser/components/places/jar.mn
+++ b/browser/components/places/jar.mn
@@ -26,8 +26,10 @@ browser.jar:
* content/browser/history/history-panel.xul (content/history-panel.xul)
* content/browser/places/history-panel.js (content/history-panel.js)
# ditto for the bookmarks sidebar
* content/browser/bookmarks/bookmarksPanel.xul (content/bookmarksPanel.xul)
* content/browser/bookmarks/bookmarksPanel.js (content/bookmarksPanel.js)
* content/browser/bookmarks/sidebarUtils.js (content/sidebarUtils.js)
* content/browser/places/moveBookmarks.xul (content/moveBookmarks.xul)
* content/browser/places/moveBookmarks.js (content/moveBookmarks.js)
+* content/browser/places/editBookmarkOverlay.xul (content/editBookmarkOverlay.xul)
+* content/browser/places/editBookmarkOverlay.js (content/editBookmarkOverlay.js)
--- a/browser/components/places/public/nsIPlacesImportExportService.idl
+++ b/browser/components/places/public/nsIPlacesImportExportService.idl
@@ -44,28 +44,27 @@ interface nsILocalFile;
* The PlacesImportExport interface provides methods for importing
* and exporting Places data.
*/
[scriptable, uuid(21c00314-fa63-11db-8314-0800200c9a66)]
interface nsIPlacesImportExportService: nsISupports
{
/**
- * Loads the given bookmarks.html file and merges it with the current
- * bookmarks hierarchy.
+ * Loads the given bookmarks.html file and replaces it with the current
+ * bookmarks hierarchy (if aIsInitialImport is true) or appends it
+ * (if aIsInitialImport is false)
*/
void importHTMLFromFile(in nsILocalFile aFile, in boolean aIsInitialImport);
-
/**
* Loads the given bookmarks.html file and puts it in the given folder
*/
void importHTMLFromFileToFolder(in nsILocalFile aFile, in PRInt64 aFolder, in boolean aIsInitialImport);
-
/**
* Saves the current bookmarks hierarchy to a bookmarks.html file.
*/
void exportHTMLToFile(in nsILocalFile aFile);
/**
* Backup and archive the bookmarks.html file.
*/
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -271,29 +271,29 @@ SessionStartup.prototype = {
// get app name from branding properties
var brandStringBundle = this._getStringBundle("chrome://branding/locale/brand.properties");
var brandShortName = brandStringBundle.GetStringFromName("brandShortName");
// create prompt strings
var ssStringBundle = this._getStringBundle("chrome://browser/locale/sessionstore.properties");
var restoreTitle = ssStringBundle.formatStringFromName("restoredTitle", [brandShortName], 1);
var restoreText = ssStringBundle.formatStringFromName("restoredMsg", [brandShortName], 1);
- var buttonTitle = ssStringBundle.GetStringFromName("buttonTitle");
+ var okTitle = ssStringBundle.GetStringFromName("okTitle");
var cancelTitle = ssStringBundle.GetStringFromName("cancelTitle");
var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
getService(Ci.nsIPromptService);
// set the buttons that will appear on the dialog
var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
promptService.BUTTON_POS_0_DEFAULT;
var buttonChoice = promptService.confirmEx(null, restoreTitle, restoreText,
- flags, buttonTitle, cancelTitle, null,
+ flags, okTitle, cancelTitle, null,
null, {});
recover = (buttonChoice == 0);
}
}
catch (ex) { dump(ex + "\n"); } // if the prompt fails, recover anyway
return recover;
},
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -386,18 +386,16 @@ SessionStoreService.prototype = {
* @param aWindow
* Window reference
*/
onLoad: function sss_onLoad(aWindow) {
// return if window has already been initialized
if (aWindow && aWindow.__SSi && this._windows[aWindow.__SSi])
return;
- var _this = this;
-
// ignore non-browser windows and windows opened while shutting down
if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" ||
this._loadState == STATE_QUITTING)
return;
// assign it a unique identifier (timestamp)
aWindow.__SSi = "window" + Date.now();
@@ -418,17 +416,17 @@ SessionStoreService.prototype = {
// make sure that the restored tabs are first in the window
this._initialState._firstTabs = true;
this.restoreWindow(aWindow, this._initialState, this._isCmdLineEmpty(aWindow));
delete this._initialState;
}
if (this._lastSessionCrashed) {
// restart any interrupted downloads
- aWindow.setTimeout(function(){ _this.retryDownloads(aWindow); }, 0);
+ aWindow.setTimeout(this.retryDownloads, 0);
}
}
var tabbrowser = aWindow.getBrowser();
var tabpanels = tabbrowser.mPanelContainer;
// add tab change listeners to all already existing tabs
for (var i = 0; i < tabpanels.childNodes.length; i++) {
@@ -1621,60 +1619,52 @@ SessionStoreService.prototype = {
cookieManager.add(cookie.host, cookie.path || "", cookie.name || "", cookie.value, !!cookie.secure, !!cookie.httponly, true, "expiry" in cookie ? cookie.expiry : MAX_EXPIRY);
}
catch (ex) { Components.utils.reportError(ex); } // don't let a single cookie stop recovering
}
},
/**
* Restart incomplete downloads
- * @param aWindow
- * Window reference
*/
- retryDownloads: function sss_retryDownloads(aWindow) {
- var downloadManager = Cc["@mozilla.org/download-manager;1"].
- getService(Ci.nsIDownloadManager);
+ retryDownloads: function sss_retryDownloads() {
var ioService = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
-
- var database = downloadManager.DBConnection;
+ var dlManager = Cc["@mozilla.org/download-manager;1"].
+ getService(Ci.nsIDownloadManager);
- var stmt = database.createStatement("SELECT source, target, id " +
- "FROM moz_downloads " +
- "WHERE state = ?1");
+ function AsyncDownloadRetrier(aDlId) {
+ this._dlId = aDlId;
+ this._dlManager = dlManager;
+ }
+ AsyncDownloadRetrier.prototype = {
+ onStartRequest: function(aRequest, aContext) { },
+ onStopRequest: function(aRequest, aContext, aStatus) {
+ if (Components.isSuccessCode(aStatus))
+ this._dlManager.retryDownload(this._dlId);
+ }
+ };
+
+ var stmt = dlManager.DBConnection.
+ createStatement("SELECT id, source " +
+ "FROM moz_downloads " +
+ "WHERE state = ?1");
stmt.bindInt32Parameter(0, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
- var dls = [];
// restart all downloads that were in progress before the crash
+ // and which are currently available through the network
while (stmt.executeStep()) {
- // URL being downloaded
- var url = stmt.getUTF8String(0);
+ var dlId = stmt.getInt64(0);
+ var url = stmt.getUTF8String(1);
- var savedTo = stmt.getUTF8String(1);
- var savedToURI = ioService.newURI(savedTo, null, null);
- savedTo = savedToURI.path;
-
- var dl = { id: stmt.getInt64(2), url: url, savedTo: savedTo };
- dls.push(dl);
- }
- stmt.reset();
-
- // We need to remove it from the database otherwise it just sits there
- stmt = database.createStatement("DELETE FROM moz_downloads " +
- "WHERE state = ?1");
- stmt.bindInt32Parameter(0, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
- stmt.execute();
-
- for (var i = dls.length - 1; i >= 0; --i) {
var linkChecker = Cc["@mozilla.org/network/urichecker;1"].
createInstance(Ci.nsIURIChecker);
- linkChecker.init(ioService.newURI(dls[i].url, null, null));
+ linkChecker.init(ioService.newURI(url, null, null));
linkChecker.loadFlags = Ci.nsIRequest.LOAD_BACKGROUND;
- linkChecker.asyncCheck(new AutoDownloader(dls[i].url, dls[i].savedTo, aWindow),
- null);
+ linkChecker.asyncCheck(new AsyncDownloadRetrier(dlId), null);
}
},
/* ........ Disk Access .............. */
/**
* save state delayed by N ms
* marks window as dirty (i.e. data update can't be skipped)
@@ -2044,40 +2034,16 @@ SessionStoreService.prototype = {
Components.returnCode = Cr.NS_ERROR_NO_INTERFACE;
return null;
}
return this;
}
};
-/* :::::::::: Asynchronous File Downloader :::::::::::::: */
-
-function AutoDownloader(aURL, aFilename, aWindow) {
- this._URL = aURL;
- this._filename = aFilename;
- this._window = aWindow;
-}
-
-AutoDownloader.prototype = {
- onStartRequest: function(aRequest, aContext) { },
- onStopRequest: function(aRequest, aContext, aStatus) {
- if (Components.isSuccessCode(aStatus)) {
- var file =
- Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
- file.initWithPath(this._filename);
- if (file.exists()) {
- file.remove(false);
- }
-
- this._window.saveURL(this._URL, this._filename, null, true, true, null);
- }
- }
-};
-
/* :::::::: Service Registration & Initialization ::::::::::::::: */
/* ........ nsIModule .............. */
const SessionStoreModule = {
getClassObject: function(aCompMgr, aCID, aIID) {
if (aCID.equals(CID)) {
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -522,8 +522,9 @@ extensions/talkback@mozilla.org/componen
#else
extensions/talkback@mozilla.org/components/talkback/talkback
extensions/talkback@mozilla.org/components/talkback/XTalkback.ad
extensions/talkback@mozilla.org/components/master.ini
extensions/talkback@mozilla.org/components/talkback.so
#endif
#endif
components/airbag.xpt
+components/nsUrlClassifierTable.js
--- a/browser/installer/unix/packages-static
+++ b/browser/installer/unix/packages-static
@@ -213,16 +213,17 @@ bin/components/nsHelperAppDlg.js
bin/components/nsInterfaceInfoToIDL.js
; bin/components/nsProgressDialog.js not needed for firefox
bin/components/nsProxyAutoConfig.js
; bin/components/nsResetPref.js not needed for firefox
bin/components/nsSidebar.js
; bin/components/nsUpdateNotifier.js not needed for firefox
bin/components/nsXmlRpcClient.js
bin/components/nsExtensionManager.js
+bin/components/nsBlocklistService.js
bin/components/nsUpdateService.js
bin/components/pluginGlue.js
bin/components/extensions.xpt
bin/components/update.xpt
bin/components/nsSessionStartup.js
bin/components/nsSessionStore.js
bin/components/sessionstore.xpt
bin/components/nsURLFormatter.js
@@ -231,26 +232,27 @@ bin/components/libbrowserdirprovider.so
bin/components/libbrowsercomps.so
bin/components/txEXSLTRegExFunctions.js
bin/components/nsLivemarkService.js
bin/components/nsTaggingService.js
bin/components/nsDefaultCLH.js
bin/components/nsContentPrefService.js
bin/components/nsContentDispatchChooser.js
bin/components/nsHandlerService.js
+bin/components/nsScriptableIO.js
+bin/components/nsWebHandlerApp.js
; Modules
bin/modules/*
; Safe Browsing
bin/components/nsSafebrowsingApplication.js
bin/components/safebrowsing.xpt
bin/components/nsUrlClassifierListManager.js
bin/components/nsUrlClassifierLib.js
-bin/components/nsUrlClassifierTable.js
bin/components/url-classifier.xpt
; Kerberos NegotiateAuth
bin/components/libauth.so
; GNOME hooks
bin/components/libmozgnome.so
bin/components/mozgnome.xpt
--- a/browser/installer/windows/packages-static
+++ b/browser/installer/windows/packages-static
@@ -206,16 +206,17 @@ bin\components\nsTryToClose.js
bin\components\nsDictionary.js
bin\components\nsHelperAppDlg.js
bin\components\nsProxyAutoConfig.js
bin\components\nsSearchService.js
bin\components\nsSearchSuggestions.js
bin\components\nsSidebar.js
bin\components\nsXmlRpcClient.js
bin\components\nsExtensionManager.js
+bin\components\nsBlocklistService.js
bin\components\nsUpdateService.js
bin\components\nsMicrosummaryService.js
bin\components\nsPlacesTransactionsService.js
bin\components\nsPostUpdateWin.js
bin\components\nsLoginInfo.js
bin\components\nsLoginManager.js
bin\components\nsLoginManagerPrompter.js
bin\components\storage-Legacy.js
@@ -231,26 +232,27 @@ bin\components\browserdirprovider.dll
bin\components\brwsrcmp.dll
bin\components\txEXSLTRegExFunctions.js
bin\components\nsLivemarkService.js
bin\components\nsTaggingService.js
bin\components\nsDefaultCLH.js
bin\components\nsContentPrefService.js
bin\components\nsContentDispatchChooser.js
bin\components\nsHandlerService.js
+bin\components\nsScriptableIO.js
+bin\components\nsWebHandlerApp.js
; Modules
bin\modules\*
; Safe Browsing
bin\components\nsSafebrowsingApplication.js
bin\components\safebrowsing.xpt
bin\components\nsUrlClassifierListManager.js
bin\components\nsUrlClassifierLib.js
-bin\components\nsUrlClassifierTable.js
bin\components\url-classifier.xpt
; [Browser Chrome Files]
bin\chrome\browser.jar
bin\chrome\browser.manifest
bin\chrome\classic.jar
bin\chrome\classic.manifest
bin\extensions\{972ce4c6-7e08-4474-a285-3208198ce6fd}\install.rdf
--- a/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
+++ b/browser/locales/en-US/chrome/browser/feeds/subscribe.properties
@@ -3,8 +3,15 @@ addHandler=Add "%S" (%S) as a Feed Reade
addHandlerAddButton=Add Feed Reader
addHandlerAddButtonAccesskey=A
handlerRegistered="%S" is already registered as a Feed Reader
liveBookmarks=Live Bookmarks
subscribeNow=Subscribe Now
chooseApplicationMenuItem=Choose Application...
chooseApplicationDialogTitle=Choose Application
alwaysUse=Always use %S to subscribe to feeds
+
+# Protocol Handling
+# "Add %appName (%appDomain) as an application for %protocolType links?"
+addProtocolHandler=Add %S (%S) as an application for %S links?
+addProtocolHandlerAddButton=Add Application
+# "%appName has already been added as an application for %protocolType links."
+protocolHandlerRegistered=%S has already been added as an application for %S links.
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/places/editBookmarkOverlay.dtd
@@ -0,0 +1,13 @@
+<!ENTITY editBookmarkOverlay.name.label "Name:">
+<!ENTITY editBookmarkOverlay.liveTitlesSeparator.label "Live Titles">
+<!ENTITY editBookmarkOverlay.folder.label "Folder:">
+<!ENTITY editBookmarkOverlay.allBookmarksFolderItem.label "All Bookmarks">
+<!ENTITY editBookmarkOverlay.bookmarksMenuFolderItem.label "Bookmarks Menu">
+<!ENTITY editBookmarkOverlay.toolbarFolderItem.label "Bookmarks Toolbar">
+<!ENTITY editBookmarkOverlay.foldersExpanderDown.tooltip "Show all the bookmarks folders">
+<!ENTITY editBookmarkOverlay.expanderUp.tooltip "Hide">
+<!ENTITY editBookmarkOverlay.tags.label "Tags">
+<!ENTITY editBookmarkOverlay.description.label "Description:">
+<!ENTITY editBookmarkOverlay.tagsExpanderDown.tooltip "Show all tags">
+<!ENTITY editBookmarkOverlay.ok.label "OK">
+<!ENTITY editBookmarkOverlay.delete.label "Delete">
--- a/browser/locales/en-US/chrome/browser/sessionstore.properties
+++ b/browser/locales/en-US/chrome/browser/sessionstore.properties
@@ -1,4 +1,7 @@
restoredTitle= %S - Restore Previous Session
restoredMsg=Your last %S session closed unexpectedly. You can restore the tabs and windows from your previous session, or start a new session if you think the problem was related to a page you were viewing.
-buttonTitle=Restore Session
+
+# Localization note: It is recommended that okTitle be longer than cancelTitle
+# so that hitting the more prominent button doesn't lead to dataloss (see bug 346264).
+okTitle=Restore Previous Session
cancelTitle=Start New Session
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -22,16 +22,17 @@
locale/browser/searchbar.dtd (%chrome/browser/searchbar.dtd)
locale/browser/engineManager.dtd (%chrome/browser/engineManager.dtd)
locale/browser/engineManager.properties (%chrome/browser/engineManager.properties)
locale/browser/setDesktopBackground.dtd (%chrome/browser/setDesktopBackground.dtd)
locale/browser/shellservice.properties (%chrome/browser/shellservice.properties)
locale/browser/sessionstore.properties (%chrome/browser/sessionstore.properties)
locale/browser/places/places.dtd (%chrome/browser/places/places.dtd)
locale/browser/places/places.properties (%chrome/browser/places/places.properties)
+ locale/browser/places/editBookmarkOverlay.dtd (%chrome/browser/places/editBookmarkOverlay.dtd)
locale/browser/places/bookmarkProperties.dtd (%chrome/browser/places/bookmarkProperties.dtd)
locale/browser/places/bookmarkProperties.properties (%chrome/browser/places/bookmarkProperties.properties)
locale/browser/preferences/selectBookmark.dtd (%chrome/browser/preferences/selectBookmark.dtd)
locale/browser/places/moveBookmarks.dtd (%chrome/browser/places/moveBookmarks.dtd)
#ifdef MOZ_SAFE_BROWSING
locale/browser/safebrowsing/phishing-afterload-warning-message.dtd (%chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd)
locale/browser/safebrowsing/report-phishing.dtd (%chrome/browser/safebrowsing/report-phishing.dtd)
#endif
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -1264,8 +1264,17 @@ toolbarbutton.bookmark-item[dragover="tr
border-top: none !important;
border-left: 2px solid;
border-right: 2px solid;
border-bottom: 3px solid;
-moz-border-right-colors: -moz-mac-menushadow ThreeDLightShadow !important;
-moz-border-bottom-colors: -moz-mac-menushadow -moz-mac-menushadow ThreeDShadow !important;
-moz-border-left-colors: ThreeDLightShadow ThreeDHighlight !important;
}
+
+/* star icon */
+#star-icon {
+ list-style-image: url("chrome://browser/skin/places/starPage.png");
+}
+
+#star-icon[starred="true"] {
+ list-style-image: url("chrome://browser/skin/places/pageStarred.png");
+}
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -39,16 +39,19 @@ classic.jar:
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
skin/classic/browser/places/folderDragOver.png (places/folderDragOver.png)
skin/classic/browser/places/folderDropArrow.png (places/folderDropArrow.png)
skin/classic/browser/places/folderDropHoverArrow.png (places/folderDropHoverArrow.png)
skin/classic/browser/places/livemarkFolder.png (places/livemarkFolder.png)
skin/classic/browser/places/livemarkFolderHover.png (places/livemarkFolderHover.png)
skin/classic/browser/places/bookmarkProperties.css (places/bookmarkProperties.css)
+ skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
+ skin/classic/browser/places/starPage.png (places/starPage.png)
+ skin/classic/browser/places/pageStarred.png (places/pageStarred.png)
skin/classic/browser/places/organizer-toolbar.png (bookmarks/Bookmarks-toolbar.png)
skin/classic/browser/places/expander-closed-active.png (bookmarks/expander-closed-active.png)
skin/classic/browser/places/expander-closed.png (bookmarks/expander-closed.png)
skin/classic/browser/places/expander-open-active.png (bookmarks/expander-open-active.png)
skin/classic/browser/places/expander-open.png (bookmarks/expander-open.png)
#ifdef MOZ_SAFE_BROWSING
skin/classic/browser/safebrowsing/browser-protection.css (safebrowsing/browser-protection.css)
skin/classic/browser/safebrowsing/close16x16.png (safebrowsing/close16x16.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/pinstripe/browser/places/editBookmarkOverlay.css
@@ -0,0 +1,143 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Firefox.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Myk Melez <myk@mozilla.org>
+ * Asaf Romano <mano@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+@namespace html url("http://www.w3.org/1999/xhtml");
+
+/**** folder menulist ****/
+.folder-icon > .menulist-label-box > .menulist-icon,
+.folder-icon > .menu-iconic-left > .menu-iconic-icon {
+ width: 16px;
+ height: 16px;
+}
+
+.folder-icon > .menu-iconic-left {
+ display: -moz-box;
+}
+
+.folder-icon {
+ list-style-image: url("chrome://global/skin/tree/folder.png") !important;
+}
+
+.menulist-icon {
+ margin: 0 !important;
+}
+
+/**** folder tree ****/
+
+#editBMPanel_folderTree {
+ margin: 6px 0;
+}
+
+/**** expanders ****/
+
+.expander-up,
+.expander-down {
+ -moz-appearance: none;
+ margin-left: 8px;
+ padding: 0;
+ min-width: 0;
+}
+
+.expander-up {
+ list-style-image: url("chrome://browser/skin/places/expander-open.png") !important;
+}
+
+.expander-down {
+ list-style-image: url("chrome://browser/skin/places/expander-closed.png") !important;
+}
+
+.expander-down:hover:active {
+ list-style-image: url("chrome://browser/skin/places/expander-closed-active.png") !important;
+}
+
+.expander-up:hover:active {
+ list-style-image: url("chrome://browser/skin/places/expander-open-active.png") !important;
+}
+
+/**** name picker ****/
+
+/* Make the microsummary picker look like a regular textbox instead of
+ * an editable menulist when no microsummaries are available.
+ */
+#editBMPanel_namePicker[droppable="false"] {
+ -moz-appearance: none;
+ margin: 0px;
+ border: none;
+ padding: 0px;
+ height: auto !important;
+}
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
+ display: none;
+}
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-editable-box {
+ /* These rules are duplicates of the rules for the textbox element
+ * in textbox.css and should track changes in that file.
+ */
+ -moz-appearance: textfield;
+ cursor: text;
+ margin: 2px 4px;
+ border: 2px solid;
+ -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
+ -moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
+ -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
+ -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
+ padding: 2px 2px 3px 4px;
+ background-color: -moz-Field;
+ color: -moz-FieldText;
+}
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-editable-box > html|*.textbox-input {
+ margin: 0px !important;
+ border: none !important;
+ padding: 0px !important;
+ background-color: inherit;
+ color: inherit;
+ font: inherit;
+}
+
+/* Hide the drop marker and the popup. */
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
+ display: none;
+}
+
+#editBMPanel_namePicker[droppable="false"] > menupopup {
+ display: none;
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b63f06afbcdc46f379d1ce0fb0783ef4a0ffc90b
GIT binary patch
literal 3270
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
Eg3c`;d;kCd
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5223196e8ea68fbd7d714e8820a0bcc25f184d2a
GIT binary patch
literal 3075
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
R_H+OM002ovPDHLkV1iqKt?2*&
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -1434,8 +1434,17 @@ toolbarbutton.bookmark-item[dragover="tr
.bookmark-item[dragover-top="true"] {
-moz-border-top-colors: #000000;
}
.bookmark-item[dragover-bottom="true"] {
-moz-border-bottom-colors: #000000;
}
+
+/* star icon */
+#star-icon {
+ list-style-image: url("chrome://browser/skin/places/starPage.png");
+}
+
+#star-icon[starred="true"] {
+ list-style-image: url("chrome://browser/skin/places/pageStarred.png");
+}
--- a/browser/themes/winstripe/browser/jar.mn
+++ b/browser/themes/winstripe/browser/jar.mn
@@ -45,16 +45,19 @@ classic.jar:
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
skin/classic/browser/places/places.css (places/places.css)
skin/classic/browser/places/query.png (places/query.png)
skin/classic/browser/places/livemarkItem.png (places/livemarkItem.png)
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
skin/classic/browser/places/folderDragOver.png (places/folderDragOver.png)
+ skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
+ skin/classic/browser/places/starPage.png (places/starPage.png)
+ skin/classic/browser/places/pageStarred.png (places/pageStarred.png)
skin/classic/browser/places/bookmarkProperties.css (places/bookmarkProperties.css)
skin/classic/browser/places/organizer-toolbar.png (bookmarks/Bookmarks-toolbar.png)
#ifdef MOZ_SAFE_BROWSING
skin/classic/browser/safebrowsing/browser-protection.css (safebrowsing/browser-protection.css)
skin/classic/browser/safebrowsing/close16x16.png (safebrowsing/close16x16.png)
skin/classic/browser/safebrowsing/dim.png (safebrowsing/dim.png)
skin/classic/browser/safebrowsing/tail.png (safebrowsing/tail.png)
skin/classic/browser/safebrowsing/warning16x16.png (safebrowsing/warning16x16.png)
new file mode 100644
--- /dev/null
+++ b/browser/themes/winstripe/browser/places/editBookmarkOverlay.css
@@ -0,0 +1,110 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Firefox.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2006
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Myk Melez <myk@mozilla.org>
+ * Asaf Romano <mano@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**** folder menulist ****/
+.folder-icon > .menulist-label-box > .menulist-icon {
+ width: 16px;
+ height: 16px;
+}
+
+.folder-icon > .menu-iconic-left {
+ display: -moz-box;
+}
+
+.folder-icon {
+ list-style-image: url("chrome://global/skin/icons/folder-item.png") !important;
+ -moz-image-region: rect(0px, 32px, 16px, 16px) !important;
+}
+
+
+/**** expanders ****/
+
+.expander-up,
+.expander-down {
+ min-width: 0;
+}
+
+.expander-up {
+ list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
+}
+
+.expander-down {
+ list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif");
+}
+
+.expander-down:hover:active {
+ list-style-image: url("chrome://global/skin/arrow/arrow-dn-hov.gif");
+}
+
+.expander-up:hover:active {
+ list-style-image: url("chrome://global/skin/arrow/arrow-up-hov.gif");
+}
+
+/**** name picker ****/
+
+/* Make the microsummary picker look like a regular textbox instead of
+ * an editable menulist when no microsummaries are available.
+ */
+#editBMPanel_namePicker[droppable="false"] {
+ /* These rules come from the textbox element in textbox.css. */
+
+ /* Normal editable menulists set this to "none". */
+ -moz-appearance: textfield;
+ cursor: text;
+
+ border: 2px solid;
+ -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow;
+ -moz-border-right-colors: ThreeDHighlight ThreeDLightShadow;
+ -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow;
+ -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow;
+ background-color: -moz-Field;
+ color: -moz-FieldText;
+}
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker {
+ /* Normal editable menulists set this to "menulist-textfield". */
+ -moz-appearance: none;
+ padding: 2px 2px 3px 4px;
+}
+
+
+/* Hide the drop marker and the popup. */
+
+#editBMPanel_namePicker[droppable="false"] > .menulist-dropmarker,
+#editBMPanel_namePicker[droppable="false"] > menupopup {
+ display: none;
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b63f06afbcdc46f379d1ce0fb0783ef4a0ffc90b
GIT binary patch
literal 3270
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
Eg3c`;d;kCd
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5223196e8ea68fbd7d714e8820a0bcc25f184d2a
GIT binary patch
literal 3075
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
R_H+OM002ovPDHLkV1iqKt?2*&
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -174,16 +174,17 @@ MOZ_COMPONENT_NSPR_LIBS=@MOZ_COMPONENT_N
MOZ_FIX_LINK_PATHS=@MOZ_FIX_LINK_PATHS@
XPCOM_FROZEN_LDOPTS=@XPCOM_FROZEN_LDOPTS@
XPCOM_LIBS=@XPCOM_LIBS@
MOZ_TIMELINE=@MOZ_TIMELINE@
ENABLE_STRIP = @ENABLE_STRIP@
+PKG_SKIP_STRIP = @PKG_SKIP_STRIP@
ClientWallet=1
CookieManagement=1
SingleSignon=1
MOZ_OJI = @MOZ_OJI@
MOZ_PLUGINS = @MOZ_PLUGINS@
--- a/configure.in
+++ b/configure.in
@@ -6091,16 +6091,24 @@ dnl ====================================
dnl = Enable stripping of libs & executables
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(strip,
[ --enable-strip Enable stripping of libs & executables ],
ENABLE_STRIP=1,
ENABLE_STRIP= )
dnl ========================================================
+dnl = Enable stripping of libs & executables when packaging
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(install-strip,
+[ --enable-install-strip Enable stripping of libs & executables when packaging ],
+ PKG_SKIP_STRIP= ,
+ PKG_SKIP_STRIP=1)
+
+dnl ========================================================
dnl = --enable-elf-dynstr-gc
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(elf-dynstr-gc,
[ --enable-elf-dynstr-gc Enable elf dynstr garbage collector (opt builds only)],
USE_ELF_DYNSTR_GC=1,
USE_ELF_DYNSTR_GC= )
dnl ========================================================
@@ -7436,16 +7444,17 @@ AC_SUBST(MOZ_XPINSTALL)
AC_SUBST(MOZ_VIEW_SOURCE)
AC_SUBST(MOZ_SPELLCHECK)
AC_SUBST(MOZ_XPFE_COMPONENTS)
AC_SUBST(MOZ_USER_DIR)
AC_SUBST(MOZ_CRASHREPORTER)
AC_SUBST(MOZ_MOCHITEST)
AC_SUBST(ENABLE_STRIP)
+AC_SUBST(PKG_SKIP_STRIP)
AC_SUBST(USE_ELF_DYNSTR_GC)
AC_SUBST(USE_PREBINDING)
AC_SUBST(INCREMENTAL_LINKER)
AC_SUBST(MOZ_COMPONENTS_VERSION_SCRIPT_LDFLAGS)
AC_SUBST(MOZ_COMPONENT_NSPR_LIBS)
AC_SUBST(MOZ_XPCOM_OBSOLETE_LIBS)
AC_SUBST(MOZ_FIX_LINK_PATHS)
--- a/content/base/public/nsIContentSerializer.h
+++ b/content/base/public/nsIContentSerializer.h
@@ -47,26 +47,27 @@ class nsIDOMComment; /* forward declarat
class nsIDOMDocumentType; /* forward declaration */
class nsIDOMElement; /* forward declaration */
class nsIDOMDocument; /* forward declaration */
class nsAString;
/* starting interface: nsIContentSerializer */
#define NS_ICONTENTSERIALIZER_IID \
-{ 0x0921afbc, 0x4c6f, 0x4249, \
- { 0xa7, 0xf5, 0x32, 0xe4, 0x91, 0xbf, 0x6e, 0x32 } }
+{ 0x34769de0, 0x30d0, 0x4cef, \
+ { 0x89, 0x4a, 0xfc, 0xd8, 0xbb, 0x27, 0xc4, 0xb4 } }
class nsIContentSerializer : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTSERIALIZER_IID)
NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
- const char* aCharSet, PRBool aIsCopying) = 0;
+ const char* aCharSet, PRBool aIsCopying,
+ PRBool aIsWholeDocument) = 0;
NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
PRInt32 aEndOffset, nsAString& aStr) = 0;
NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
PRInt32 aStartOffset, PRInt32 aEndOffset,
nsAString& aStr) = 0;
--- a/content/base/src/mozSanitizingSerializer.cpp
+++ b/content/base/src/mozSanitizingSerializer.cpp
@@ -121,29 +121,30 @@ NS_IMPL_ISUPPORTS4(mozSanitizingHTMLSeri
nsIContentSerializer,
nsIContentSink,
nsIHTMLContentSink,
mozISanitizingHTMLSerializer)
NS_IMETHODIMP
mozSanitizingHTMLSerializer::Init(PRUint32 aFlags, PRUint32 dummy,
- const char* aCharSet, PRBool aIsCopying)
+ const char* aCharSet, PRBool aIsCopying,
+ PRBool aIsWholeDocument)
{
NS_ENSURE_TRUE(nsContentUtils::GetParserService(), NS_ERROR_UNEXPECTED);
return NS_OK;
}
NS_IMETHODIMP
mozSanitizingHTMLSerializer::Initialize(nsAString* aOutString,
PRUint32 aFlags,
const nsAString& allowedTags)
{
- nsresult rv = Init(aFlags, 0, nsnull, PR_FALSE);
+ nsresult rv = Init(aFlags, 0, nsnull, PR_FALSE, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// XXX This is wrong. It violates XPCOM string ownership rules.
// We're only getting away with this because instances of this
// class are restricted to single function scope.
// (Comment copied from nsPlaintextSerializer)
mOutputString = aOutString;
--- a/content/base/src/mozSanitizingSerializer.h
+++ b/content/base/src/mozSanitizingSerializer.h
@@ -67,17 +67,17 @@ public:
virtual ~mozSanitizingHTMLSerializer();
static PRBool PR_CALLBACK ReleaseProperties(nsHashKey* key, void* data,
void* closure);
NS_DECL_ISUPPORTS
// nsIContentSerializer
NS_IMETHOD Init(PRUint32 flags, PRUint32 dummy, const char* aCharSet,
- PRBool aIsCopying);
+ PRBool aIsCopying, PRBool aIsWholeDocument);
NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
PRInt32 aEndOffset, nsAString& aStr);
NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
PRInt32 aStartOffset, PRInt32 aEndOffset,
nsAString& aStr)
{ return NS_OK; }
NS_IMETHOD AppendProcessingInstruction(nsIDOMProcessingInstruction* aPI,
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -888,17 +888,19 @@ nsDocumentEncoder::EncodeToString(nsAStr
nsCOMPtr<nsIAtom> charsetAtom;
if (!mCharset.IsEmpty()) {
if (!mCharsetConverterManager) {
mCharsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
}
- mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying);
+
+ PRBool isWholeDocument = !(mSelection || mRange || mNode);
+ mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying, isWholeDocument);
if (mSelection) {
nsCOMPtr<nsIDOMRange> range;
PRInt32 i, count = 0;
rv = mSelection->GetRangeCount(&count);
NS_ENSURE_SUCCESS(rv, rv);
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -421,16 +421,17 @@ GK_ATOM(insertafter, "insertafter")
GK_ATOM(insertbefore, "insertbefore")
GK_ATOM(instanceOf, "instanceOf")
GK_ATOM(intersection, "intersection")
GK_ATOM(iscontainer, "iscontainer")
GK_ATOM(isempty, "isempty")
GK_ATOM(isindex, "isindex")
GK_ATOM(ismap, "ismap")
GK_ATOM(kbd, "kbd")
+GK_ATOM(noautofocus, "noautofocus")
GK_ATOM(key, "key")
GK_ATOM(keycode, "keycode")
GK_ATOM(keydown, "keydown")
GK_ATOM(keypress, "keypress")
GK_ATOM(keyset, "keyset")
GK_ATOM(keytext, "keytext")
GK_ATOM(keyup, "keyup")
GK_ATOM(label, "label")
--- a/content/base/src/nsHTMLContentSerializer.cpp
+++ b/content/base/src/nsHTMLContentSerializer.cpp
@@ -88,16 +88,17 @@ nsresult NS_NewHTMLContentSerializer(nsI
}
nsHTMLContentSerializer::nsHTMLContentSerializer()
: mIndent(0),
mColPos(0),
mInBody(PR_FALSE),
mAddSpace(PR_FALSE),
mMayIgnoreLineBreakSequence(PR_FALSE),
+ mIsWholeDocument(PR_FALSE),
mInCDATA(PR_FALSE),
mNeedLineBreaker(PR_TRUE)
{
}
nsHTMLContentSerializer::~nsHTMLContentSerializer()
{
NS_ASSERTION(mOLStateStack.Count() == 0, "Expected OL State stack to be empty");
@@ -107,26 +108,28 @@ nsHTMLContentSerializer::~nsHTMLContentS
delete state;
mOLStateStack.RemoveElementAt(i);
}
}
}
NS_IMETHODIMP
nsHTMLContentSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
- const char* aCharSet, PRBool aIsCopying)
+ const char* aCharSet, PRBool aIsCopying,
+ PRBool aIsWholeDocument)
{
mFlags = aFlags;
if (!aWrapColumn) {
mMaxColumn = 72;
}
else {
mMaxColumn = aWrapColumn;
}
+ mIsWholeDocument = aIsWholeDocument;
mIsCopying = aIsCopying;
mIsFirstChildOfOL = PR_FALSE;
mDoFormat = (mFlags & nsIDocumentEncoder::OutputFormatted) ? PR_TRUE
: PR_FALSE;
mBodyOnly = (mFlags & nsIDocumentEncoder::OutputBodyOnly) ? PR_TRUE
: PR_FALSE;
// Set the line break character:
if ((mFlags & nsIDocumentEncoder::OutputCRLineBreak)
@@ -631,17 +634,17 @@ nsHTMLContentSerializer::AppendElementSt
// even if we're not in pretty printing mode
PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None,
nsGkAtoms::mozdirty);
nsIAtom *name = content->Tag();
// We need too skip any meta tags that set the content type
// becase we set our own later.
- if (name == nsGkAtoms::meta) {
+ if (mIsWholeDocument && name == nsGkAtoms::meta) {
nsAutoString header;
content->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
if (header.LowerCaseEqualsLiteral("content-type")) {
return NS_OK;
}
}
if (name == nsGkAtoms::br && mPreLevel > 0
@@ -733,17 +736,17 @@ nsHTMLContentSerializer::AppendElementSt
if (name == nsGkAtoms::script ||
name == nsGkAtoms::style ||
name == nsGkAtoms::noscript ||
name == nsGkAtoms::noframes) {
mInCDATA = PR_TRUE;
}
- if (name == nsGkAtoms::head) {
+ if (mIsWholeDocument && name == nsGkAtoms::head) {
AppendToString(mLineBreak, aStr);
AppendToString(NS_LITERAL_STRING("<meta http-equiv=\"content-type\""),
aStr);
AppendToString(NS_LITERAL_STRING(" content=\"text/html; charset="), aStr);
AppendToString(NS_ConvertASCIItoUTF16(mCharset), aStr);
AppendToString(NS_LITERAL_STRING("\">"), aStr);
}
@@ -760,17 +763,17 @@ nsHTMLContentSerializer::AppendElementEn
if (!content) return NS_ERROR_FAILURE;
PRBool hasDirtyAttr = content->HasAttr(kNameSpaceID_None,
nsGkAtoms::mozdirty);
nsIAtom *name = content->Tag();
// So that we don't mess up the line breaks.
- if (name == nsGkAtoms::meta) {
+ if (mIsWholeDocument && name == nsGkAtoms::meta) {
nsAutoString header;
content->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
if (header.LowerCaseEqualsLiteral("content-type")) {
return NS_OK;
}
}
if (name == nsGkAtoms::script) {
--- a/content/base/src/nsHTMLContentSerializer.h
+++ b/content/base/src/nsHTMLContentSerializer.h
@@ -53,17 +53,18 @@ class nsIContent;
class nsIAtom;
class nsHTMLContentSerializer : public nsXMLContentSerializer {
public:
nsHTMLContentSerializer();
virtual ~nsHTMLContentSerializer();
NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
- const char* aCharSet, PRBool aIsCopying);
+ const char* aCharSet, PRBool aIsCopying,
+ PRBool aIsWholeDocument);
NS_IMETHOD AppendText(nsIDOMText* aText,
PRInt32 aStartOffset,
PRInt32 aEndOffset,
nsAString& aStr);
NS_IMETHOD AppendElementStart(nsIDOMElement *aElement,
nsIDOMElement *aOriginalElement,
nsAString& aStr);
@@ -134,16 +135,20 @@ class nsHTMLContentSerializer : public n
PRPackedBool mIsCopying; // Set to PR_TRUE only while copying
// Indicates that a space will be added if and only if content is
// continued on the same line while serializing source. Otherwise,
// the newline character acts as the whitespace and no space is needed.
PRPackedBool mAddSpace;
PRPackedBool mMayIgnoreLineBreakSequence;
+ // This is to ensure that we only do meta tag fixups when dealing with
+ // whole documents.
+ PRPackedBool mIsWholeDocument;
+
// To keep track of First LI child of OL in selected range
PRPackedBool mIsFirstChildOfOL;
PRInt32 mPreLevel;
/*
* mInCDATA is set to PR_TRUE while the serializer is serializing
* the content of a element whose content is considerd CDATA by the
* serializer (such elements are 'script', 'style', 'noscript' and
--- a/content/base/src/nsPlainTextSerializer.cpp
+++ b/content/base/src/nsPlainTextSerializer.cpp
@@ -144,17 +144,18 @@ NS_IMPL_ISUPPORTS4(nsPlainTextSerializer
nsIContentSerializer,
nsIContentSink,
nsIHTMLContentSink,
nsIHTMLToTextSink)
NS_IMETHODIMP
nsPlainTextSerializer::Init(PRUint32 aFlags, PRUint32 aWrapColumn,
- const char* aCharSet, PRBool aIsCopying)
+ const char* aCharSet, PRBool aIsCopying,
+ PRBool aIsWholeDocument)
{
#ifdef DEBUG
// Check if the major control flags are set correctly.
if(aFlags & nsIDocumentEncoder::OutputFormatFlowed) {
NS_ASSERTION(aFlags & nsIDocumentEncoder::OutputFormatted,
"If you want format=flowed, you must combine it with "
"nsIDocumentEncoder::OutputFormatted");
}
@@ -269,17 +270,17 @@ nsPlainTextSerializer::PopBool(nsVoidArr
}
return returnValue;
}
NS_IMETHODIMP
nsPlainTextSerializer::Initialize(nsAString* aOutString,
PRUint32 aFlags, PRUint32 aWrapCol)
{
- nsresult rv = Init(aFlags, aWrapCol, nsnull, PR_FALSE);
+ nsresult rv = Init(aFlags, aWrapCol, nsnull, PR_FALSE, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// XXX This is wrong. It violates XPCOM string ownership rules.
// We're only getting away with this because instances of this
// class are restricted to single function scope.
mOutputString = aOutString;
return NS_OK;
--- a/content/base/src/nsPlainTextSerializer.h
+++ b/content/base/src/nsPlainTextSerializer.h
@@ -64,17 +64,18 @@ class nsPlainTextSerializer : public nsI
public:
nsPlainTextSerializer();
virtual ~nsPlainTextSerializer();
NS_DECL_ISUPPORTS
// nsIContentSerializer
NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
- const char* aCharSet, PRBool aIsCopying);
+ const char* aCharSet, PRBool aIsCopying,
+ PRBool aIsWholeDocument);
NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
PRInt32 aEndOffset, nsAString& aStr);
NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
PRInt32 aStartOffset, PRInt32 aEndOffset,
nsAString& aStr);
NS_IMETHOD AppendProcessingInstruction(nsIDOMProcessingInstruction* aPI,
PRInt32 aStartOffset,
--- a/content/base/src/nsXMLContentSerializer.cpp
+++ b/content/base/src/nsXMLContentSerializer.cpp
@@ -88,17 +88,18 @@ nsXMLContentSerializer::nsXMLContentSeri
nsXMLContentSerializer::~nsXMLContentSerializer()
{
}
NS_IMPL_ISUPPORTS1(nsXMLContentSerializer, nsIContentSerializer)
NS_IMETHODIMP
nsXMLContentSerializer::Init(PRUint32 flags, PRUint32 aWrapColumn,
- const char* aCharSet, PRBool aIsCopying)
+ const char* aCharSet, PRBool aIsCopying,
+ PRBool aIsWholeDocument)
{
mCharset = aCharSet;
return NS_OK;
}
nsresult
nsXMLContentSerializer::AppendTextData(nsIDOMNode* aNode,
PRInt32 aStartOffset,
--- a/content/base/src/nsXMLContentSerializer.h
+++ b/content/base/src/nsXMLContentSerializer.h
@@ -55,17 +55,18 @@ class nsIAtom;
class nsXMLContentSerializer : public nsIContentSerializer {
public:
nsXMLContentSerializer();
virtual ~nsXMLContentSerializer();
NS_DECL_ISUPPORTS
NS_IMETHOD Init(PRUint32 flags, PRUint32 aWrapColumn,
- const char* aCharSet, PRBool aIsCopying);
+ const char* aCharSet, PRBool aIsCopying,
+ PRBool aIsWholeDocument);
NS_IMETHOD AppendText(nsIDOMText* aText, PRInt32 aStartOffset,
PRInt32 aEndOffset, nsAString& aStr);
NS_IMETHOD AppendCDATASection(nsIDOMCDATASection* aCDATASection,
PRInt32 aStartOffset, PRInt32 aEndOffset,
nsAString& aStr);
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -81,16 +81,17 @@ include $(topsrcdir)/config/rules.mk
test_bug371576-2.html \
test_bug371576-3.html \
test_bug371576-4.html \
test_bug371576-5.html \
test_bug372086.html \
test_bug373181.xhtml \
test_bug375314.html \
test_bug382113.html \
+ test_bug390735.html \
bug382113_object.html \
test_CrossSiteXHR.html \
file_CrossSiteXHR_fail1.xml \
file_CrossSiteXHR_fail2.xml \
file_CrossSiteXHR_fail2.xml^headers^ \
file_CrossSiteXHR_fail3.xml \
file_CrossSiteXHR_fail4.xml \
file_CrossSiteXHR_pass1.xml \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug390735.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=390735
+-->
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
+ <title>Test for Bug 390735</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+/** Test for Bug 390735 **/
+
+var contents = document.getElementsByTagName("head")[0].innerHTML;
+var expectedFind = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">";
+
+ok(contents.indexOf(expectedFind) > -1, "The meta tag element was not found");
+</script>
+</pre>
+</body>
+</html>
--- a/content/events/public/nsIEventStateManager.h
+++ b/content/events/public/nsIEventStateManager.h
@@ -47,22 +47,20 @@ class nsIDOMEvent;
class nsIFrame;
class nsIView;
class nsIWidget;
class imgIContainer;
/*
* Event state manager interface.
*/
-// {9d25327a-7a17-4d19-928c-f7f3ac19b763}
+// {fb7516ff-2f01-4893-84e8-e4b282813023}
#define NS_IEVENTSTATEMANAGER_IID \
-{ 0x9d25327a, 0x7a17, 0x4d19, \
- { 0x92, 0x8c, 0xf7, 0xf3, 0xac, 0x19, 0xb7, 0x63 } }
-
-
+{ 0xfb7516ff, 0x2f01, 0x4893, \
+ { 0x84, 0xe8, 0xe4, 0xb2, 0x82, 0x81, 0x30, 0x23 } }
#define NS_EVENT_NEEDS_FRAME(event) (!NS_IS_FOCUS_EVENT(event))
class nsIEventStateManager : public nsISupports {
public:
enum EFocusedWithType {
eEventFocusedByUnknown, // focus gained via unknown method
@@ -140,16 +138,25 @@ public:
NS_IMETHOD SetCursor(PRInt32 aCursor, imgIContainer* aContainer,
PRBool aHaveHotspot, float aHotspotX, float aHotspotY,
nsIWidget* aWidget, PRBool aLockCursor) = 0;
// Method for moving the focus forward/back.
NS_IMETHOD ShiftFocus(PRBool aDirection, nsIContent* aStart)=0;
NS_IMETHOD NotifyDestroyPresContext(nsPresContext* aPresContext) = 0;
+
+ /**
+ * Returns true if the current code is being executed as a result of user input.
+ * This includes timers or anything else that is initiated from user input.
+ * However, mouse hover events are not counted as user input, nor are
+ * page load events. If this method is called from asynchronously executed code,
+ * such as during layout reflows, it will return false.
+ */
+ NS_IMETHOD_(PRBool) IsHandlingUserInputExternal() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIEventStateManager, NS_IEVENTSTATEMANAGER_IID)
#define NS_EVENT_STATE_ACTIVE 0x00000001 // mouse is down on content
#define NS_EVENT_STATE_FOCUS 0x00000002 // content has focus
#define NS_EVENT_STATE_HOVER 0x00000004 // mouse is hovering over content
#define NS_EVENT_STATE_DRAGOVER 0x00000008 // drag is hovering over content
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -88,16 +88,17 @@
#include "nsIDOMEventTarget.h"
#include "nsIEnumerator.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeNode.h"
#include "nsIWebNavigation.h"
#include "nsIContentViewer.h"
#include "nsIPrefBranch2.h"
#include "nsIObjectFrame.h"
+#include "nsXULPopupManager.h"
#include "nsIServiceManager.h"
#include "nsIScriptSecurityManager.h"
#include "nsIFocusController.h"
#include "nsIDOMXULElement.h"
#include "nsIDOMDocument.h"
@@ -3373,23 +3374,64 @@ nsEventStateManager::ShiftFocusInternal(
mCurrentTabIndex = docHasFocus && selectionFrame ? 0 : 1;
} else if (!docHasFocus) {
mCurrentTabIndex = 0;
} else if (selectionFrame) {
mCurrentTabIndex = 1; // will keep it from wrapping around to end
}
}
+ // when a popup is open, we want to ensure that tab navigation occurs only
+ // within the most recently opened panel. If a popup is open, its frame will
+ // be stored in popupFrame.
+ nsIFrame* popupFrame = nsnull;
+ if (curFocusFrame) {
+ // check if the focus is currently inside a popup. Elements such as the
+ // autocomplete widget use the noautofocus attribute to allow the focus to
+ // remain outside the popup when it is opened.
+ popupFrame = nsLayoutUtils::GetClosestFrameOfType(curFocusFrame,
+ nsGkAtoms::menuPopupFrame);
+ }
+ else {
+ // if there is no focus, yet a panel is open, focus the
+ // first item in the popup
+ nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+ if (pm) {
+ popupFrame = pm->GetTopPopup(ePopupTypePanel);
+ }
+ }
+
+ if (popupFrame) {
+ // Don't navigate outside of a popup, so pretend that the
+ // root content is the popup itself
+ rootContent = popupFrame->GetContent();
+ NS_ASSERTION(rootContent, "Popup frame doesn't have a content node");
+ }
+
nsCOMPtr<nsIContent> nextFocus;
nsIFrame* nextFocusFrame;
if (aForward || !docHasFocus || selectionFrame)
GetNextTabbableContent(rootContent, startContent, curFocusFrame,
aForward, ignoreTabIndex || mCurrentTabIndex < 0,
getter_AddRefs(nextFocus), &nextFocusFrame);
+ if (popupFrame && !nextFocus) {
+ // if no content was found to focus, yet we are inside a popup, try again
+ // from the beginning or end of the popup. Set the current tab index to
+ // the beginning or end.
+ mCurrentTabIndex = aForward ? 1 : 0;
+ GetNextTabbableContent(rootContent, rootContent, nsnull,
+ aForward, ignoreTabIndex,
+ getter_AddRefs(nextFocus), &nextFocusFrame);
+ // if the same node was found, don't change the focus
+ if (startContent == nextFocus) {
+ nextFocus = nsnull;
+ }
+ }
+
// Clear out mCurrentTabIndex. It has a garbage value because of GetNextTabbableContent()'s side effects
// It will be set correctly when focus is changed via ChangeFocusWith()
mCurrentTabIndex = 0;
if (nextFocus) {
// Check to see if the next focused element has a subshell.
// This is the case for an IFRAME or FRAME element. If it
// does, we send focus into the subshell.
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -151,16 +151,18 @@ public:
--sUserInputEventDepth;
}
static PRBool IsHandlingUserInput()
{
return sUserInputEventDepth > 0;
}
+ NS_IMETHOD_(PRBool) IsHandlingUserInputExternal() { return IsHandlingUserInput(); }
+
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsEventStateManager,
nsIEventStateManager)
protected:
/**
* In certain situations the focus controller's concept of focus gets out of
* whack with mCurrentFocus. This is used in known cases to reset the focus
* controller's focus. At some point we should probably move to a single
--- a/content/html/content/src/nsFormSubmission.cpp
+++ b/content/html/content/src/nsFormSubmission.cpp
@@ -752,23 +752,26 @@ nsFSMultipartFormData::AddNameValuePair(
NS_ENSURE_SUCCESS(rv, rv);
//
// Make MIME block for name/value pair
//
// XXX: name parameter should be encoded per RFC 2231
// RFC 2388 specifies that RFC 2047 be used, but I think it's not
// consistent with MIME standard.
+ // NOTE: The ordering of these headers, and in particular which comes first
+ // and which comes last, is important. See comments in
+ // nsFSMultipartFormData::AddNameFilePair
mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
+ NS_LITERAL_CSTRING(CRLF)
+ + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
+ + nameStr + NS_LITERAL_CSTRING("\"" CRLF)
+ NS_LITERAL_CSTRING("Content-Type: text/plain; charset=")
+ mCharset
- + NS_LITERAL_CSTRING(CRLF)
- + NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
- + nameStr + NS_LITERAL_CSTRING("\"" CRLF CRLF)
+ + NS_LITERAL_CSTRING(CRLF CRLF)
+ valueStr + NS_LITERAL_CSTRING(CRLF);
return NS_OK;
}
nsresult
nsFSMultipartFormData::AddNameFilePair(nsIDOMHTMLElement* aSource,
const nsAString& aName,
@@ -785,22 +788,33 @@ nsFSMultipartFormData::AddNameFilePair(n
//
// Make MIME block for name/value pair
//
// more appropriate than always using binary?
mPostDataChunk += NS_LITERAL_CSTRING("--") + mBoundary
+ NS_LITERAL_CSTRING(CRLF);
if (!mBackwardsCompatibleSubmit) {
// XXX Is there any way to tell when "8bit" or "7bit" etc may be
+ // XXXbz See bug 58189 for why we try to send it and bug 83065 for why we
+ // don't just always do it. It seems like a better solution would be to
+ // just make sure we send this header before the Content-Type header (to
+ // deal with the PHP brain-deadness described in bug 83065), but to send it
+ // anyway. However, we need to make sure it comes after the
+ // Content-Disposition header, because other server-side packages make the
+ // equally brain-dead assumption that Content-Disposition is the first
+ // header in every part. See bug 116346 for that fun.
mPostDataChunk +=
NS_LITERAL_CSTRING("Content-Transfer-Encoding: binary" CRLF);
}
// XXX: name/filename parameter should be encoded per RFC 2231
// RFC 2388 specifies that RFC 2047 be used, but I think it's not
// consistent with the MIME standard.
+ // NOTE: The Content-Disposition MUST come first and the Content-Type last to
+ // satisfy non-MIME-compliant server-side parsers. See comment above on
+ // Content-Transfer-Encoding.
mPostDataChunk +=
NS_LITERAL_CSTRING("Content-Disposition: form-data; name=\"")
+ nameStr + NS_LITERAL_CSTRING("\"; filename=\"")
+ filenameStr + NS_LITERAL_CSTRING("\"" CRLF)
+ NS_LITERAL_CSTRING("Content-Type: ") + aContentType
+ NS_LITERAL_CSTRING(CRLF CRLF);
//
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -3658,16 +3658,17 @@ nsHTMLDocument::CreateAndAddWyciwygChann
NS_ENSURE_SUCCESS(rv, rv);
mWyciwygChannel = do_QueryInterface(channel);
mWyciwygChannel->SetSecurityInfo(mSecurityInfo);
// Note: we want to treat this like a "previous document" hint so that,
// e.g. a <meta> tag in the document.write content can override it.
+ SetDocumentCharacterSetSource(kCharsetFromHintPrevDoc);
mWyciwygChannel->SetCharsetAndSource(kCharsetFromHintPrevDoc,
GetDocumentCharacterSet());
// Use our new principal
channel->SetOwner(NodePrincipal());
// Inherit load flags from the original document's channel
channel->SetLoadFlags(mLoadFlags);
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -50,17 +50,17 @@
// uriloader
#include "nsURILoader.h"
#include "nsDocLoader.h"
#include "nsOSHelperAppService.h"
#include "nsExternalProtocolHandler.h"
#include "nsPrefetchService.h"
#include "nsOfflineCacheUpdate.h"
-#include "nsHandlerAppImpl.h"
+#include "nsLocalHandlerApp.h"
// session history
#include "nsSHEntry.h"
#include "nsSHistory.h"
#include "nsSHTransaction.h"
// global history
#include "nsGlobalHistoryAdapter.h"
--- a/dom/public/idl/base/nsIDOMWindowUtils.idl
+++ b/dom/public/idl/base/nsIDOMWindowUtils.idl
@@ -42,17 +42,17 @@
* to the current nsIDOMWindow. Some of the methods may require
* elevated privileges; the method implementations should contain the
* necessary security checks. Access this interface by calling
* getInterface on a DOMWindow.
*/
interface nsIDOMElement;
-[scriptable, uuid(1F313394-73AB-41BF-8307-9FC5DA8A481E)]
+[scriptable, uuid(25f55fb2-a6f8-4f7f-93c3-3adafd5166bc)]
interface nsIDOMWindowUtils : nsISupports {
/**
* Image animation mode of the window. When this attribute's value
* is changed, the implementation should set all images in the window
* to the given value. That is, when set to kDontAnimMode, all images
* will stop animating. The attribute's value must be one of the
* animationMode values from imgIContainer.
@@ -65,16 +65,22 @@ interface nsIDOMWindowUtils : nsISupport
* have subsequently been individually animated.
* @note Only images immediately in this window are affected;
* this is not recursive to subwindows.
* @see imgIContainer
*/
attribute unsigned short imageAnimationMode;
/**
+ * Whether the charset of the window's current document has been forced by
+ * the user
+ */
+ readonly attribute boolean docCharsetIsForced;
+
+ /**
* Function to get metadata associated with the window's current document
* @param aName the name of the metadata. This should be all lowercase.
* @return the value of the metadata, or the empty string if it's not set
*
* Will throw a DOM security error if called without UniversalXPConnect
* privileges.
*/
AString getDocumentMetadata(in AString aName);
--- a/dom/src/base/Makefile.in
+++ b/dom/src/base/Makefile.in
@@ -78,16 +78,17 @@ REQUIRES = xpcom \
find \
appshell \
intl \
unicharutil \
rdf \
xultmpl \
jar \
storage \
+ htmlparser \
$(NULL)
ifdef NS_TRACE_MALLOC
REQUIRES += tracemalloc
endif
ifdef MOZ_JSDEBUGGER
REQUIRES += jsdebug
--- a/dom/src/base/nsDOMWindowUtils.cpp
+++ b/dom/src/base/nsDOMWindowUtils.cpp
@@ -47,16 +47,17 @@
#include "nsIFocusController.h"
#include "nsIEventStateManager.h"
#include "nsContentUtils.h"
#include "nsIFrame.h"
#include "nsIWidget.h"
#include "nsGUIEvent.h"
+#include "nsIParser.h"
#ifdef MOZ_ENABLE_GTK2
#include <gdk/gdkx.h>
#endif
NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils)
NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils)
@@ -108,16 +109,33 @@ nsDOMWindowUtils::SetImageAnimationMode(
return NS_OK;
}
}
}
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
+nsDOMWindowUtils::GetDocCharsetIsForced(PRBool *aIsForced)
+{
+ *aIsForced = PR_FALSE;
+
+ PRBool hasCap = PR_FALSE;
+ if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap)) || !hasCap)
+ return NS_ERROR_DOM_SECURITY_ERR;
+
+ if (mWindow) {
+ nsCOMPtr<nsIDocument> doc(do_QueryInterface(mWindow->GetExtantDocument()));
+ *aIsForced = doc &&
+ doc->GetDocumentCharacterSetSource() >= kCharsetFromParentForced;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName,
nsAString& aValue)
{
PRBool hasCap = PR_FALSE;
if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap))
|| !hasCap)
return NS_ERROR_DOM_SECURITY_ERR;
--- a/dom/src/base/nsJSEnvironment.cpp
+++ b/dom/src/base/nsJSEnvironment.cpp
@@ -1043,25 +1043,16 @@ nsJSContext::~nsJSContext()
struct ContextCallbackItem : public JSTracer
{
nsCycleCollectionTraversalCallback *cb;
};
void
NoteContextChild(JSTracer *trc, void *thing, uint32 kind)
{
- if (kind == JSTRACE_ATOM) {
- JSAtom *atom = (JSAtom *)thing;
- jsval v = ATOM_KEY(atom);
- if (!JSVAL_IS_PRIMITIVE(v)) {
- thing = JSVAL_TO_GCTHING(v);
- kind = JSTRACE_OBJECT;
- }
- }
-
if (kind == JSTRACE_OBJECT || kind == JSTRACE_NAMESPACE ||
kind == JSTRACE_QNAME || kind == JSTRACE_XML) {
ContextCallbackItem *item = static_cast<ContextCallbackItem*>(trc);
item->cb->NoteScriptChild(JAVASCRIPT, thing);
}
}
// QueryInterface implementation for nsJSContext
--- a/editor/libeditor/text/nsEditorEventListeners.cpp
+++ b/editor/libeditor/text/nsEditorEventListeners.cpp
@@ -518,33 +518,37 @@ nsTextEditorDragListener::DragGesture(ns
return rv;
}
nsresult
nsTextEditorDragListener::DragEnter(nsIDOMEvent* aDragEvent)
{
+ nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
if (!mCaret)
{
- nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
if (presShell)
{
mCaret = do_CreateInstance("@mozilla.org/layout/caret;1");
if (mCaret)
{
mCaret->Init(presShell);
mCaret->SetCaretReadOnly(PR_TRUE);
mOtherCaret = presShell->SetCaret(mCaret);
}
mCaretDrawn = PR_FALSE;
}
}
-
+ else if (presShell)
+ {
+ presShell->SetCaret(mCaret);
+ }
+
return DragOver(aDragEvent);
}
nsresult
nsTextEditorDragListener::DragOver(nsIDOMEvent* aDragEvent)
{
// XXX cache this between drag events?
--- a/extensions/inspector/jar.mn
+++ b/extensions/inspector/jar.mn
@@ -63,16 +63,18 @@ inspector.jar:
content/inspector/prefs/pref-inspector.xul (resources/content/prefs/pref-inspector.xul)
content/inspector/prefs/prefsOverlay.xul (resources/content/prefs/prefsOverlay.xul)
content/inspector/prefs/pref-sidebar.js (resources/content/prefs/pref-sidebar.js)
content/inspector/tests/allskin.xul (resources/content/tests/allskin.xul)
content/inspector/viewers/accessibleObject/accessibleObject.js (resources/content/viewers/accessibleObject/accessibleObject.js)
content/inspector/viewers/accessibleObject/accessibleObject.xul (resources/content/viewers/accessibleObject/accessibleObject.xul)
content/inspector/viewers/accessibleProps/accessibleProps.js (resources/content/viewers/accessibleProps/accessibleProps.js)
content/inspector/viewers/accessibleProps/accessibleProps.xul (resources/content/viewers/accessibleProps/accessibleProps.xul)
+ content/inspector/viewers/accessibleTree/accessibleTree.js (resources/content/viewers/accessibleTree/accessibleTree.js)
+ content/inspector/viewers/accessibleTree/accessibleTree.xul (resources/content/viewers/accessibleTree/accessibleTree.xul)
content/inspector/viewers/computedStyle/computedStyle.js (resources/content/viewers/computedStyle/computedStyle.js)
content/inspector/viewers/computedStyle/computedStyle.xul (resources/content/viewers/computedStyle/computedStyle.xul)
content/inspector/viewers/dom/FindDialog.js (resources/content/viewers/dom/FindDialog.js)
content/inspector/viewers/dom/columnsDialog.js (resources/content/viewers/dom/columnsDialog.js)
content/inspector/viewers/dom/columnsDialog.xul (resources/content/viewers/dom/columnsDialog.xul)
content/inspector/viewers/dom/commandOverlay.xul (resources/content/viewers/dom/commandOverlay.xul)
content/inspector/viewers/dom/insertDialog.js (resources/content/viewers/dom/insertDialog.js)
content/inspector/viewers/dom/insertDialog.xul (resources/content/viewers/dom/insertDialog.xul)
--- a/extensions/inspector/resources/content/res/viewer-registry.rdf
+++ b/extensions/inspector/resources/content/res/viewer-registry.rdf
@@ -91,21 +91,24 @@
ins:filter="return true;"/>
</rdf:li>
<rdf:li>
<rdf:Description ins:uid="accessibleObject"
ins:panels="bxObjectPanel bxObjPanel"
ins:description="Accessible Object">
<ins:filter><![CDATA[
- if (!linkedViewer || linkedViewer.uid != "dom" ||
- !linkedViewer.getAccessibleNodes() ||
+ if (!linkedViewer ||
!(object instanceof Components.interfaces.nsIDOMNode))
return false;
+ if (linkedViewer.uid != "accessibleTree" &&
+ (linkedViewer.uid != "dom" || !linkedViewer.getAccessibleNodes()))
+ return false;
+
try {
var accService =
Components.classes["@mozilla.org/accessibleRetrieval;1"]
.getService(Components.interfaces.nsIAccessibleRetrieval);
return accService.getAttachedAccessibleFor(object);
} catch(e) {
return false;
@@ -114,21 +117,45 @@
</rdf:Description>
</rdf:li>
<rdf:li>
<rdf:Description ins:uid="accessibleProps"
ins:panels="bxObjectPanel bxObjPanel"
ins:description="Accessible Properties">
<ins:filter><![CDATA[
- if (!linkedViewer || linkedViewer.uid != "dom" ||
- !linkedViewer.getAccessibleNodes() ||
+ if (!linkedViewer ||
!(object instanceof Components.interfaces.nsIDOMNode))
return false;
+ if (linkedViewer.uid != "accessibleTree" &&
+ (linkedViewer.uid != "dom" || !linkedViewer.getAccessibleNodes()))
+ return false;
+
+ try {
+ var accService =
+ Components.classes["@mozilla.org/accessibleRetrieval;1"]
+ .getService(Components.interfaces.nsIAccessibleRetrieval);
+
+ return accService.getAttachedAccessibleFor(object);
+ } catch(e) {
+ return false;
+ }
+ ]]></ins:filter>
+ </rdf:Description>
+ </rdf:li>
+
+ <rdf:li>
+ <rdf:Description ins:uid="accessibleTree"
+ ins:panels="bxDocPanel"
+ ins:description="Accessible Tree">
+ <ins:filter><![CDATA[
+ if (!(object instanceof Components.interfaces.nsIDOMDocument))
+ return false;
+
try {
var accService =
Components.classes["@mozilla.org/accessibleRetrieval;1"]
.getService(Components.interfaces.nsIAccessibleRetrieval);
return accService.getAttachedAccessibleFor(object);
} catch(e) {
return false;
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/content/viewers/accessibleTree/accessibleTree.js
@@ -0,0 +1,426 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/***************************************************************
+* AccessibleEventsViewer --------------------------------------------
+* The viewer for the accessible tree of a document.
+* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+* REQUIRED IMPORTS:
+* chrome://inspector/content/jsutil/xpcom/XPCU.js
+****************************************************************/
+
+///////////////////////////////////////////////////////////////////////////////
+//// Global Variables
+
+var viewer;
+
+///////////////////////////////////////////////////////////////////////////////
+//// Global Constants
+
+const kAccessibleRetrievalCID = "@mozilla.org/accessibleRetrieval;1";
+
+const nsIAccessibleRetrieval = Components.interfaces.nsIAccessibleRetrieval;
+const nsIAccessibleEvent = Components.interfaces.nsIAccessibleEvent;
+const nsIAccessible = Components.interfaces.nsIAccessible;
+const nsIAccessNode = Components.interfaces.nsIAccessNode;
+
+///////////////////////////////////////////////////////////////////////////////
+//// Initialization
+
+window.addEventListener("load", AccessibleTreeViewer_initialize, false);
+
+function AccessibleTreeViewer_initialize()
+{
+ viewer = new AccessibleTreeViewer();
+ viewer.initialize(parent.FrameExchange.receiveData(window));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// AccessibleEventsViewer
+
+function AccessibleTreeViewer()
+{
+ this.mURL = window.location;
+ this.mObsMan = new ObserverManager(this);
+
+ this.mTree = document.getElementById("olAccessibleTree");
+ this.mOlBox = this.mTree.treeBoxObject;
+}
+
+AccessibleTreeViewer.prototype =
+{
+ //Initialization
+
+ mSubject: null,
+ mPane: null,
+ mView: null,
+
+ // interface inIViewer
+
+ get uid() { return "accessibleTree"; },
+ get pane() { return this.mPane; },
+ get selection() { return this.mSelection; },
+
+ get subject() { return this.mSubject; },
+ set subject(aObject)
+ {
+ this.mView = new inAccTreeView(aObject);
+ this.mOlBox.view = this.mView;
+ this.mObsMan.dispatchEvent("subjectChange", { subject: aObject });
+ this.mView.selection.select(0);
+ },
+
+ initialize: function initialize(aPane)
+ {
+ this.mPane = aPane;
+ aPane.notifyViewerReady(this);
+ },
+
+ destroy: function destroy()
+ {
+ this.mOlBox.view = null;
+ },
+
+ isCommandEnabled: function isCommandEnabled(aCommand)
+ {
+ return false;
+ },
+
+ getCommand: function getCommand(aCommand)
+ {
+ return null;
+ },
+
+ // event dispatching
+
+ addObserver: function addObserver(aEvent, aObserver)
+ {
+ this.mObsMan.addObserver(aEvent, aObserver);
+ },
+ removeObserver: function removeObserver(aEvent, aObserver)
+ {
+ this.mObsMan.removeObserver(aEvent, aObserver);
+ },
+
+ // stuff
+
+ onItemSelected: function onItemSelected()
+ {
+ var idx = this.mTree.currentIndex;
+ this.mSelection = this.mView.getDOMNode(idx);
+ this.mObsMan.dispatchEvent("selectionChange",
+ { selection: this.mSelection } );
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeView
+
+function inAccTreeView(aDocument)
+{
+ this.mNodes = [];
+
+ this.mAccService = XPCU.getService(kAccessibleRetrievalCID,
+ nsIAccessibleRetrieval);
+
+ this.mDocument = aDocument;
+ this.mAccDocument = this.mAccService.getAccessibleFor(aDocument);
+
+ var node = this.createNode(this.mAccDocument);
+ this.mNodes.push(node);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeView. nsITreeView interface
+
+inAccTreeView.prototype = new inBaseTreeView();
+
+inAccTreeView.prototype.__defineGetter__("rowCount",
+function rowCount()
+{
+ return this.mNodes.length;
+});
+
+inAccTreeView.prototype.getCellText =
+function getCellText(aRow, aCol)
+{
+ var node = this.rowToNode(aRow);
+ if (!node)
+ return "";
+
+ var accessible = node.accessible;
+
+ if (aCol.id == "olcRole")
+ return this.mAccService.getStringRole(accessible.finalRole);
+
+ if (aCol.id == "olcName")
+ return accessible.name;
+
+ if (aCol.id == "olcNodeName") {
+ var node = this.getDOMNodeFor(accessible);
+ return node ? node.nodeName : "";
+ }
+
+ return "";
+}
+
+inAccTreeView.prototype.isContainer =
+function isContainer(aRow)
+{
+ var node = this.rowToNode(aRow);
+ return node ? node.isContainer : false;
+}
+
+inAccTreeView.prototype.isContainerOpen =
+function isContainerOpen(aRow)
+{
+ var node = this.rowToNode(aRow);
+ return node ? node.isOpen : false;
+}
+
+inAccTreeView.prototype.isContainerEmpty =
+function isContainerEmpty(aRow)
+{
+ return !this.isContainer(aRow);
+}
+
+inAccTreeView.prototype.getLevel =
+function getLevel(aRow)
+{
+ var node = this.rowToNode(aRow);
+ return node ? node.level : 0;
+}
+
+inAccTreeView.prototype.getParentIndex =
+function getParentIndex(aRow)
+{
+ var node = this.rowToNode(aRow);
+ if (!node)
+ return -1;
+
+ var checkNode = null;
+ var i = aRow - 1;
+ do {
+ checkNode = this.rowToNode(i);
+ if (!checkNode)
+ return -1;
+
+ if (checkNode == node.parent)
+ return i;
+ --i;
+ } while (checkNode);
+
+ return -1;
+}
+
+inAccTreeView.prototype.hasNextSibling =
+function hasNextSibling(aRow, aAfterRow)
+{
+ var node = this.rowToNode(aRow);
+ return node && (node.next != null);
+}
+
+inAccTreeView.prototype.toggleOpenState =
+function toggleOpenState(aRow)
+{
+ var node = this.rowToNode(aRow);
+ if (!node)
+ return;
+
+ var oldCount = this.rowCount;
+ if (node.isOpen)
+ this.collapseNode(aRow);
+ else
+ this.expandNode(aRow);
+
+ this.mTree.invalidateRow(aRow);
+ this.mTree.rowCountChanged(aRow + 1, this.rowCount - oldCount);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeView. Tree utils.
+
+/**
+ * Expands a tree node on the given row.
+ *
+ * @param aRow - row index.
+ */
+inAccTreeView.prototype.expandNode =
+function expandNode(aRow)
+{
+ var node = this.rowToNode(aRow);
+ if (!node)
+ return;
+
+ var kids = node.accessible.children;
+ var kidCount = kids.length;
+
+ var newNode = null;
+ var prevNode = null;
+
+ for (var i = 0; i < kidCount; ++i) {
+ var accessible = kids.queryElementAt(i, nsIAccessible);
+ newNode = this.createNode(accessible, node);
+ this.mNodes.splice(aRow + i + 1, 0, newNode);
+
+ if (prevNode)
+ prevNode.next = newNode;
+ newNode.previous = prevNode;
+ prevNode = newNode;
+ }
+
+ node.isOpen = true;
+}
+
+/**
+ * Collapse a tree node on the given row.
+ *
+ * @param aRow - row index.
+ */
+inAccTreeView.prototype.collapseNode =
+function collapseNode(aRow)
+{
+ var node = this.rowToNode(aRow);
+ if (!node)
+ return;
+
+ var row = this.getLastDescendantOf(node, aRow);
+ this.mNodes.splice(aRow + 1, row - aRow);
+
+ node.isOpen = false;
+}
+
+/**
+ * Create a tree node.
+ *
+ * @param aAccessible - an accessible object associated with created tree node.
+ * @param aParent - parent tree node for the created tree node.
+ * @retrurn - tree node object for the given accesible.
+ */
+inAccTreeView.prototype.createNode =
+function createNode(aAccessible, aParent)
+{
+ var node = new inAccTreeViewNode(aAccessible);
+ node.level = aParent ? aParent.level + 1 : 0;
+ node.parent = aParent;
+ node.isContainer = aAccessible.children.length > 0;
+
+ return node;
+}
+
+/**
+ * Return row index of the last node that is a descendant of the given node.
+ * If there is no required node then return the given row.
+ *
+ * @param aNode - tree node for that last descedant is searched.
+ * @param aRow - row index of the given tree node.
+ */
+inAccTreeView.prototype.getLastDescendantOf =
+function getLastDescendantOf(aNode, aRow)
+{
+ var rowCount = this.rowCount;
+
+ var row = aRow + 1;
+ for (; row < rowCount; ++row) {
+ if (this.mNodes[row].level <= aNode.level)
+ return row - 1;
+ }
+
+ return rowCount - 1;
+}
+
+/**
+ * Return a tree node by the given row.
+ *
+ * @param aRow - row index.
+ */
+inAccTreeView.prototype.rowToNode =
+function rowToNode(aRow)
+{
+ if (aRow < 0 || aRow >= this.rowCount)
+ return null;
+
+ return this.mNodes[aRow];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeView. Accessibility utils.
+
+/**
+ * Return DOM node for the given accessible.
+ *
+ * @param aAccessible - an accessible object.
+ */
+inAccTreeView.prototype.getDOMNodeFor =
+function getDOMNodeFor(aAccessible)
+{
+ var accessNode = XPCU.QI(aAccessible, nsIAccessNode);
+ return accessNode.DOMNode;
+}
+
+/**
+ * Return DOM node for an accessible of the tree node pointed by the given
+ * row index.
+ *
+ * @param aRow - row index.
+ */
+inAccTreeView.prototype.getDOMNode =
+function getDOMNode(aRow)
+{
+ var node = this.mNodes[aRow];
+ if (!node)
+ return null;
+
+ return this.getDOMNodeFor(node.accessible);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//// inAccTreeViewNode
+
+function inAccTreeViewNode(aAccessible)
+{
+ this.accessible = aAccessible;
+
+ this.parent = null;
+ this.next = null;
+ this.previous = null;
+
+ this.level = 0;
+ this.isOpen = false;
+ this.isContainer = false;
+}
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/content/viewers/accessibleTree/accessibleTree.xul
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+
+<!-- ***** BEGIN LICENSE BLOCK *****
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is DOM Inspector.
+ -
+ - The Initial Developer of the Original Code is
+ - Mozilla Foundation.
+ - Portions created by the Initial Developer are Copyright (C) 2007
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ - Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the GPL or the LGPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+ - ***** END LICENSE BLOCK ***** -->
+
+<!DOCTYPE page [
+ <!ENTITY % dtd1 SYSTEM "chrome://inspector/locale/inspector.dtd"> %dtd1;
+ <!ENTITY % dtd2 SYSTEM "chrome://inspector/content/util.dtd"> %dtd2;
+ <!ENTITY % dtd3 SYSTEM "chrome://inspector/locale/viewers/accessibleTree.dtd"> %dtd3;
+]>
+
+<?xml-stylesheet href="chrome://inspector/skin/"?>
+
+<page id="winAccessibleTree"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://inspector/content/jsutil/xul/inBaseTreeView.js"/>
+ <script type="application/javascript"
+ src="chrome://inspector/content/jsutil/xpcom/XPCU.js"/>
+ <script type="application/javascript"
+ src="chrome://inspector/content/jsutil/events/ObserverManager.js"/>
+ <script type="application/javascript"
+ src="chrome://inspector/content/viewers/accessibleTree/accessibleTree.js"/>
+
+ <tree id="olAccessibleTree" class="plain" flex="1"
+ onselect="viewer.onItemSelected()">
+ <treecols>
+ <treecol id="olcRole"
+ label="&role.label;"
+ persist="width,hidden,ordinal"
+ primary="true"
+ flex="1"/>
+ <splitter class="tree-splitter"/>
+ <treecol id="olcName"
+ label="&name.label;"
+ persist="width,hidden,ordinal"
+ flex="1"/>
+ <splitter class="tree-splitter"/>
+ <treecol id="olcNodeName"
+ label="&nodeName.label;"
+ persist="width,hidden,ordinal"
+ flex="1"/>
+ </treecols>
+ <treechildren id="olbAccessibleTree"
+ alternatingbackground="true"/>
+ </tree>
+
+</page>
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/en-US/viewers/accessibleTree.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is DOM Inspector.
+ -
+ - The Initial Developer of the Original Code is
+ - Mozilla Foundation.
+ - Portions created by the Initial Developer are Copyright (C) 2007
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ - Alexander Surkov <surkov.alexander@gmail.com>
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the LGPL or the GPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+#endif
+ - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Role">
+<!ENTITY name.label "Name">
+<!ENTITY nodeName.label "Node Name">
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/fr/viewers/accessibleTree.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is DOM Inspector.
+ -
+ - The Initial Developer of the Original Code is
+ - Mozilla Foundation.
+ - Portions created by the Initial Developer are Copyright (C) 2007
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ - Alexander Surkov <surkov.alexander@gmail.com>
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the LGPL or the GPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+#endif
+ - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Role">
+<!ENTITY name.label "Name">
+<!ENTITY nodeName.label "Node Name">
+
--- a/extensions/inspector/resources/locale/jar.mn
+++ b/extensions/inspector/resources/locale/jar.mn
@@ -3,16 +3,17 @@
inspector.jar:
% locale inspector @AB_CD@ %locale/@AB_CD@/inspector/
* locale/@AB_CD@/inspector/contents.rdf (contents.rdf)
locale/@AB_CD@/inspector/inspector.dtd (@AB_CD@/inspector.dtd)
locale/@AB_CD@/inspector/prefs.dtd (@AB_CD@/prefs.dtd)
locale/@AB_CD@/inspector/editing.dtd (@AB_CD@/editing.dtd)
locale/@AB_CD@/inspector/tasksOverlay.dtd (@AB_CD@/tasksOverlay.dtd)
* locale/@AB_CD@/inspector/viewers/accessibleProps.dtd (@AB_CD@/viewers/accessibleProps.dtd)
+* locale/@AB_CD@/inspector/viewers/accessibleTree.dtd (@AB_CD@/viewers/accessibleTree.dtd)
* locale/@AB_CD@/inspector/viewers/dom.dtd (@AB_CD@/viewers/dom.dtd)
* locale/@AB_CD@/inspector/viewers/domNode.dtd (@AB_CD@/viewers/domNode.dtd)
* locale/@AB_CD@/inspector/viewers/styleRules.dtd (@AB_CD@/viewers/styleRules.dtd)
* locale/@AB_CD@/inspector/viewers/stylesheets.dtd (@AB_CD@/viewers/stylesheets.dtd)
* locale/@AB_CD@/inspector/viewers/xblBindings.dtd (@AB_CD@/viewers/xblBindings.dtd)
* locale/@AB_CD@/inspector/viewers/boxModel.dtd (@AB_CD@/viewers/boxModel.dtd)
* locale/@AB_CD@/inspector/viewers/computedStyle.dtd (@AB_CD@/viewers/computedStyle.dtd)
* locale/@AB_CD@/inspector/viewers/jsObject.dtd (@AB_CD@/viewers/jsObject.dtd)
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/nb-NO/viewers/accessibleTree.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is DOM Inspector.
+ -
+ - The Initial Developer of the Original Code is
+ - Mozilla Foundation.
+ - Portions created by the Initial Developer are Copyright (C) 2007
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ - Alexander Surkov <surkov.alexander@gmail.com>
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the LGPL or the GPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+#endif
+ - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Role">
+<!ENTITY name.label "Name">
+<!ENTITY nodeName.label "Node Name">
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/pl/viewers/accessibleTree.dtd
@@ -0,0 +1,44 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is DOM Inspector.
+ -
+ - The Initial Developer of the Original Code is
+ - Mozilla Foundation.
+ - Portions created by the Initial Developer are Copyright (C) 2007
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ - Alexander Surkov <surkov.alexander@gmail.com>
+ - Marek Stępień <mstepien@aviary.pl>
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the LGPL or the GPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+#endif
+ - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Rola">
+<!ENTITY name.label "Nazwa">
+<!ENTITY nodeName.label "Nazwa węzła">
+
new file mode 100644
--- /dev/null
+++ b/extensions/inspector/resources/locale/ru/viewers/accessibleTree.dtd
@@ -0,0 +1,43 @@
+<!-- ***** BEGIN LICENSE BLOCK *****
+#if 0
+ - Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ -
+ - The contents of this file are subject to the Mozilla Public License Version
+ - 1.1 (the "License"); you may not use this file except in compliance with
+ - the License. You may obtain a copy of the License at
+ - http://www.mozilla.org/MPL/
+ -
+ - Software distributed under the License is distributed on an "AS IS" basis,
+ - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ - for the specific language governing rights and limitations under the
+ - License.
+ -
+ - The Original Code is DOM Inspector.
+ -
+ - The Initial Developer of the Original Code is
+ - Mozilla Foundation.
+ - Portions created by the Initial Developer are Copyright (C) 2007
+ - the Initial Developer. All Rights Reserved.
+ -
+ - Contributor(s):
+ - Alexander Surkov <surkov.alexander@gmail.com>
+ -
+ - Alternatively, the contents of this file may be used under the terms of
+ - either the GNU General Public License Version 2 or later (the "GPL"), or
+ - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ - in which case the provisions of the GPL or the LGPL are applicable instead
+ - of those above. If you wish to allow use of your version of this file only
+ - under the terms of either the GPL or the LGPL, and not to allow others to
+ - use your version of this file under the terms of the MPL, indicate your
+ - decision by deleting the provisions above and replace them with the notice
+ - and other provisions required by the LGPL or the GPL. If you do not delete
+ - the provisions above, a recipient may use your version of this file under
+ - the terms of any one of the MPL, the GPL or the LGPL.
+ -
+#endif
+ - ***** END LICENSE BLOCK ***** -->
+
+<!ENTITY role.label "Роль">
+<!ENTITY name.label "Имя">
+<!ENTITY nodeName.label "Имя узла">
+
--- a/gfx/cairo/cairo/src/cairo-malloc-private.h
+++ b/gfx/cairo/cairo/src/cairo-malloc-private.h
@@ -35,70 +35,85 @@
*/
#ifndef CAIRO_MALLOC_PRIVATE_H
#define CAIRO_MALLOC_PRIVATE_H
#include "cairo-wideint-private.h"
/**
+ * _cairo_malloc:
+ * @size: size in bytes
+ *
+ * Allocate @size memory using malloc().
+ * The memory should be freed using free().
+ * malloc is skipped, if 0 bytes are requested, and %NULL will be returned.
+ *
+ * Return value: A pointer to the newly allocated memory, or %NULL in
+ * case of malloc() failure or size is 0.
+ */
+
+#define _cairo_malloc(size) \
+ ((size) ? malloc((unsigned) (size)) : NULL)
+
+/**
* _cairo_malloc_ab:
* @n: number of elements to allocate
* @size: size of each element
*
- * Allocates @a*@size memory using malloc(), taking care to not
+ * Allocates @a*@size memory using _cairo_malloc(), taking care to not
* overflow when doing the multiplication. Behaves much like
* calloc(), except that the returned memory is not set to zero.
* The memory should be freed using free().
*
* @size should be a constant so that the compiler can optimize
* out a constant division.
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or overflow.
*/
#define _cairo_malloc_ab(a, size) \
- ((unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
- malloc((unsigned) (a) * (unsigned) (size)))
+ ((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
+ _cairo_malloc((unsigned) (a) * (unsigned) (size)))
/**
* _cairo_malloc_abc:
* @a: first factor of number of elements to allocate
* @b: second factor of number of elements to allocate
* @size: size of each element
*
- * Allocates @a*@b*@size memory using malloc(), taking care to not
+ * Allocates @a*@b*@size memory using _cairo_malloc(), taking care to not
* overflow when doing the multiplication. Behaves like
* _cairo_malloc_ab(). The memory should be freed using free().
*
* @size should be a constant so that the compiler can optimize
* out a constant division.
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or overflow.
*/
#define _cairo_malloc_abc(a, b, size) \
- ((unsigned) (a) >= INT32_MAX / (unsigned) (b) ? NULL : \
- (unsigned) ((a)*(b)) >= INT32_MAX / (unsigned) (size) ? NULL : \
- malloc((unsigned) (a) * (unsigned) (b) * (unsigned) size))
+ ((b) && (unsigned) (a) >= INT32_MAX / (unsigned) (b) ? NULL : \
+ (size) && (unsigned) ((a)*(b)) >= INT32_MAX / (unsigned) (size) ? NULL : \
+ _cairo_malloc((unsigned) (a) * (unsigned) (b) * (unsigned) (size)))
/**
* _cairo_malloc_ab_plus_c:
* @n: number of elements to allocate
* @size: size of each element
* @k: additional size to allocate
*
- * Allocates @a*@ksize+@k memory using malloc(), taking care to not
+ * Allocates @a*@ksize+@k memory using _cairo_malloc(), taking care to not
* overflow when doing the arithmetic. Behaves like
* _cairo_malloc_ab(). The memory should be freed using free().
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or overflow.
*/
#define _cairo_malloc_ab_plus_c(n, size, k) \
- ((unsigned) (n) >= INT32_MAX / (unsigned) (size) ? NULL : \
+ ((size) && (unsigned) (n) >= INT32_MAX / (unsigned) (size) ? NULL : \
(unsigned) (k) >= INT32_MAX - (unsigned) (n) * (unsigned) (size) ? NULL : \
- malloc((unsigned) (n) * (unsigned) (size) + (unsigned) (k)))
+ _cairo_malloc((unsigned) (n) * (unsigned) (size) + (unsigned) (k)))
#endif /* CAIRO_MALLOC_PRIVATE_H */
--- a/gfx/src/thebes/nsSystemFontsMac.cpp
+++ b/gfx/src/thebes/nsSystemFontsMac.cpp
@@ -138,17 +138,17 @@ nsSystemFontsMac::GetSystemFont(nsSystem
//case eSystemFont_Document: = 'sans-serif'
case eSystemFont_Workspace: fontID = kThemeViewsFont; break;
case eSystemFont_Desktop: fontID = kThemeViewsFont; break;
case eSystemFont_Info: fontID = kThemeViewsFont; break;
case eSystemFont_Dialog: fontID = kThemeSystemFont; break;
case eSystemFont_Button: fontID = kThemeSmallSystemFont; break;
case eSystemFont_PullDownMenu: fontID = kThemeMenuItemFont; break;
case eSystemFont_List: fontID = kThemeSmallSystemFont; break;
- case eSystemFont_Field: fontID = kThemeApplicationFont; break;
+ case eSystemFont_Field: fontID = kThemeSmallSystemFont; break;
// moz
case eSystemFont_Tooltips: fontID = kThemeSmallSystemFont; break;
case eSystemFont_Widget: fontID = kThemeSmallSystemFont; break;
default:
// should never hit this
return NS_ERROR_FAILURE;
}
--- a/gfx/thebes/src/gfxFont.cpp
+++ b/gfx/thebes/src/gfxFont.cpp
@@ -342,17 +342,19 @@ gfxFont::Measure(gfxTextRun *aTextRun,
floatAdvance += aSpacing[i].mBefore + aSpacing[i].mAfter;
}
}
RunMetrics metrics;
const gfxFont::Metrics& fontMetrics = GetMetrics();
metrics.mAdvanceWidth = floatAdvance;
const PRUint32 appUnitsPerDevUnit = aTextRun->GetAppUnitsPerDevUnit();
metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
- metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit;
+ gfxFloat descentForUnderline =
+ NS_round(fontMetrics.underlineSize) + NS_round(metrics.mAscent - fontMetrics.underlineOffset) - metrics.mAscent;
+ metrics.mDescent = PR_MAX(fontMetrics.maxDescent, descentForUnderline)*appUnitsPerDevUnit;
metrics.mBoundingBox =
gfxRect(0, -metrics.mAscent, floatAdvance, metrics.mAscent + metrics.mDescent);
return metrics;
}
gfxFontGroup::gfxFontGroup(const nsAString& aFamilies, const gfxFontStyle *aStyle)
: mFamilies(aFamilies), mStyle(*aStyle)
{
--- a/gfx/thebes/src/gfxWindowsFonts.cpp
+++ b/gfx/thebes/src/gfxWindowsFonts.cpp
@@ -75,21 +75,24 @@
#include "prlog.h"
static PRLogModuleInfo *gFontLog = PR_NewLogModule("winfonts");
#define ROUND(x) floor((x) + 0.5)
struct DCFromContext {
DCFromContext(gfxContext *aContext) {
+ dc = NULL;
nsRefPtr<gfxASurface> aSurface = aContext->CurrentSurface();
- if (aSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
+ NS_ASSERTION(aSurface, "DCFromContext: null surface");
+ if (aSurface && aSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
dc = static_cast<gfxWindowsSurface*>(aSurface.get())->GetDC();
needsRelease = PR_FALSE;
- } else {
+ }
+ if (!dc) {
dc = GetDC(NULL);
needsRelease = PR_TRUE;
}
}
~DCFromContext() {
if (needsRelease)
ReleaseDC(NULL, dc);
--- a/intl/build/Makefile.in
+++ b/intl/build/Makefile.in
@@ -111,8 +111,11 @@ CXXFLAGS += \
$(MOZ_PANGO_CFLAGS) \
$(NULL)
EXTRA_DSO_LDOPTS += \
$(MOZ_PANGO_LIBS) \
$(NULL)
endif
+ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
+OS_LIBS += $(call EXPAND_LIBNAME,usp10)
+endif
--- a/intl/locale/src/nsLocaleService.cpp
+++ b/intl/locale/src/nsLocaleService.cpp
@@ -294,31 +294,36 @@ nsLocaleService::~nsLocaleService(void)
{
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsLocaleService, nsILocaleService)
NS_IMETHODIMP
nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
{
- int i;
- nsresult result;
+ nsresult result;
- *_retval = (nsILocale*)nsnull;
-
- nsLocale* resultLocale = new nsLocale();
- if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
+ *_retval = nsnull;
+
+ nsLocale* resultLocale = new nsLocale();
+ if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
- for(i=0;i<LocaleListLength;i++) {
- nsString category; category.AssignWithConversion(LocaleList[i]);
- result = resultLocale->AddCategory(category, aLocale);
- if (NS_FAILED(result)) { delete resultLocale; return result;}
- }
+ for (PRInt32 i = 0; i < LocaleListLength; i++) {
+ nsString category; category.AssignWithConversion(LocaleList[i]);
+ result = resultLocale->AddCategory(category, aLocale);
+ if (NS_FAILED(result)) { delete resultLocale; return result;}
+#if (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_BEOS)
+ category.AppendLiteral("##PLATFORM");
+ result = resultLocale->AddCategory(category, aLocale);
+ if (NS_FAILED(result)) { delete resultLocale; return result;}
+#endif
+ }
- return resultLocale->QueryInterface(NS_GET_IID(nsILocale),(void**)_retval);
+ NS_ADDREF(*_retval = resultLocale);
+ return NS_OK;
}
NS_IMETHODIMP
nsLocaleService::GetSystemLocale(nsILocale **_retval)
{
if (mSystemLocale) {
NS_ADDREF(*_retval = mSystemLocale);
--- a/intl/lwbrk/src/Makefile.in
+++ b/intl/lwbrk/src/Makefile.in
@@ -58,27 +58,38 @@ CPPSRCS = \
nsSemanticUnitScanner.cpp \
$(NULL)
ifdef MOZ_ENABLE_PANGO
CPPSRCS += \
nsPangoBreaker.cpp \
$(NULL)
else
+ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
CPPSRCS += \
- nsRuleBreaker.cpp \
+ nsUniscribeBreaker.cpp \
+ $(NULL)
+else
+ifeq ($(MOZ_WIDGET_TOOLKIT), cocoa)
+CPPSRCS += \
+ nsCarbonBreaker.cpp \
+ $(NULL)
+else
+CPPSRCS += \
+ nsRuleBreaker.cpp \
$(NULL)
CSRCS = rulebrk.c
endif
+endif
+endif
include $(topsrcdir)/config/rules.mk
ifdef MOZ_ENABLE_PANGO
CXXFLAGS += \
$(MOZ_PANGO_CFLAGS) \
$(NULL)
EXTRA_DSO_LDOPTS += \
$(MOZ_PANGO_LIBS) \
$(NULL)
endif
-
new file mode 100755
--- /dev/null
+++ b/intl/lwbrk/src/nsCarbonBreaker.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Vee Satayamas <vsatayamas@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * - Vee Satayamas <vsatayamas@gmail.com>
+ * - Patipat Susumpow <kengggg@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsComplexBreaker.h"
+#include <Carbon/Carbon.h>
+
+void
+NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
+ PRPackedBool* aBreakBefore)
+{
+ NS_ASSERTION(aText, "aText shouldn't be null");
+ TextBreakLocatorRef breakLocator;
+
+ memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRPackedBool));
+
+ OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakLineMask, &breakLocator);
+
+ if (status != noErr)
+ return;
+
+ for (UniCharArrayOffset position = 0; position < aLength;) {
+ UniCharArrayOffset offset;
+ status = UCFindTextBreak(breakLocator,
+ kUCTextBreakLineMask,
+ position == 0 ? kUCTextBreakLeadingEdgeMask :
+ (kUCTextBreakLeadingEdgeMask |
+ kUCTextBreakIterateMask),
+ aText,
+ aLength,
+ position,
+ &offset);
+ if (status != noErr)
+ break;
+ aBreakBefore[offset] = PR_TRUE;
+ position = offset;
+ }
+ UCDisposeTextBreakLocator(&breakLocator);
+}
new file mode 100755
--- /dev/null
+++ b/intl/lwbrk/src/nsUniscribeBreaker.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Pattara Kiatisevi <ott@linux.thai.net>.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * - Nattachai Ungsriwong <nattachai@gmail.com>
+ * - Theppitak Karoonboonyanan <thep@linux.thai.net>
+ * - Vee Satayamas <vsatayamas@gmail.com>
+ * - Pattara Kiatisevi <ott@linux.thai.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsComplexBreaker.h"
+
+#include <Usp10.h>
+#include "nsUTF8Utils.h"
+#include "nsString.h"
+#include "nsTArray.h"
+
+void
+NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
+ PRPackedBool* aBreakBefore)
+{
+ NS_ASSERTION(aText, "aText shouldn't be null");
+ int outItems = 0;
+ HRESULT result;
+ nsAutoTArray<SCRIPT_ITEM, 64> items;
+
+ memset(aBreakBefore, PR_FALSE, aLength);
+
+ if (!items.AppendElements(64))
+ return;
+
+ do {
+ result = ScriptItemize(aText, aLength, items.Length(), NULL, NULL, items.Elements(), &outItems);
+
+ if (result == E_OUTOFMEMORY) {
+ if (!items.AppendElements(items.Length()))
+ return;
+ }
+ } while (result == E_OUTOFMEMORY);
+
+ for (int iItem = 0; iItem < outItems; ++iItem) {
+ PRUint32 endOffset = (iItem + 1 == outItems ? aLength : items[iItem + 1].iCharPos);
+ PRUint32 startOffset = items[iItem].iCharPos;
+ nsAutoTArray<SCRIPT_LOGATTR, 64> sla;
+
+ if (!sla.AppendElements(endOffset - startOffset))
+ return;
+
+ if (ScriptBreak(aText, aLength, &items[iItem].a, sla.Elements()) < 0)
+ return;
+
+ for (PRUint32 j=0; j+startOffset < endOffset; ++j) {
+ aBreakBefore[j+startOffset] = sla[j].fSoftBreak;
+ }
+ }
+
+}
--- a/js/src/js.cpp
+++ b/js/src/js.cpp
@@ -961,19 +961,19 @@ UpdateSwitchTableBounds(JSScript *script
static void
SrcNotes(JSContext *cx, JSScript *script)
{
uintN offset, delta, caseOff, switchTableStart, switchTableEnd;
jssrcnote *notes, *sn;
JSSrcNoteType type;
const char *name;
- jsatomid atomIndex;
uint32 index;
JSAtom *atom;
+ JSString *str;
fprintf(gOutFile, "\nSource notes:\n");
offset = 0;
notes = SCRIPT_NOTES(script);
switchTableEnd = switchTableStart = 0;
for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
delta = SN_DELTA(sn);
offset += delta;
@@ -1010,30 +1010,29 @@ SrcNotes(JSContext *cx, JSScript *script
case SRC_PCDELTA:
case SRC_DECL:
case SRC_BRACE:
fprintf(gOutFile, " offset %u", (uintN) js_GetSrcNoteOffset(sn, 0));
break;
case SRC_LABEL:
case SRC_LABELBRACE:
case SRC_BREAK2LABEL:
- case SRC_CONT2LABEL: {
- const char *bytes;
-
- atomIndex = (jsatomid) js_GetSrcNoteOffset(sn, 0);
- JS_GET_SCRIPT_ATOM(script, atomIndex, atom);
- bytes = js_AtomToPrintableString(cx, atom);
- fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, bytes);
+ case SRC_CONT2LABEL:
+ index = js_GetSrcNoteOffset(sn, 0);
+ JS_GET_SCRIPT_ATOM(script, index, atom);
+ JS_ASSERT(ATOM_IS_STRING(atom));
+ str = ATOM_TO_STRING(atom);
+ fprintf(gOutFile, " atom %u (", index);
+ js_FileEscapedString(gOutFile, str, 0);
+ putc(')', gOutFile);
break;
- }
case SRC_FUNCDEF: {
const char *bytes;
JSObject *obj;
JSFunction *fun;
- JSString *str;
index = js_GetSrcNoteOffset(sn, 0);
JS_GET_SCRIPT_OBJECT(script, index, obj);
fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj);
str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
bytes = str ? JS_GetStringBytes(str) : "N/A";
fprintf(gOutFile, " function %u (%s)", index, bytes);
break;
@@ -1268,33 +1267,45 @@ Tracing(JSContext *cx, JSObject *obj, ui
}
static void
DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
{
uintN i;
JSScope *scope;
JSScopeProperty *sprop;
+ jsval v;
+ JSString *str;
i = 0;
scope = OBJ_SCOPE(obj);
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
continue;
- fprintf(fp, "%3u %p", i, (void *)sprop);
+ fprintf(fp, "%3u %p ", i, (void *)sprop);
+
+ v = ID_TO_VALUE(sprop->id);
if (JSID_IS_INT(sprop->id)) {
- fprintf(fp, " [%ld]", (long)JSVAL_TO_INT(sprop->id));
- } else if (JSID_IS_ATOM(sprop->id)) {
- JSAtom *atom = JSID_TO_ATOM(sprop->id);
- fprintf(fp, " \"%s\"", js_AtomToPrintableString(cx, atom));
+ fprintf(fp, "[%ld]", (long)JSVAL_TO_INT(v));
} else {
- jsval v = OBJECT_TO_JSVAL(JSID_TO_OBJECT(sprop->id));
- fprintf(fp, " \"%s\"", js_ValueToPrintableString(cx, v));
+ if (JSID_IS_ATOM(sprop->id)) {
+ str = JSVAL_TO_STRING(v);
+ } else if (JSID_IS_HIDDEN(sprop->id)) {
+ str = JSVAL_TO_STRING(v);
+ fputs("hidden ", fp);
+ } else {
+ JS_ASSERT(JSID_IS_OBJECT(sprop->id));
+ str = js_ValueToString(cx, v);
+ fputs("object ", fp);
+ }
+ if (!str)
+ fputs("<error>", fp);
+ else
+ js_FileEscapedString(fp, str, '"');
}
-
#define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp)
DUMP_ATTR(ENUMERATE);
DUMP_ATTR(READONLY);
DUMP_ATTR(PERMANENT);
DUMP_ATTR(EXPORTED);
DUMP_ATTR(GETTER);
DUMP_ATTR(SETTER);
#undef DUMP_ATTR
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1435,20 +1435,22 @@ JS_ResolveStandardClass(JSContext *cx, J
JSRuntime *rt;
JSAtom *atom;
JSStdName *stdnm;
uintN i;
CHECK_REQUEST(cx);
*resolved = JS_FALSE;
- if (!JSVAL_IS_STRING(id))
+ rt = cx->runtime;
+ JS_ASSERT(rt->state != JSRTS_DOWN);
+ if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id))
return JS_TRUE;
+
idstr = JSVAL_TO_STRING(id);
- rt = cx->runtime;
/* Check whether we're resolving 'undefined', and define it if so. */
atom = rt->atomState.typeAtoms[JSTYPE_VOID];
if (idstr == ATOM_TO_STRING(atom)) {
*resolved = JS_TRUE;
return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,
NULL, NULL, JSPROP_PERMANENT, NULL);
}
@@ -1959,20 +1961,16 @@ JS_PrintTraceThingInfo(char *buf, size_t
case JSTRACE_DOUBLE:
name = "double";
break;
case JSTRACE_FUNCTION:
name = "function";
break;
- case JSTRACE_ATOM:
- name = "atom";
- break;
-
#if JS_HAS_XML_SUPPORT
case JSTRACE_NAMESPACE:
name = "namespace";
break;
case JSTRACE_QNAME:
name = "qname";
break;
@@ -2023,48 +2021,35 @@ JS_PrintTraceThingInfo(char *buf, size_t
{
JSFunction *fun = (JSFunction *)thing;
if (fun->atom && ATOM_IS_STRING(fun->atom))
js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0);
break;
}
- case JSTRACE_ATOM:
- {
- JSAtom *atom = (JSAtom *)thing;
-
- if (ATOM_IS_INT(atom))
- JS_snprintf(buf, bufsize, "%d", ATOM_TO_INT(atom));
- else if (ATOM_IS_STRING(atom))
- js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(atom), 0);
- else
- JS_snprintf(buf, bufsize, "object");
- break;
- }
-
#if JS_HAS_XML_SUPPORT
- case GCX_NAMESPACE:
+ case JSTRACE_NAMESPACE:
{
JSXMLNamespace *ns = (JSXMLNamespace *)thing;
if (ns->prefix) {
n = js_PutEscapedString(buf, bufsize, ns->prefix, 0);
buf += n;
bufsize -= n;
}
if (bufsize > 2) {
*buf++ = ':';
bufsize--;
js_PutEscapedString(buf, bufsize, ns->uri, 0);
}
break;
}
- case GCX_QNAME:
+ case JSTRACE_QNAME:
{
JSXMLQName *qn = (JSXMLQName *)thing;
if (qn->prefix) {
n = js_PutEscapedString(buf, bufsize, qn->prefix, 0);
buf += n;
bufsize -= n;
}
@@ -2079,17 +2064,17 @@ JS_PrintTraceThingInfo(char *buf, size_t
*buf++ = ':';
bufsize -= 2;
js_PutEscapedString(buf, bufsize, qn->localName, 0);
}
}
break;
}
- case GCX_XML:
+ case JSTRACE_XML:
{
extern const char *js_xml_class_str[];
JSXML *xml = (JSXML *)thing;
JS_snprintf(buf, bufsize, "%s", js_xml_class_str[xml->xml_class]);
break;
}
#endif
@@ -2525,29 +2510,28 @@ JS_NewExternalString(JSContext *cx, jsch
JSString *str;
CHECK_REQUEST(cx);
JS_ASSERT(GCX_EXTERNAL_STRING <= type && type < (intN) GCX_NTYPES);
str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
if (!str)
return NULL;
- str->length = length;
- str->chars = chars;
+ JSSTRING_INIT(str, chars, length);
return str;
}
JS_PUBLIC_API(intN)
JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
{
uint8 type = (uint8) (*js_GetGCThingFlags(str) & GCF_TYPEMASK);
if (type >= GCX_EXTERNAL_STRING)
return (intN)type;
- JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
+ JS_ASSERT(type == GCX_STRING);
return -1;
}
JS_PUBLIC_API(void)
JS_SetThreadStackLimit(JSContext *cx, jsuword limitAddr)
{
#if JS_STACK_GROWTH_DIRECTION > 0
if (limitAddr == 0)
@@ -2892,17 +2876,17 @@ JS_GetConstructor(JSContext *cx, JSObjec
return NULL;
}
return JSVAL_TO_OBJECT(cval);
}
JS_PUBLIC_API(JSBool)
JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
{
- JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
+ JS_ASSERT(JSID_IS_OBJECT(obj));
*idp = OBJECT_TO_JSID(obj);
return JS_TRUE;
}
JS_PUBLIC_API(JSObject *)
JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
{
CHECK_REQUEST(cx);
@@ -5038,17 +5022,17 @@ JS_NewString(JSContext *cx, char *bytes,
CHECK_REQUEST(cx);
/* Make a UTF-16 vector from the 8-bit char codes in bytes. */
chars = js_InflateString(cx, bytes, &length);
if (!chars)
return NULL;
/* Free chars (but not bytes, which caller frees on error) if we fail. */
- str = js_NewString(cx, chars, length, 0);
+ str = js_NewString(cx, chars, length);
if (!str) {
JS_free(cx, chars);
return NULL;
}
/* Hand off bytes to the deflated string cache, if possible. */
if (!js_SetStringBytes(cx, str, bytes, nbytes))
JS_free(cx, bytes);
@@ -5060,17 +5044,17 @@ JS_NewStringCopyN(JSContext *cx, const c
{
jschar *js;
JSString *str;
CHECK_REQUEST(cx);
js = js_InflateString(cx, s, &n);
if (!js)
return NULL;
- str = js_NewString(cx, js, n, 0);
+ str = js_NewString(cx, js, n);
if (!str)
JS_free(cx, js);
return str;
}
JS_PUBLIC_API(JSString *)
JS_NewStringCopyZ(JSContext *cx, const char *s)
{
@@ -5080,17 +5064,17 @@ JS_NewStringCopyZ(JSContext *cx, const c
CHECK_REQUEST(cx);
if (!s)
return cx->runtime->emptyString;
n = strlen(s);
js = js_InflateString(cx, s, &n);
if (!js)
return NULL;
- str = js_NewString(cx, js, n, 0);
+ str = js_NewString(cx, js, n);
if (!str)
JS_free(cx, js);
return str;
}
JS_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s)
{
@@ -5102,17 +5086,17 @@ JS_InternString(JSContext *cx, const cha
return NULL;
return ATOM_TO_STRING(atom);
}
JS_PUBLIC_API(JSString *)
JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
{
CHECK_REQUEST(cx);
- return js_NewString(cx, chars, length, 0);
+ return js_NewString(cx, chars, length);
}
JS_PUBLIC_API(JSString *)
JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n)
{
CHECK_REQUEST(cx);
return js_NewStringCopyN(cx, s, n);
}
@@ -5172,25 +5156,27 @@ JS_GetStringChars(JSString *str)
* rate bugs in string concatenation, is worth this slight loss in API
* compatibility.
*/
if (JSSTRING_IS_DEPENDENT(str)) {
n = JSSTRDEP_LENGTH(str);
size = (n + 1) * sizeof(jschar);
s = (jschar *) malloc(size);
if (s) {
- js_strncpy(s, JSSTRDEP_CHARS(str), n);
+ memcpy(s, JSSTRDEP_CHARS(str), n * sizeof *s);
s[n] = 0;
- str->length = n;
- str->chars = s;
+ JSSTRING_INIT(str, s, n);
+ } else {
+ s = JSSTRDEP_CHARS(str);
}
+ } else {
+ JSSTRING_CLEAR_MUTABLE(str);
+ s = str->u.chars;
}
-
- *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
- return JSSTRING_CHARS(str);
+ return s;
}
JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str)
{
return JSSTRING_LENGTH(str);
}
@@ -5198,18 +5184,24 @@ JS_PUBLIC_API(intN)
JS_CompareStrings(JSString *str1, JSString *str2)
{
return js_CompareStrings(str1, str2);
}
JS_PUBLIC_API(JSString *)
JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
{
+ JSString *str;
+
CHECK_REQUEST(cx);
- return js_NewString(cx, chars, length, GCF_MUTABLE);
+ str = js_NewString(cx, chars, length);
+ if (!str)
+ return str;
+ JSSTRING_SET_MUTABLE(str);
+ return str;
}
JS_PUBLIC_API(JSString *)
JS_NewDependentString(JSContext *cx, JSString *str, size_t start,
size_t length)
{
CHECK_REQUEST(cx);
return js_NewDependentString(cx, str, start, length);
@@ -5228,21 +5220,17 @@ JS_UndependString(JSContext *cx, JSStrin
CHECK_REQUEST(cx);
return js_UndependString(cx, str);
}
JS_PUBLIC_API(JSBool)
JS_MakeStringImmutable(JSContext *cx, JSString *str)
{
CHECK_REQUEST(cx);
- if (!js_UndependString(cx, str))
- return JS_FALSE;
-
- *js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
- return JS_TRUE;
+ return js_MakeStringImmutable(cx, str);
}
JS_PUBLIC_API(JSBool)
JS_EncodeCharacters(JSContext *cx, const jschar *src, size_t srclen, char *dst,
size_t *dstlenp)
{
size_t n;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -597,18 +597,17 @@ array_join_sub(JSContext *cx, JSObject *
*rval = JS_GetEmptyStringValue(cx);
return ok;
}
/* Flag he as BUSY so we can distinguish a cycle from a join-point. */
MAKE_BUSY(he);
if (sep) {
- sepstr = JSSTRING_CHARS(sep);
- seplen = JSSTRING_LENGTH(sep);
+ JSSTRING_CHARS_AND_LENGTH(sep, sepstr, seplen);
} else {
sepstr = NULL; /* indicates to use "," as separator */
seplen = 1;
}
}
/* Use rval to locally root each element value as we loop and convert. */
for (index = 0; index < length; index++) {
@@ -710,17 +709,17 @@ array_join_sub(JSContext *cx, JSObject *
make_string:
if (!chars) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
}
chars[nchars] = 0;
JS_ASSERT(growth == (size_t)-1 || (nchars + 1) * sizeof(jschar) == growth);
- str = js_NewString(cx, chars, nchars, 0);
+ str = js_NewString(cx, chars, nchars);
if (!str) {
free(chars);
return JS_FALSE;
}
*rval = STRING_TO_JSVAL(str);
return JS_TRUE;
}
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -207,446 +207,488 @@ const char js_send_str[] = "s
#ifdef NARCISSUS
const char js_call_str[] = "__call__";
const char js_construct_str[] = "__construct__";
const char js_hasInstance_str[] = "__hasInstance__";
const char js_ExecutionContext_str[] = "ExecutionContext";
const char js_current_str[] = "current";
#endif
-#define HASH_DOUBLE(dp) ((JSDOUBLE_HI32(*dp) ^ JSDOUBLE_LO32(*dp)))
+/*
+ * JSAtomState.doubleAtoms and JSAtomState.stringAtoms hashtable entry. To
+ * support pinned and interned string atoms, we use the lowest bits of the
+ * keyAndFlags field to store ATOM_PINNED and ATOM_INTERNED flags.
+ */
+typedef struct JSAtomHashEntry {
+ JSDHashEntryHdr hdr;
+ jsuword keyAndFlags;
+} JSAtomHashEntry;
-JS_STATIC_DLL_CALLBACK(JSHashNumber)
-js_hash_atom_key(const void *key)
-{
- jsval v;
- jsdouble *dp;
+#define ATOM_ENTRY_FLAG_MASK (ATOM_PINNED | ATOM_INTERNED)
+
+JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JSVAL_ALIGN);
- v = (jsval)key;
- if (JSVAL_IS_STRING(v))
- return js_HashString(JSVAL_TO_STRING(v));
- if (JSVAL_IS_DOUBLE(v)) {
- dp = JSVAL_TO_DOUBLE(v);
- return HASH_DOUBLE(dp);
- }
- JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
- v == JSVAL_NULL || v == JSVAL_VOID);
- return (JSHashNumber)v;
+/*
+ * Helper macros to access and modify JSAtomHashEntry.
+ */
+#define TO_ATOM_ENTRY(hdr) ((JSAtomHashEntry *) hdr)
+#define ATOM_ENTRY_KEY(entry) \
+ ((void *)((entry)->keyAndFlags & ~ATOM_ENTRY_FLAG_MASK))
+#define ATOM_ENTRY_FLAGS(entry) \
+ ((uintN)((entry)->keyAndFlags & ATOM_ENTRY_FLAG_MASK))
+#define INIT_ATOM_ENTRY(entry, key) \
+ ((void)((entry)->keyAndFlags = (jsuword)(key)))
+#define ADD_ATOM_ENTRY_FLAGS(entry, flags) \
+ ((void)((entry)->keyAndFlags |= (jsuword)(flags)))
+#define CLEAR_ATOM_ENTRY_FLAGS(entry, flags) \
+ ((void)((entry)->keyAndFlags &= ~(jsuword)(flags)))
+
+static const JSDHashTableOps DoubleHashOps;
+static const JSDHashTableOps StringHashOps;
+
+#define IS_DOUBLE_TABLE(table) ((table)->ops == &DoubleHashOps)
+#define IS_STRING_TABLE(table) ((table)->ops == &StringHashOps)
+
+#define IS_INITIALIZED_STATE(state) IS_DOUBLE_TABLE(&(state)->doubleAtoms)
+
+JS_STATIC_DLL_CALLBACK(JSDHashNumber)
+HashDouble(JSDHashTable *table, const void *key)
+{
+ jsdouble d;
+
+ JS_ASSERT(IS_DOUBLE_TABLE(table));
+ d = *(jsdouble *)key;
+ return JSDOUBLE_HI32(d) ^ JSDOUBLE_LO32(d);
}
-JS_STATIC_DLL_CALLBACK(intN)
-js_compare_atom_keys(const void *k1, const void *k2)
+JS_STATIC_DLL_CALLBACK(JSDHashNumber)
+HashString(JSDHashTable *table, const void *key)
{
- jsval v1, v2;
-
- v1 = (jsval)k1, v2 = (jsval)k2;
- if (JSVAL_IS_STRING(v1) && JSVAL_IS_STRING(v2))
- return js_EqualStrings(JSVAL_TO_STRING(v1), JSVAL_TO_STRING(v2));
- if (JSVAL_IS_DOUBLE(v1) && JSVAL_IS_DOUBLE(v2)) {
- double d1 = *JSVAL_TO_DOUBLE(v1);
- double d2 = *JSVAL_TO_DOUBLE(v2);
- if (JSDOUBLE_IS_NaN(d1))
- return JSDOUBLE_IS_NaN(d2);
-#if defined(XP_WIN)
- /* XXX MSVC miscompiles such that (NaN == 0) */
- if (JSDOUBLE_IS_NaN(d2))
- return JS_FALSE;
-#endif
- return d1 == d2;
- }
- return v1 == v2;
+ JS_ASSERT(IS_STRING_TABLE(table));
+ return js_HashString((JSString *)key);
}
-JS_STATIC_DLL_CALLBACK(int)
-js_compare_stub(const void *v1, const void *v2)
+JS_STATIC_DLL_CALLBACK(JSBool)
+MatchDouble(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key)
{
- return 1;
-}
+ JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+ jsdouble d1, d2;
-/* These next two are exported to jsscript.c and used similarly there. */
-void * JS_DLL_CALLBACK
-js_alloc_table_space(void *priv, size_t size)
-{
- return malloc(size);
-}
+ JS_ASSERT(IS_DOUBLE_TABLE(table));
+ if (entry->keyAndFlags == 0) {
+ /* See comments in MatchString. */
+ return JS_FALSE;
+ }
-void JS_DLL_CALLBACK
-js_free_table_space(void *priv, void *item)
-{
- free(item);
+ d1 = *(jsdouble *)ATOM_ENTRY_KEY(entry);
+ d2 = *(jsdouble *)key;
+ if (JSDOUBLE_IS_NaN(d1))
+ return JSDOUBLE_IS_NaN(d2);
+#if defined(XP_WIN)
+ /* XXX MSVC miscompiles such that (NaN == 0) */
+ if (JSDOUBLE_IS_NaN(d2))
+ return JS_FALSE;
+#endif
+ return d1 == d2;
}
-JS_STATIC_DLL_CALLBACK(JSHashEntry *)
-js_alloc_atom(void *priv, const void *key)
+JS_STATIC_DLL_CALLBACK(JSBool)
+MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key)
{
- JSAtom *atom;
+ JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
- atom = (JSAtom *) malloc(sizeof(JSAtom));
- if (!atom)
- return NULL;
- ((JSAtomState *)priv)->tablegen++;
- atom->entry.key = key;
- atom->entry.value = NULL;
- atom->flags = 0;
- return &atom->entry;
+ JS_ASSERT(IS_STRING_TABLE(table));
+ if (entry->keyAndFlags == 0) {
+ /*
+ * This happens when js_AtomizeString adds a new hash entry and
+ * releases the lock but before it takes the lock the second time to
+ * initialize keyAndFlags for the entry.
+ *
+ * We always return false for such entries so JS_DHashTableOperate
+ * never finds them. We clean them during GC's sweep phase.
+ *
+ * It means that with a contested lock or when GC is triggered outside
+ * the lock we may end up adding two entries, but this is a price for
+ * simpler code.
+ */
+ return JS_FALSE;
+ }
+ return js_EqualStrings((JSString *)ATOM_ENTRY_KEY(entry), (JSString *)key);
}
-JS_STATIC_DLL_CALLBACK(void)
-js_free_atom(void *priv, JSHashEntry *he, uintN flag)
-{
- if (flag != HT_FREE_ENTRY)
- return;
- ((JSAtomState *)priv)->tablegen++;
- free(he);
-}
-
-static JSHashAllocOps atom_alloc_ops = {
- js_alloc_table_space, js_free_table_space,
- js_alloc_atom, js_free_atom
+static const JSDHashTableOps DoubleHashOps = {
+ JS_DHashAllocTable,
+ JS_DHashFreeTable,
+ HashDouble,
+ MatchDouble,
+ JS_DHashMoveEntryStub,
+ JS_DHashClearEntryStub,
+ JS_DHashFinalizeStub,
+ NULL
};
-#define JS_ATOM_HASH_SIZE 1024
+static const JSDHashTableOps StringHashOps = {
+ JS_DHashAllocTable,
+ JS_DHashFreeTable,
+ HashString,
+ MatchString,
+ JS_DHashMoveEntryStub,
+ JS_DHashClearEntryStub,
+ JS_DHashFinalizeStub,
+ NULL
+};
+
+/*
+ * For a browser build from 2007-08-09 after the browser starts up there are
+ * just 55 double atoms, but over 15000 string atoms. Not to penalize more
+ * economical embeddings allocating too much memory initially we initialize
+ * atomized strings with just 1K entries.
+ */
+#define JS_STRING_HASH_COUNT 1024
+#define JS_DOUBLE_HASH_COUNT 64
JSBool
js_InitAtomState(JSRuntime *rt)
{
JSAtomState *state = &rt->atomState;
/*
* The caller must zero the state before calling this function.
*/
- JS_ASSERT(!state->table);
+ JS_ASSERT(!state->stringAtoms.ops);
+ JS_ASSERT(!state->doubleAtoms.ops);
JS_ASSERT(state->tablegen == 0);
- state->table = JS_NewHashTable(JS_ATOM_HASH_SIZE, js_hash_atom_key,
- js_compare_atom_keys, js_compare_stub,
- &atom_alloc_ops, state);
- if (!state->table)
+ if (!JS_DHashTableInit(&state->stringAtoms, &StringHashOps,
+ NULL, sizeof(JSAtomHashEntry),
+ JS_DHASH_DEFAULT_CAPACITY(JS_STRING_HASH_COUNT))) {
+ state->stringAtoms.ops = NULL;
return JS_FALSE;
+ }
+ JS_ASSERT(IS_STRING_TABLE(&state->stringAtoms));
+
+ if (!JS_DHashTableInit(&state->doubleAtoms, &DoubleHashOps,
+ NULL, sizeof(JSAtomHashEntry),
+ JS_DHASH_DEFAULT_CAPACITY(JS_DOUBLE_HASH_COUNT))) {
+ state->doubleAtoms.ops = NULL;
+ JS_DHashTableFinish(&state->stringAtoms);
+ state->stringAtoms.ops = NULL;
+ return JS_FALSE;
+ }
+ JS_ASSERT(IS_DOUBLE_TABLE(&state->doubleAtoms));
#ifdef JS_THREADSAFE
js_InitLock(&state->lock);
#endif
+ JS_ASSERT(IS_INITIALIZED_STATE(state));
return JS_TRUE;
}
-JS_STATIC_DLL_CALLBACK(intN)
-js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_string_uninterner(JSDHashTable *table, JSDHashEntryHdr *hdr,
+ uint32 number, void *arg)
{
- JSAtom *atom;
- JSRuntime *rt;
+ JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+ JSRuntime *rt = (JSRuntime *)arg;
- atom = (JSAtom *)he;
- rt = (JSRuntime *)arg;
- if (ATOM_IS_STRING(atom))
- js_FinalizeStringRT(rt, ATOM_TO_STRING(atom));
- return HT_ENUMERATE_NEXT;
+ /*
+ * Any string entry that remains at this point must be initialized, as the
+ * last GC should clean any uninitialized ones.
+ */
+ JS_ASSERT(IS_STRING_TABLE(table));
+ JS_ASSERT(entry->keyAndFlags != 0);
+ js_FinalizeStringRT(rt, (JSString *)ATOM_ENTRY_KEY(entry));
+ return JS_DHASH_NEXT;
}
void
js_FinishAtomState(JSRuntime *rt)
{
JSAtomState *state = &rt->atomState;
- if (!state->table) {
+ if (!IS_INITIALIZED_STATE(state)) {
/*
- * state->table is null when JS_NewRuntime fails and calls
- * JS_DestroyRuntime on a partially initialized runtime.
+ * We are called with uninitialized state when JS_NewRuntime fails and
+ * calls JS_DestroyRuntime on a partially initialized runtime.
*/
return;
}
- JS_HashTableEnumerateEntries(state->table, js_atom_uninterner, rt);
- JS_HashTableDestroy(state->table);
+ JS_DHashTableEnumerate(&state->stringAtoms, js_string_uninterner, rt);
+ JS_DHashTableFinish(&state->stringAtoms);
+ JS_DHashTableFinish(&state->doubleAtoms);
+
#ifdef JS_THREADSAFE
js_FinishLock(&state->lock);
#endif
#ifdef DEBUG
memset(state, JS_FREE_PATTERN, sizeof *state);
#endif
}
JSBool
js_InitCommonAtoms(JSContext *cx)
{
JSAtomState *state = &cx->runtime->atomState;
uintN i;
JSAtom **atoms;
- atoms = (JSAtom **)((uint8 *)state + ATOM_OFFSET_START);
+ atoms = COMMON_ATOMS_START(state);
for (i = 0; i < JS_ARRAY_LENGTH(js_common_atom_names); i++, atoms++) {
*atoms = js_Atomize(cx, js_common_atom_names[i],
strlen(js_common_atom_names[i]), ATOM_PINNED);
if (!*atoms)
return JS_FALSE;
}
JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START);
memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START);
return JS_TRUE;
}
-JS_STATIC_DLL_CALLBACK(intN)
-js_atom_unpinner(JSHashEntry *he, intN i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_atom_unpinner(JSDHashTable *table, JSDHashEntryHdr *hdr,
+ uint32 number, void *arg)
{
- JSAtom *atom;
-
- atom = (JSAtom *)he;
- atom->flags &= ~ATOM_PINNED;
- return HT_ENUMERATE_NEXT;
+ JS_ASSERT(IS_STRING_TABLE(table));
+ CLEAR_ATOM_ENTRY_FLAGS(TO_ATOM_ENTRY(hdr), ATOM_PINNED);
+ return JS_DHASH_NEXT;
}
void
js_FinishCommonAtoms(JSContext *cx)
{
JSAtomState *state = &cx->runtime->atomState;
- JS_HashTableEnumerateEntries(state->table, js_atom_unpinner, NULL);
+ JS_DHashTableEnumerate(&state->stringAtoms, js_atom_unpinner, NULL);
#ifdef DEBUG
- memset((uint8 *)state + ATOM_OFFSET_START, JS_FREE_PATTERN,
+ memset(COMMON_ATOMS_START(state), JS_FREE_PATTERN,
ATOM_OFFSET_LIMIT - ATOM_OFFSET_START);
#endif
}
-void
-js_TraceAtom(JSTracer *trc, JSAtom *atom)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_locked_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
+ uint32 number, void *arg)
{
- jsval key;
+ JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+ JSTracer *trc = (JSTracer *)arg;
- key = ATOM_KEY(atom);
- JS_CALL_VALUE_TRACER(trc, key, "key");
- if (atom->flags & ATOM_HIDDEN)
- JS_CALL_TRACER(trc, atom->entry.value, JSTRACE_ATOM, "hidden");
+ if (entry->keyAndFlags == 0) {
+ /* Ignore uninitialized entries during tracing. */
+ return JS_DHASH_NEXT;
+ }
+ JS_SET_TRACING_INDEX(trc, "locked_atom", (size_t)number);
+ JS_CallTracer(trc, ATOM_ENTRY_KEY(entry),
+ IS_STRING_TABLE(table) ? JSTRACE_STRING : JSTRACE_DOUBLE);
+ return JS_DHASH_NEXT;
}
-typedef struct TraceArgs {
- JSBool allAtoms;
- JSTracer *trc;
-} TraceArgs;
-
-JS_STATIC_DLL_CALLBACK(intN)
-js_locked_atom_tracer(JSHashEntry *he, intN i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_pinned_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
+ uint32 number, void *arg)
{
- JSAtom *atom;
- TraceArgs *args;
+ JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+ JSTracer *trc = (JSTracer *)arg;
+ uintN flags = ATOM_ENTRY_FLAGS(entry);
- atom = (JSAtom *)he;
- args = (TraceArgs *)arg;
- if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) || args->allAtoms) {
- JS_SET_TRACING_INDEX(args->trc,
- (atom->flags & ATOM_PINNED)
+ JS_ASSERT(IS_STRING_TABLE(table));
+ if (flags & (ATOM_PINNED | ATOM_INTERNED)) {
+ JS_SET_TRACING_INDEX(trc,
+ flags & ATOM_PINNED
? "pinned_atom"
- : (atom->flags & ATOM_INTERNED)
- ? "interned_atom"
- : "locked_atom",
- (size_t)i);
- JS_CallTracer(args->trc, atom, JSTRACE_ATOM);
+ : "interned_atom",
+ (size_t)number);
+ JS_CallTracer(trc, ATOM_ENTRY_KEY(entry), JSTRACE_STRING);
}
- return HT_ENUMERATE_NEXT;
+ return JS_DHASH_NEXT;
}
void
-js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms)
+js_TraceAtomState(JSTracer *trc, JSBool allAtoms)
{
JSAtomState *state;
- TraceArgs args;
state = &trc->context->runtime->atomState;
- if (!state->table)
- return;
- args.allAtoms = allAtoms;
- args.trc = trc;
- JS_HashTableEnumerateEntries(state->table, js_locked_atom_tracer, &args);
+ if (allAtoms) {
+ JS_DHashTableEnumerate(&state->doubleAtoms, js_locked_atom_tracer, trc);
+ JS_DHashTableEnumerate(&state->stringAtoms, js_locked_atom_tracer, trc);
+ } else {
+ JS_DHashTableEnumerate(&state->stringAtoms, js_pinned_atom_tracer, trc);
+ }
}
-JS_STATIC_DLL_CALLBACK(intN)
-js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+js_atom_sweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
+ uint32 number, void *arg)
{
- JSAtom *atom;
+ JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
+ JSContext *cx = (JSContext *)arg;
- atom = (JSAtom *)he;
- if (atom->flags & ATOM_MARK) {
- atom->flags &= ~ATOM_MARK;
- return HT_ENUMERATE_NEXT;
+ /* Remove uninitialized entries. */
+ if (entry->keyAndFlags == 0)
+ return JS_DHASH_REMOVE;
+
+ if (ATOM_ENTRY_FLAGS(entry) & (ATOM_PINNED | ATOM_INTERNED)) {
+ /* Pinned or interned key cannot be finalized. */
+ JS_ASSERT(!js_IsAboutToBeFinalized(cx, ATOM_ENTRY_KEY(entry)));
+ } else if (js_IsAboutToBeFinalized(cx, ATOM_ENTRY_KEY(entry))) {
+ /* Remove entries with things about to be GC'ed. */
+ return JS_DHASH_REMOVE;
}
- JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
- atom->entry.key = atom->entry.value = NULL;
- atom->flags = 0;
- return HT_ENUMERATE_REMOVE;
+ return JS_DHASH_NEXT;
}
void
js_SweepAtomState(JSContext *cx)
{
JSAtomState *state = &cx->runtime->atomState;
- JS_HashTableEnumerateEntries(state->table, js_atom_sweeper, NULL);
-}
-
-static JSAtom *
-AtomizeHashedKey(JSContext *cx, jsval key, JSHashNumber keyHash)
-{
- JSAtomState *state;
- JSHashTable *table;
- JSHashEntry *he, **hep;
- JSAtom *atom;
+ JS_DHashTableEnumerate(&state->doubleAtoms, js_atom_sweeper, cx);
+ JS_DHashTableEnumerate(&state->stringAtoms, js_atom_sweeper, cx);
- state = &cx->runtime->atomState;
- JS_LOCK(&state->lock, cx);
- table = state->table;
- hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
- if ((he = *hep) == NULL) {
- he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
- if (!he) {
- JS_UNLOCK(&state->lock,cx);
- JS_ReportOutOfMemory(cx);
- return NULL;
- }
- }
-
- atom = (JSAtom *)he;
- cx->weakRoots.lastAtom = atom;
- JS_UNLOCK(&state->lock,cx);
- return atom;
+ /*
+ * Optimize for simplicity and mutate tablegen even if the sweeper has not
+ * removed any entries.
+ */
+ state->tablegen++;
}
-/* Worst-case alignment grain and aligning macro for 2x-sized buffer. */
-#define ALIGNMENT(t) JS_MAX(JSVAL_ALIGN, sizeof(t))
-#define ALIGN(b,t) ((t*) &(b)[ALIGNMENT(t) - (jsuword)(b) % ALIGNMENT(t)])
-
JSAtom *
js_AtomizeDouble(JSContext *cx, jsdouble d)
{
- char buf[2 * ALIGNMENT(double)];
- jsdouble *dp;
- JSHashNumber keyHash;
- jsval key;
JSAtomState *state;
- JSHashTable *table;
- JSHashEntry *he, **hep;
+ JSDHashTable *table;
+ JSAtomHashEntry *entry;
uint32 gen;
- JSAtom *atom;
+ jsdouble *key;
+ jsval v;
- dp = ALIGN(buf, double);
- *dp = d;
- keyHash = HASH_DOUBLE(dp);
- key = DOUBLE_TO_JSVAL(dp);
state = &cx->runtime->atomState;
- table = state->table;
+ table = &state->doubleAtoms;
JS_LOCK(&state->lock, cx);
- hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
- if ((he = *hep) == NULL) {
- gen = state->tablegen;
+ entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, &d, JS_DHASH_ADD));
+ if (!entry)
+ goto failed_hash_add;
+ if (entry->keyAndFlags == 0) {
+ gen = ++state->tablegen;
JS_UNLOCK(&state->lock, cx);
- if (!js_NewDoubleValue(cx, d, &key))
+ key = js_NewDouble(cx, d, 0);
+ if (!key)
return NULL;
JS_LOCK(&state->lock, cx);
- if (state->tablegen != gen) {
- hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
- if ((he = *hep) != NULL)
+ if (state->tablegen == gen) {
+ JS_ASSERT(entry->keyAndFlags == 0);
+ } else {
+ entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key,
+ JS_DHASH_ADD));
+ if (!entry)
+ goto failed_hash_add;
+ if (entry->keyAndFlags != 0)
goto finish;
+ ++state->tablegen;
}
- he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
- if (!he) {
- JS_UNLOCK(&state->lock, cx);
- JS_ReportOutOfMemory(cx);
- return NULL;
- }
+ INIT_ATOM_ENTRY(entry, key);
}
finish:
- atom = (JSAtom *)he;
- cx->weakRoots.lastAtom = atom;
+ v = DOUBLE_TO_JSVAL((jsdouble *)ATOM_ENTRY_KEY(entry));
+ cx->weakRoots.lastAtom = v;
JS_UNLOCK(&state->lock,cx);
- return atom;
-}
+
+ return (JSAtom *)v;
-/*
- * To put an atom into the hidden subspace. XOR its keyHash with this value,
- * which is (sqrt(2)-1) in 32-bit fixed point.
- */
-#define HIDDEN_ATOM_SUBSPACE_KEYHASH 0x6A09E667
+ failed_hash_add:
+ JS_UNLOCK(&state->lock,cx);
+ JS_ReportOutOfMemory(cx);
+ return NULL;
+}
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
{
- JSHashNumber keyHash;
- void *key;
JSAtomState *state;
- JSHashTable *table;
- JSHashEntry *he, **hep;
+ JSDHashTable *table;
+ JSAtomHashEntry *entry;
+ JSString *key;
uint32 gen;
- JSString *hashed;
- JSAtom *atom;
+ jsval v;
- keyHash = js_HashString(str);
- if (flags & ATOM_HIDDEN)
- keyHash ^= HIDDEN_ATOM_SUBSPACE_KEYHASH;
- key = (void *)STRING_TO_JSVAL(str);
+ JS_ASSERT((flags &
+ ~(ATOM_PINNED | ATOM_INTERNED | ATOM_TMPSTR | ATOM_NOCOPY))
+ == 0);
state = &cx->runtime->atomState;
- table = state->table;
+ table = &state->stringAtoms;
JS_LOCK(&state->lock, cx);
- hep = JS_HashTableRawLookup(table, keyHash, key);
- if ((he = *hep) == NULL) {
+ entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, str, JS_DHASH_ADD));
+ if (!entry)
+ goto failed_hash_add;
+ if (entry->keyAndFlags == 0) {
+ ++state->tablegen;
gen = state->tablegen;
JS_UNLOCK(&state->lock, cx);
if (flags & ATOM_TMPSTR) {
if (flags & ATOM_NOCOPY) {
- hashed = js_NewString(cx, str->chars, str->length, 0);
- if (!hashed)
+ key = js_NewString(cx, str->u.chars, str->length);
+ if (!key)
return NULL;
/* Transfer ownership of str->chars to GC-controlled string. */
- str->chars = NULL;
+ str->u.chars = NULL;
} else {
- hashed = js_NewStringCopyN(cx, str->chars, str->length);
- if (!hashed)
+ key = js_NewStringCopyN(cx, str->u.chars, str->length);
+ if (!key)
return NULL;
}
- key = (void *)STRING_TO_JSVAL(hashed);
} else {
JS_ASSERT((flags & ATOM_NOCOPY) == 0);
if (!JS_MakeStringImmutable(cx, str))
return NULL;
+ key = str;
}
JS_LOCK(&state->lock, cx);
- if (state->tablegen != gen) {
- hep = JS_HashTableRawLookup(table, keyHash, key);
- if ((he = *hep) != NULL)
+ if (state->tablegen == gen) {
+ JS_ASSERT(entry->keyAndFlags == 0);
+ } else {
+ entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key,
+ JS_DHASH_ADD));
+ if (!entry)
+ goto failed_hash_add;
+ if (entry->keyAndFlags != 0)
goto finish;
+ ++state->tablegen;
}
- he = JS_HashTableRawAdd(table, hep, keyHash, key, NULL);
- if (!he) {
- JS_UNLOCK(&state->lock, cx);
- JS_ReportOutOfMemory(cx);
- return NULL;
- }
+ INIT_ATOM_ENTRY(entry, key);
}
finish:
- atom = (JSAtom *)he;
- atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED | ATOM_HIDDEN);
- cx->weakRoots.lastAtom = atom;
+ ADD_ATOM_ENTRY_FLAGS(entry, flags & (ATOM_PINNED | ATOM_INTERNED));
+ v = STRING_TO_JSVAL((JSString *)ATOM_ENTRY_KEY(entry));
+ cx->weakRoots.lastAtom = v;
JS_UNLOCK(&state->lock, cx);
- return atom;
+ return (JSAtom *)v;
+
+ failed_hash_add:
+ JS_UNLOCK(&state->lock,cx);
+ JS_ReportOutOfMemory(cx);
+ return NULL;
}
JS_FRIEND_API(JSAtom *)
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
{
jschar *chars;
- JSString *str;
+ JSString str;
JSAtom *atom;
- char buf[2 * ALIGNMENT(JSString)];
/*
* Avoiding the malloc in js_InflateString on shorter strings saves us
* over 20,000 malloc calls on mozilla browser startup. This compares to
* only 131 calls where the string is longer than a 31 char (net) buffer.
* The vast majority of atomized strings are already in the hashtable. So
* js_AtomizeString rarely has to copy the temp string we make.
*/
@@ -661,114 +703,137 @@ js_Atomize(JSContext *cx, const char *by
} else {
inflatedLength = length;
chars = js_InflateString(cx, bytes, &inflatedLength);
if (!chars)
return NULL;
flags |= ATOM_NOCOPY;
}
- str = ALIGN(buf, JSString);
-
- str->chars = chars;
- str->length = inflatedLength;
- atom = js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
- if (chars != inflated && str->chars)
+ JSSTRING_INIT(&str, (jschar *)chars, inflatedLength);
+ atom = js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
+ if (chars != inflated && str.u.chars)
JS_free(cx, chars);
return atom;
}
JS_FRIEND_API(JSAtom *)
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
{
- JSString *str;
- char buf[2 * ALIGNMENT(JSString)];
+ JSString str;
- str = ALIGN(buf, JSString);
- str->chars = (jschar *)chars;
- str->length = length;
- return js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
+ JSSTRING_INIT(&str, (jschar *)chars, length);
+ return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
}
JSAtom *
js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
{
- JSString *str;
- char buf[2 * ALIGNMENT(JSString)];
- JSHashNumber keyHash;
- jsval key;
+ JSString str, *str2;
JSAtomState *state;
- JSHashTable *table;
- JSHashEntry **hep;
+ JSDHashEntryHdr *hdr;
+
+ JSSTRING_INIT(&str, (jschar *)chars, length);
+ state = &cx->runtime->atomState;
- str = ALIGN(buf, JSString);
- str->chars = (jschar *)chars;
- str->length = length;
- keyHash = js_HashString(str);
- key = STRING_TO_JSVAL(str);
- state = &cx->runtime->atomState;
JS_LOCK(&state->lock, cx);
- table = state->table;
- hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
+ hdr = JS_DHashTableOperate(&state->stringAtoms, &str, JS_DHASH_LOOKUP);
+ str2 = JS_DHASH_ENTRY_IS_BUSY(hdr)
+ ? (JSString *)ATOM_ENTRY_KEY(TO_ATOM_ENTRY(hdr))
+ : NULL;
JS_UNLOCK(&state->lock, cx);
- return (hep) ? (JSAtom *)*hep : NULL;
+
+ return str2 ? (JSAtom *)STRING_TO_JSVAL(str2) : NULL;
}
-JSAtom *
-js_AtomizePrimitiveValue(JSContext *cx, jsval v)
+JSBool
+js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp)
{
- if (JSVAL_IS_STRING(v))
- return js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
- if (JSVAL_IS_DOUBLE(v))
- return js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v));
- JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
- v == JSVAL_NULL || v == JSVAL_VOID);
- return AtomizeHashedKey(cx, v, (JSHashNumber)v);
+ JSAtom *atom;
+
+ if (JSVAL_IS_STRING(v)) {
+ atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
+ if (!atom)
+ return JS_FALSE;
+ } else if (JSVAL_IS_DOUBLE(v)) {
+ atom = js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v));
+ if (!atom)
+ return JS_FALSE;
+ } else {
+ JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
+ v == JSVAL_NULL || v == JSVAL_VOID);
+ atom = (JSAtom *)v;
+ }
+ *atomp = atom;
+ return JS_TRUE;
}
JSAtom *
js_ValueToStringAtom(JSContext *cx, jsval v)
{
JSString *str;
str = js_ValueToString(cx, v);
if (!str)
return NULL;
return js_AtomizeString(cx, str, 0);
}
#ifdef DEBUG
-JS_STATIC_DLL_CALLBACK(int)
-atom_dumper(JSHashEntry *he, int i, void *arg)
+JS_STATIC_DLL_CALLBACK(JSDHashOperator)
+atom_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr,
+ uint32 number, void *arg)
{
+ JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
FILE *fp = (FILE *)arg;
- JSAtom *atom = (JSAtom *)he;
+ void *key;
+ uintN flags;
- fprintf(fp, "%3u %08x ", (uintN)i, (uintN)he->keyHash);
- if (ATOM_IS_STRING(atom))
- js_FileEscapedString(fp, ATOM_TO_STRING(atom), '"');
- else if (ATOM_IS_INT(atom))
- fprintf(fp, "%ld", (long)ATOM_TO_INT(atom));
- else
- fprintf(fp, "%.16g", *ATOM_TO_DOUBLE(atom));
+ fprintf(fp, "%3u %08x ", number, (uintN)entry->hdr.keyHash);
+ if (entry->keyAndFlags == 0) {
+ fputs("<uninitialized>", fp);
+ } else {
+ key = ATOM_ENTRY_KEY(entry);
+ if (IS_DOUBLE_TABLE(table)) {
+ fprintf(fp, "%.16g", *(jsdouble *)key);
+ } else {
+ JS_ASSERT(IS_STRING_TABLE(table));
+ js_FileEscapedString(fp, (JSString *)key, '"');
+ }
+ flags = ATOM_ENTRY_FLAGS(entry);
+ if (flags != 0) {
+ fputs((flags & (ATOM_PINNED | ATOM_INTERNED))
+ ? " pinned | interned"
+ : (flags & ATOM_PINNED) ? " pinned" : " interned",
+ fp);
+ }
+ }
putc('\n', fp);
- return HT_ENUMERATE_NEXT;
+ return JS_DHASH_NEXT;
}
JS_FRIEND_API(void)
js_DumpAtoms(JSContext *cx, FILE *fp)
{
JSAtomState *state = &cx->runtime->atomState;
- fprintf(fp, "\natom table contents:\n");
- JS_HashTableEnumerateEntries(state->table, atom_dumper, fp);
-#ifdef HASHMETER
- JS_HashTableDumpMeter(state->table, atom_dumper, fp);
+ fprintf(fp, "stringAtoms table contents:\n");
+ JS_DHashTableEnumerate(&state->stringAtoms, atom_dumper, fp);
+#ifdef JS_DHASHMETER
+ JS_DHashTableDumpMeter(&state->stringAtoms, atom_dumper, fp);
#endif
+ putc('\n', fp);
+
+ fprintf(fp, "doubleAtoms table contents:\n");
+ JS_DHashTableEnumerate(&state->doubleAtoms, atom_dumper, fp);
+#ifdef JS_DHASHMETER
+ JS_DHashTableDumpMeter(&state->doubleAtoms, atom_dumper, fp);
+#endif
+ putc('\n', fp);
}
#endif
JS_STATIC_DLL_CALLBACK(JSHashNumber)
js_hash_atom_ptr(const void *key)
{
const JSAtom *atom = (const JSAtom *) key;
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -41,48 +41,37 @@
#define jsatom_h___
/*
* JS atom table.
*/
#include <stddef.h>
#include "jsconfig.h"
#include "jstypes.h"
#include "jshash.h" /* Added by JSIFY */
+#include "jsdhash.h"
#include "jsapi.h"
#include "jsprvtd.h"
#include "jspubtd.h"
#ifdef JS_THREADSAFE
#include "jslock.h"
#endif
JS_BEGIN_EXTERN_C
-#define ATOM_PINNED 0x01 /* atom is pinned against GC */
-#define ATOM_INTERNED 0x02 /* pinned variant for JS_Intern* API */
-#define ATOM_MARK 0x04 /* atom is reachable via GC */
-#define ATOM_HIDDEN 0x08 /* atom is in special hidden subspace */
-#define ATOM_NOCOPY 0x40 /* don't copy atom string bytes */
-#define ATOM_TMPSTR 0x80 /* internal, to avoid extra string */
+#define ATOM_PINNED 0x1 /* atom is pinned against GC */
+#define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */
+#define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */
+#define ATOM_TMPSTR 0x8 /* internal, to avoid extra string */
-struct JSAtom {
- JSHashEntry entry; /* key is jsval or unhidden atom
- if ATOM_HIDDEN */
- uint32 flags; /* pinned, interned, and mark flags */
-};
-
-#define ATOM_KEY(atom) ((jsval)(atom)->entry.key)
-#define ATOM_IS_INT(atom) JSVAL_IS_INT(ATOM_KEY(atom))
-#define ATOM_TO_INT(atom) JSVAL_TO_INT(ATOM_KEY(atom))
+#define ATOM_KEY(atom) ((jsval)(atom))
#define ATOM_IS_DOUBLE(atom) JSVAL_IS_DOUBLE(ATOM_KEY(atom))
#define ATOM_TO_DOUBLE(atom) JSVAL_TO_DOUBLE(ATOM_KEY(atom))
#define ATOM_IS_STRING(atom) JSVAL_IS_STRING(ATOM_KEY(atom))
#define ATOM_TO_STRING(atom) JSVAL_TO_STRING(ATOM_KEY(atom))
-#define ATOM_IS_BOOLEAN(atom) JSVAL_IS_BOOLEAN(ATOM_KEY(atom))
-#define ATOM_TO_BOOLEAN(atom) JSVAL_TO_BOOLEAN(ATOM_KEY(atom))
JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD);
#if JS_BYTES_PER_WORD == 4
# define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2)
#elif JS_BYTES_PER_WORD == 8
# define ATOM_HASH(atom) (((JSHashNumber)(atom) >> 3) ^ \
@@ -151,18 +140,18 @@ struct JSAtomList {
JS_END_MACRO
struct JSAtomMap {
JSAtom **vector; /* array of ptrs to indexed atoms */
jsatomid length; /* count of (to-be-)indexed atoms */
};
struct JSAtomState {
- JSHashTable *table; /* hash table containing all atoms */
-
+ JSDHashTable stringAtoms; /* hash table with shared strings */
+ JSDHashTable doubleAtoms; /* hash table with shared doubles */
uint32 tablegen; /* number of atoms mutations to
optimize hashing */
#ifdef JS_THREADSAFE
JSThinLock lock;
#endif
/*
* From this point until the end of struct definition the struct must
@@ -269,16 +258,19 @@ struct JSAtomState {
JSAtom *watchAtom;
} lazy;
};
#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom)
#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy)
#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState))
+#define COMMON_ATOMS_START(state) \
+ (JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START)
+
/* Start and limit offsets should correspond to atoms. */
JS_STATIC_ASSERT(ATOM_OFFSET_START % sizeof(JSAtom *) == 0);
JS_STATIC_ASSERT(ATOM_OFFSET_LIMIT % sizeof(JSAtom *) == 0);
#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
@@ -374,20 +366,17 @@ js_InitAtomState(JSRuntime *rt);
extern void
js_FinishAtomState(JSRuntime *rt);
/*
* Atom tracing and garbage collection hooks.
*/
extern void
-js_TraceAtom(JSTracer *trc, JSAtom *atom);
-
-extern void
-js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms);
+js_TraceAtomState(JSTracer *trc, JSBool allAtoms);
extern void
js_SweepAtomState(JSContext *cx);
extern JSBool
js_InitCommonAtoms(JSContext *cx);
extern void
@@ -418,18 +407,18 @@ js_AtomizeChars(JSContext *cx, const jsc
* sequence is currently not atomized.
*/
extern JSAtom *
js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length);
/*
* This variant handles all primitive values.
*/
-extern JSAtom *
-js_AtomizePrimitiveValue(JSContext *cx, jsval v);
+JSBool
+js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp);
/*
* Convert v to an atomized string.
*/
extern JSAtom *
js_ValueToStringAtom(JSContext *cx, jsval v);
#ifdef DEBUG
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -554,83 +554,97 @@ date_msecFromDate(jsdouble year, jsdoubl
jsdouble msec_time;
jsdouble result;
day = MakeDay(year, mon, mday);
msec_time = MakeTime(hour, min, sec, msec);
result = MakeDate(day, msec_time);
return result;
}
-
-/*
- * See ECMA 15.9.4.[3-10];
- */
+
+/* compute the time in msec (unclipped) from the given args */
#define MAXARGS 7
static JSBool
-date_UTC(JSContext *cx, uintN argc, jsval *vp)
+date_msecFromArgs(JSContext *cx, uintN argc, jsval *argv, jsdouble *rval)
{
- jsval *argv;
uintN loop;
jsdouble array[MAXARGS];
jsdouble d;
+ jsdouble msec_time;
- argv = vp + 2;
for (loop = 0; loop < MAXARGS; loop++) {
if (loop < argc) {
if (!js_ValueToNumber(cx, argv[loop], &d))
return JS_FALSE;
- /* return NaN if any arg is NaN */
+ /* return NaN if any arg is not finite */
if (!JSDOUBLE_IS_FINITE(d)) {
- return js_NewNumberValue(cx, d, vp);
+ *rval = *cx->runtime->jsNaN;
+ return JS_TRUE;
}
- array[loop] = floor(d);
+ array[loop] = js_DoubleToInteger(d);
} else {
- array[loop] = 0;
+ if (loop == 2) {
+ array[loop] = 1; /* Default the date argument to 1. */
+ } else {
+ array[loop] = 0;
+ }
}
}
/* adjust 2-digit years into the 20th century */
if (array[0] >= 0 && array[0] <= 99)
array[0] += 1900;
- /* if we got a 0 for 'date' (which is out of range)
- * pretend it's a 1. (So Date.UTC(1972, 5) works) */
- if (array[2] < 1)
- array[2] = 1;
+ msec_time = date_msecFromDate(array[0], array[1], array[2],
+ array[3], array[4], array[5], array[6]);
+ *rval = msec_time;
+ return JS_TRUE;
+}
- d = date_msecFromDate(array[0], array[1], array[2],
- array[3], array[4], array[5], array[6]);
- d = TIMECLIP(d);
+
+/*
+ * See ECMA 15.9.4.[3-10];
+ */
+static JSBool
+date_UTC(JSContext *cx, uintN argc, jsval *vp)
+{
+ jsdouble msec_time;
- return js_NewNumberValue(cx, d, vp);
+ if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time))
+ return JS_FALSE;
+
+ msec_time = TIMECLIP(msec_time);
+
+ return js_NewNumberValue(cx, msec_time, vp);
}
static JSBool
date_parseString(JSString *str, jsdouble *result)
{
jsdouble msec;
- const jschar *s = JSSTRING_CHARS(str);
- size_t limit = JSSTRING_LENGTH(str);
+ const jschar *s;
+ size_t limit;
size_t i = 0;
int year = -1;
int mon = -1;
int mday = -1;
int hour = -1;
int min = -1;
int sec = -1;
int c = -1;
int n = -1;
int tzoffset = -1;
int prevc = 0;
JSBool seenplusminus = JS_FALSE;
int temp;
JSBool seenmonthname = JS_FALSE;
+ JSSTRING_CHARS_AND_LENGTH(str, s, limit);
if (limit == 0)
goto syntax;
while (i < limit) {
c = s[i];
i++;
if (c <= ' ' || c == ',' || c == '-') {
if (c == '-' && '0' <= s[i] && s[i] <= '9') {
prevc = c;
@@ -2096,58 +2110,32 @@ Date(JSContext *cx, JSObject *obj, uintN
if (!str)
return JS_FALSE;