author | David Anderson <danderson@mozilla.com> |
Tue, 08 May 2012 17:34:07 -0700 | |
changeset 113030 | e3b632e26dc04c0cf0226c8b2681a0d3243464ea |
parent 113029 | 57e056f0da79c010b7999bc650c2a570bf3a9855 (current diff) |
parent 97998 | 75d817e6bf4d504d12e4ee4f626c762114dff69c (diff) |
child 113031 | 49dad96faabaa36d24e85eb379e70bc31dd14ac5 |
push id | 239 |
push user | akeybl@mozilla.com |
push date | Thu, 03 Jan 2013 21:54:43 +0000 |
treeherder | mozilla-release@3a7b66445659 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 15.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/accessible/src/atk/nsAccessibleWrap.cpp +++ b/accessible/src/atk/nsAccessibleWrap.cpp @@ -716,17 +716,17 @@ getDescriptionCB(AtkObject *aAtkObj) AtkRole getRoleCB(AtkObject *aAtkObj) { nsAccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj); if (!accWrap) return ATK_ROLE_INVALID; -#ifdef DEBUG_A11Y +#ifdef DEBUG NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap), "Does not support nsIAccessibleText when it should"); #endif if (aAtkObj->role != ATK_ROLE_INVALID) return aAtkObj->role; #define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role) \
--- a/accessible/src/base/Relation.h +++ b/accessible/src/base/Relation.h @@ -69,19 +69,19 @@ public: mFirstIter(aRelation.mFirstIter), mLastIter(aRelation.mLastIter) { } Relation(AccIterable* aIter) : mFirstIter(aIter), mLastIter(aIter) { } Relation(nsAccessible* aAcc) : mFirstIter(nsnull), mLastIter(nsnull) { AppendTarget(aAcc); } - Relation(nsIContent* aContent) : + Relation(nsDocAccessible* aDocument, nsIContent* aContent) : mFirstIter(nsnull), mLastIter(nsnull) - { AppendTarget(aContent); } + { AppendTarget(aDocument, aContent); } Relation& operator = (const RelationCopyHelper& aRH) { mFirstIter = aRH.mFirstIter; mLastIter = aRH.mLastIter; return *this; } @@ -115,20 +115,20 @@ public: if (aAcc) AppendIter(new SingleAccIterator(aAcc)); } /** * Append the one accessible for this content node to the set of related * accessibles. */ - inline void AppendTarget(nsIContent* aContent) + void AppendTarget(nsDocAccessible* aDocument, nsIContent* aContent) { if (aContent) - AppendTarget(GetAccService()->GetAccessible(aContent, nsnull)); + AppendTarget(aDocument->GetAccessible(aContent)); } /** * compute and return the next related accessible. */ inline nsAccessible* Next() { nsAccessible* target = nsnull;
--- a/accessible/src/base/nsAccUtils.cpp +++ b/accessible/src/base/nsAccUtils.cpp @@ -438,44 +438,44 @@ nsAccUtils::GetLiveAttrValue(PRUint32 aR case ePoliteLiveAttr: aValue = NS_LITERAL_STRING("polite"); return true; } return false; } -#ifdef DEBUG_A11Y +#ifdef DEBUG bool -nsAccUtils::IsTextInterfaceSupportCorrect(nsAccessible *aAccessible) +nsAccUtils::IsTextInterfaceSupportCorrect(nsAccessible* aAccessible) { // Don't test for accessible docs, it makes us create accessibles too // early and fire mutation events before we need to if (aAccessible->IsDoc()) return true; bool foundText = false; PRInt32 childCount = aAccessible->GetChildCount(); - for (PRint32 childIdx = 0; childIdx < childCount; childIdx++) { - nsAccessible *child = GetChildAt(childIdx); + for (PRInt32 childIdx = 0; childIdx < childCount; childIdx++) { + nsAccessible* child = aAccessible->GetChildAt(childIdx); if (IsText(child)) { foundText = true; break; } } if (foundText) { // found text child node nsCOMPtr<nsIAccessibleText> text = do_QueryObject(aAccessible); if (!text) return false; } - return true; + return true; } #endif PRUint32 nsAccUtils::TextLength(nsAccessible *aAccessible) { if (!IsText(aAccessible)) return 1;
--- a/accessible/src/base/nsAccUtils.h +++ b/accessible/src/base/nsAccUtils.h @@ -265,17 +265,17 @@ public: * * @param aRule [in] rule constant (see ELiveAttrRule in nsAccMap.h) * @param aValue [out] object attribute value * * @return true if object attribute should be exposed */ static bool GetLiveAttrValue(PRUint32 aRule, nsAString& aValue); -#ifdef DEBUG_A11Y +#ifdef DEBUG /** * Detect whether the given accessible object implements nsIAccessibleText, * when it is text or has text child node. */ static bool IsTextInterfaceSupportCorrect(nsAccessible *aAccessible); #endif /**
--- a/accessible/src/base/nsAccessNode.cpp +++ b/accessible/src/base/nsAccessNode.cpp @@ -44,36 +44,31 @@ #include "nsCoreUtils.h" #include "RootAccessible.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" #include "nsIDOMWindow.h" #include "nsIFrame.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsIObserverService.h" -#include "nsIPrefBranch.h" -#include "nsIPrefService.h" #include "nsIPresShell.h" #include "nsIServiceManager.h" #include "nsIStringBundle.h" #include "nsFocusManager.h" #include "nsPresContext.h" #include "mozilla/Services.h" using namespace mozilla::a11y; /* For documentation of the accessibility architecture, * see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html */ nsIStringBundle *nsAccessNode::gStringBundle = 0; -bool nsAccessNode::gIsFormFillEnabled = false; - ApplicationAccessible* nsAccessNode::gApplicationAccessible = nsnull; /* * Class nsAccessNode */ //////////////////////////////////////////////////////////////////////////////// // nsAccessible. nsISupports @@ -158,38 +153,16 @@ void nsAccessNode::InitXPAccessibility() { nsCOMPtr<nsIStringBundleService> stringBundleService = mozilla::services::GetStringBundleService(); if (stringBundleService) { // Static variables are released in ShutdownAllXPAccessibility(); stringBundleService->CreateBundle(ACCESSIBLE_BUNDLE_URL, &gStringBundle); } - - nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID)); - if (prefBranch) { - prefBranch->GetBoolPref("browser.formfill.enable", &gIsFormFillEnabled); - } - - NotifyA11yInitOrShutdown(true); -} - -// nsAccessNode protected static -void nsAccessNode::NotifyA11yInitOrShutdown(bool aIsInit) -{ - nsCOMPtr<nsIObserverService> obsService = - mozilla::services::GetObserverService(); - NS_ASSERTION(obsService, "No observer service to notify of a11y init/shutdown"); - if (!obsService) - return; - - static const PRUnichar kInitIndicator[] = { '1', 0 }; - static const PRUnichar kShutdownIndicator[] = { '0', 0 }; - obsService->NotifyObservers(nsnull, "a11y-init-or-shutdown", - aIsInit ? kInitIndicator : kShutdownIndicator); } void nsAccessNode::ShutdownXPAccessibility() { // Called by nsAccessibilityService::Shutdown() // which happens when xpcom is shutting down // at exit of program @@ -197,18 +170,16 @@ void nsAccessNode::ShutdownXPAccessibili // Release gApplicationAccessible after everything else is shutdown // so we don't accidently create it again while tearing down root accessibles ApplicationAccessibleWrap::Unload(); if (gApplicationAccessible) { gApplicationAccessible->Shutdown(); NS_RELEASE(gApplicationAccessible); } - - NotifyA11yInitOrShutdown(false); } RootAccessible* nsAccessNode::RootAccessible() const { nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = nsCoreUtils::GetDocShellTreeItemFor(mContent); NS_ASSERTION(docShellTreeItem, "No docshell tree item for mContent");
--- a/accessible/src/base/nsAccessNode.h +++ b/accessible/src/base/nsAccessNode.h @@ -159,26 +159,19 @@ public: void Language(nsAString& aLocale); protected: void LastRelease(); nsCOMPtr<nsIContent> mContent; nsDocAccessible* mDoc; - /** - * Notify global nsIObserver's that a11y is getting init'd or shutdown. - */ - static void NotifyA11yInitOrShutdown(bool aIsInit); - // Static data, we do our own refcounting for our static data. static nsIStringBundle* gStringBundle; - static bool gIsFormFillEnabled; - private: nsAccessNode() MOZ_DELETE; nsAccessNode(const nsAccessNode&) MOZ_DELETE; nsAccessNode& operator =(const nsAccessNode&) MOZ_DELETE; static ApplicationAccessible* gApplicationAccessible; };
--- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -41,16 +41,17 @@ // NOTE: alphabetically ordered #include "Accessible-inl.h" #include "ApplicationAccessibleWrap.h" #include "ARIAGridAccessibleWrap.h" #ifdef MOZ_ACCESSIBILITY_ATK #include "AtkSocketAccessible.h" #endif #include "FocusManager.h" +#include "HTMLListAccessible.h" #include "nsAccessiblePivot.h" #include "nsAccUtils.h" #include "nsARIAMap.h" #include "nsIAccessibleProvider.h" #include "nsHTMLCanvasAccessible.h" #include "nsHTMLImageMapAccessible.h" #include "nsHTMLLinkAccessible.h" #include "nsHTMLSelectAccessible.h" @@ -217,17 +218,17 @@ nsAccessibilityService::CreateHTMLButton return accessible; } already_AddRefed<nsAccessible> nsAccessibilityService::CreateHTMLLIAccessible(nsIContent* aContent, nsIPresShell* aPresShell) { nsAccessible* accessible = - new nsHTMLLIAccessible(aContent, GetDocAccessible(aPresShell)); + new HTMLLIAccessible(aContent, GetDocAccessible(aPresShell)); NS_ADDREF(accessible); return accessible; } already_AddRefed<nsAccessible> nsAccessibilityService::CreateHyperTextAccessible(nsIContent* aContent, nsIPresShell* aPresShell) { @@ -594,17 +595,17 @@ void nsAccessibilityService::UpdateListBullet(nsIPresShell* aPresShell, nsIContent* aHTMLListItemContent, bool aHasBullet) { nsDocAccessible* document = GetDocAccessible(aPresShell); if (document) { nsAccessible* accessible = document->GetAccessible(aHTMLListItemContent); if (accessible) { - nsHTMLLIAccessible* listItem = accessible->AsHTMLListItem(); + HTMLLIAccessible* listItem = accessible->AsHTMLListItem(); if (listItem) listItem->UpdateBullet(aHasBullet); } } } void nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame) @@ -1266,32 +1267,39 @@ nsAccessibilityService::Init() // Add observers. nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); if (!observerService) return false; observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + static const PRUnichar kInitIndicator[] = { '1', 0 }; + observerService->NotifyObservers(nsnull, "a11y-init-or-shutdown", kInitIndicator); + // Initialize accessibility. nsAccessNodeWrap::InitAccessibility(); gIsShutdown = false; return true; } void nsAccessibilityService::Shutdown() { // Remove observers. nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); - if (observerService) + if (observerService) { observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + static const PRUnichar kShutdownIndicator[] = { '0', 0 }; + observerService->NotifyObservers(nsnull, "a11y-init-or-shutdown", kShutdownIndicator); + } + // Stop accessible document loader. nsAccDocManager::Shutdown(); // Application is going to be closed, shutdown accessibility and mark // accessibility service as shutdown to prevent calls of its methods. // Don't null accessibility service static member at this point to be safe // if someone will try to operate with it. @@ -1646,17 +1654,17 @@ nsAccessibilityService::CreateHTMLAccess nsAccessible* accessible = new nsHTMLSelectOptGroupAccessible(aContent, aDoc); NS_IF_ADDREF(accessible); return accessible; } if (tag == nsGkAtoms::ul || tag == nsGkAtoms::ol || tag == nsGkAtoms::dl) { - nsAccessible* accessible = new nsHTMLListAccessible(aContent, aDoc); + nsAccessible* accessible = new HTMLListAccessible(aContent, aDoc); NS_IF_ADDREF(accessible); return accessible; } if (tag == nsGkAtoms::a) { // Only some roles truly enjoy life as nsHTMLLinkAccessibles, for details // see closed bug 494807. nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent); @@ -1673,17 +1681,17 @@ nsAccessibilityService::CreateHTMLAccess } if (tag == nsGkAtoms::dt || (tag == nsGkAtoms::li && aFrame->GetType() != nsGkAtoms::blockFrame)) { // Normally for li, it is created by the list item frame (in nsBlockFrame) // which knows about the bullet frame; however, in this case the list item // must have been styled using display: foo - nsAccessible* accessible = new nsHTMLLIAccessible(aContent, aDoc); + nsAccessible* accessible = new HTMLLIAccessible(aContent, aDoc); NS_IF_ADDREF(accessible); return accessible; } if (tag == nsGkAtoms::abbr || tag == nsGkAtoms::acronym || tag == nsGkAtoms::blockquote || tag == nsGkAtoms::dd ||
--- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -909,17 +909,17 @@ void nsAccessible::GetBoundsRect(nsRect& * 1) Start with an empty rectangle * 2) Add the rect for the primary frame from for the DOM node. * 3) For each next frame at the same depth with the same DOM node, add that rect to total * 4) If that frame is an inline frame, search deeper at that point in the tree, adding all rects */ // Initialization area *aBoundingFrame = nsnull; - nsIFrame *firstFrame = GetBoundsFrame(); + nsIFrame* firstFrame = GetFrame(); if (!firstFrame) return; // Find common relative parent // This is an ancestor frame that will incompass all frames for this content node. // We need the relative parent so we can get absolute screen coordinates nsIFrame *ancestorFrame = firstFrame; @@ -1024,23 +1024,16 @@ nsAccessible::GetBounds(PRInt32* aX, PRI nsIntRect orgRectPixels = boundingFrame->GetScreenRectInAppUnits(). ToNearestPixels(presContext->AppUnitsPerDevPixel()); *aX += orgRectPixels.x; *aY += orgRectPixels.y; return NS_OK; } -// helpers - -nsIFrame* nsAccessible::GetBoundsFrame() -{ - return GetFrame(); -} - NS_IMETHODIMP nsAccessible::SetSelected(bool aSelect) { if (IsDefunct()) return NS_ERROR_FAILURE; nsAccessible* select = nsAccUtils::GetSelectableContainer(this, State()); if (select) { if (select->State() & states::MULTISELECTABLE) { @@ -2104,17 +2097,17 @@ nsAccessible::RelationByType(PRUint32 aT if (mContent->IsHTML()) { // HTML form controls implements nsIFormControl interface. nsCOMPtr<nsIFormControl> control(do_QueryInterface(mContent)); if (control) { nsCOMPtr<nsIForm> form(do_QueryInterface(control->GetFormElement())); if (form) { nsCOMPtr<nsIContent> formContent = do_QueryInterface(form->GetDefaultSubmitElement()); - return Relation(formContent); + return Relation(mDoc, formContent); } } } else { // In XUL, use first <button default="true" .../> in the document nsCOMPtr<nsIDOMXULDocument> xulDoc = do_QueryInterface(mContent->OwnerDoc()); nsCOMPtr<nsIDOMXULButtonElement> buttonEl; if (xulDoc) { @@ -2145,23 +2138,23 @@ nsAccessible::RelationByType(PRUint32 aT NS_LITERAL_STRING("default"), NS_LITERAL_STRING("true"), getter_AddRefs(possibleButtonEl)); buttonEl = do_QueryInterface(possibleButtonEl); } } } nsCOMPtr<nsIContent> relatedContent(do_QueryInterface(buttonEl)); - return Relation(relatedContent); + return Relation(mDoc, relatedContent); } } return Relation(); } case nsIAccessibleRelation::RELATION_MEMBER_OF: - return Relation(GetAtomicRegion()); + return Relation(mDoc, GetAtomicRegion()); case nsIAccessibleRelation::RELATION_SUBWINDOW_OF: case nsIAccessibleRelation::RELATION_EMBEDS: case nsIAccessibleRelation::RELATION_EMBEDDED_BY: case nsIAccessibleRelation::RELATION_POPUP_FOR: case nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF: default: return Relation(); }
--- a/accessible/src/base/nsAccessible.h +++ b/accessible/src/base/nsAccessible.h @@ -57,22 +57,23 @@ class AccEvent; class AccGroupInfo; class EmbeddedObjCollector; class KeyBinding; class nsAccessible; class nsHyperTextAccessible; class nsHTMLImageAccessible; class nsHTMLImageMapAccessible; -class nsHTMLLIAccessible; struct nsRoleMapEntry; class Relation; namespace mozilla { namespace a11y { + +class HTMLLIAccessible; class TableAccessible; /** * Name type flags. */ enum ENameValueFlag { /** * Name either @@ -440,16 +441,21 @@ public: PRUint32 aLength = PR_UINT32_MAX); /** * Assert if child not in parent's cache if the cache was initialized at this * point. */ void TestChildCache(nsAccessible* aCachedChild) const; + /** + * Return boundaries rect relative the bounding frame. + */ + virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame); + ////////////////////////////////////////////////////////////////////////////// // Downcasting and types inline bool IsAbbreviation() const { return mContent->IsHTML() && (mContent->Tag() == nsGkAtoms::abbr || mContent->Tag() == nsGkAtoms::acronym); } @@ -466,17 +472,17 @@ public: nsDocAccessible* AsDoc(); inline bool IsHyperText() const { return mFlags & eHyperTextAccessible; } nsHyperTextAccessible* AsHyperText(); inline bool IsHTMLFileInput() const { return mFlags & eHTMLFileInputAccessible; } inline bool IsHTMLListItem() const { return mFlags & eHTMLListItemAccessible; } - nsHTMLLIAccessible* AsHTMLListItem(); + mozilla::a11y::HTMLLIAccessible* AsHTMLListItem(); inline bool IsImageAccessible() const { return mFlags & eImageAccessible; } nsHTMLImageAccessible* AsImage(); bool IsImageMapAccessible() const { return mFlags & eImageMapAccessible; } nsHTMLImageMapAccessible* AsImageMap(); inline bool IsXULTree() const { return mFlags & eXULTreeAccessible; } @@ -740,19 +746,16 @@ protected: ////////////////////////////////////////////////////////////////////////////// // Miscellaneous helpers /** * Return ARIA role (helper method). */ mozilla::a11y::role ARIATransformRole(mozilla::a11y::role aRole); - virtual nsIFrame* GetBoundsFrame(); - virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame); - ////////////////////////////////////////////////////////////////////////////// // Name helpers /** * Compute the name of HTML node. */ nsresult GetHTMLName(nsAString& aName);
--- a/accessible/src/base/nsDocAccessible.h +++ b/accessible/src/base/nsDocAccessible.h @@ -118,16 +118,18 @@ public: virtual void ApplyARIAState(PRUint64* aState); virtual void SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry); #ifdef DEBUG_ACCDOCMGR virtual nsresult HandleAccEvent(AccEvent* aAccEvent); #endif + virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame); + // nsHyperTextAccessible virtual already_AddRefed<nsIEditor> GetEditor() const; // nsDocAccessible /** * Return presentation shell for this document accessible. */ @@ -379,17 +381,16 @@ public: protected: void LastRelease(); // nsAccessible virtual void CacheChildren(); // nsDocAccessible - virtual void GetBoundsRect(nsRect& aRect, nsIFrame** aRelativeFrame); virtual nsresult AddEventListeners(); virtual nsresult RemoveEventListeners(); /** * Marks this document as loaded or loading. */ inline void NotifyOfLoad(PRUint32 aLoadEventType) {
--- a/accessible/src/html/HTMLFormControlAccessible.cpp +++ b/accessible/src/html/HTMLFormControlAccessible.cpp @@ -58,16 +58,19 @@ #include "nsIFrame.h" #include "nsINameSpaceManager.h" #include "nsISelectionController.h" #include "jsapi.h" #include "nsIJSContextStack.h" #include "nsIServiceManager.h" #include "nsITextControlFrame.h" +#include "mozilla/Preferences.h" + +using namespace mozilla; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // HTMLCheckboxAccessible //////////////////////////////////////////////////////////////////////////////// HTMLCheckboxAccessible:: HTMLCheckboxAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : @@ -491,17 +494,17 @@ HTMLTextFieldAccessible::NativeState() } // Expose autocomplete state if it has associated autocomplete list. if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::list)) return state | states::SUPPORTS_AUTOCOMPLETION; // No parent can mean a fake widget created for XUL textbox. If accessible // is unattached from tree then we don't care. - if (mParent && gIsFormFillEnabled) { + if (mParent && Preferences::GetBool("browser.formfill.enable")) { // Check to see if autocompletion is allowed on this input. We don't expose // it for password fields even though the entire password can be remembered // for a page if the user asks it to be. However, the kind of autocomplete // we're talking here is based on what the user types, where a popup of // possible choices comes up. nsAutoString autocomplete; mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete, autocomplete); @@ -699,17 +702,17 @@ HTMLGroupboxAccessible::GetNameInternal( } Relation HTMLGroupboxAccessible::RelationByType(PRUint32 aType) { Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType); // No override for label, so use <legend> for this <fieldset> if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY) - rel.AppendTarget(GetLegend()); + rel.AppendTarget(mDoc, GetLegend()); return rel; } //////////////////////////////////////////////////////////////////////////////// // HTMLLegendAccessible //////////////////////////////////////////////////////////////////////////////// @@ -785,17 +788,17 @@ HTMLFigureAccessible::GetNameInternal(ns return NS_OK; } Relation HTMLFigureAccessible::RelationByType(PRUint32 aType) { Relation rel = nsHyperTextAccessibleWrap::RelationByType(aType); if (aType == nsIAccessibleRelation::RELATION_LABELLED_BY) - rel.AppendTarget(Caption()); + rel.AppendTarget(mDoc, Caption()); return rel; } nsIContent* HTMLFigureAccessible::Caption() const { for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
copy from accessible/src/html/nsHTMLTextAccessible.cpp copy to accessible/src/html/HTMLListAccessible.cpp --- a/accessible/src/html/nsHTMLTextAccessible.cpp +++ b/accessible/src/html/HTMLListAccessible.cpp @@ -1,360 +1,165 @@ /* -*- 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 - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Aaron Leventhal (aaronl@netscape.com) - * Kyle Yuan (kyle.yuan@sun.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 ***** */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsHTMLTextAccessible.h" +#include "HTMLListAccessible.h" #include "nsDocAccessible.h" -#include "nsAccUtils.h" -#include "nsTextEquivUtils.h" -#include "Relation.h" #include "Role.h" #include "States.h" -#include "nsIAccessibleRelation.h" -#include "nsIFrame.h" -#include "nsPresContext.h" #include "nsBlockFrame.h" -#include "nsISelection.h" -#include "nsISelectionController.h" -#include "nsComponentManagerUtils.h" +using namespace mozilla; using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// -// nsHTMLTextAccessible +// HTMLListAccessible //////////////////////////////////////////////////////////////////////////////// -nsHTMLTextAccessible:: - nsHTMLTextAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsTextAccessibleWrap(aContent, aDoc) -{ -} - -NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLTextAccessible, nsTextAccessible) - -ENameValueFlag -nsHTMLTextAccessible::Name(nsString& aName) -{ - // Text node, ARIA can't be used. - aName = mText; - return eNameOK; -} +NS_IMPL_ISUPPORTS_INHERITED0(HTMLListAccessible, nsHyperTextAccessible) role -nsHTMLTextAccessible::NativeRole() +HTMLListAccessible::NativeRole() { - nsIFrame *frame = GetFrame(); - // Don't return on null frame -- we still return a role - // after accessible is shutdown/DEFUNCT - if (frame && frame->IsGeneratedContentFrame()) - return roles::STATICTEXT; + if (mContent->Tag() == nsGkAtoms::dl) + return roles::DEFINITION_LIST; - return nsTextAccessible::NativeRole(); + return roles::LIST; } PRUint64 -nsHTMLTextAccessible::NativeState() +HTMLListAccessible::NativeState() { - PRUint64 state = nsTextAccessible::NativeState(); - - nsDocAccessible* docAccessible = Document(); - if (docAccessible) { - PRUint64 docState = docAccessible->State(); - if (0 == (docState & states::EDITABLE)) { - state |= states::READONLY; // Links not focusable in editor - } - } - - return state; -} - -nsresult -nsHTMLTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes) -{ - if (NativeRole() == roles::STATICTEXT) { - nsAutoString oldValueUnused; - aAttributes->SetStringProperty(NS_LITERAL_CSTRING("auto-generated"), - NS_LITERAL_STRING("true"), oldValueUnused); - } - - return NS_OK; + return nsHyperTextAccessibleWrap::NativeState() | states::READONLY; } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLHRAccessible -//////////////////////////////////////////////////////////////////////////////// - -nsHTMLHRAccessible:: - nsHTMLHRAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) -{ -} - -role -nsHTMLHRAccessible::NativeRole() -{ - return roles::SEPARATOR; -} - - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLBRAccessible -//////////////////////////////////////////////////////////////////////////////// - -nsHTMLBRAccessible:: - nsHTMLBRAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) -{ -} - -role -nsHTMLBRAccessible::NativeRole() -{ - return roles::WHITESPACE; -} - -PRUint64 -nsHTMLBRAccessible::NativeState() -{ - return states::READONLY; -} - -nsresult -nsHTMLBRAccessible::GetNameInternal(nsAString& aName) -{ - aName = static_cast<PRUnichar>('\n'); // Newline char - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLLabelAccessible +// HTMLLIAccessible //////////////////////////////////////////////////////////////////////////////// -nsHTMLLabelAccessible:: - nsHTMLLabelAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsHyperTextAccessibleWrap(aContent, aDoc) -{ -} - -NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLabelAccessible, nsHyperTextAccessible) - -nsresult -nsHTMLLabelAccessible::GetNameInternal(nsAString& aName) -{ - return nsTextEquivUtils::GetNameFromSubtree(this, aName); -} - -role -nsHTMLLabelAccessible::NativeRole() -{ - return roles::LABEL; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLOuputAccessible -//////////////////////////////////////////////////////////////////////////////// - -nsHTMLOutputAccessible:: - nsHTMLOutputAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsHyperTextAccessibleWrap(aContent, aDoc) -{ -} - -NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLOutputAccessible, nsHyperTextAccessible) - -Relation -nsHTMLOutputAccessible::RelationByType(PRUint32 aType) -{ - Relation rel = nsAccessibleWrap::RelationByType(aType); - if (aType == nsIAccessibleRelation::RELATION_CONTROLLED_BY) - rel.AppendIter(new IDRefsIterator(mDoc, mContent, nsGkAtoms::_for)); - - return rel; -} - -role -nsHTMLOutputAccessible::NativeRole() -{ - return roles::SECTION; -} - -nsresult -nsHTMLOutputAccessible::GetAttributesInternal(nsIPersistentProperties* aAttributes) -{ - nsresult rv = nsAccessibleWrap::GetAttributesInternal(aAttributes); - NS_ENSURE_SUCCESS(rv, rv); - - nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::live, - NS_LITERAL_STRING("polite")); - - return NS_OK; -} - - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLLIAccessible -//////////////////////////////////////////////////////////////////////////////// - -nsHTMLLIAccessible:: - nsHTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : +HTMLLIAccessible:: + HTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : nsHyperTextAccessibleWrap(aContent, aDoc), mBullet(nsnull) { mFlags |= eHTMLListItemAccessible; nsBlockFrame* blockFrame = do_QueryFrame(GetFrame()); if (blockFrame && blockFrame->HasBullet()) { - mBullet = new nsHTMLListBulletAccessible(mContent, mDoc); + mBullet = new HTMLListBulletAccessible(mContent, mDoc); if (!Document()->BindToDocument(mBullet, nsnull)) mBullet = nsnull; } } -NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLIAccessible, nsHyperTextAccessible) +NS_IMPL_ISUPPORTS_INHERITED0(HTMLLIAccessible, nsHyperTextAccessible) void -nsHTMLLIAccessible::Shutdown() +HTMLLIAccessible::Shutdown() { mBullet = nsnull; nsHyperTextAccessibleWrap::Shutdown(); } role -nsHTMLLIAccessible::NativeRole() +HTMLLIAccessible::NativeRole() { if (mContent->Tag() == nsGkAtoms::dt) return roles::TERM; return roles::LISTITEM; } PRUint64 -nsHTMLLIAccessible::NativeState() +HTMLLIAccessible::NativeState() { return nsHyperTextAccessibleWrap::NativeState() | states::READONLY; } -NS_IMETHODIMP nsHTMLLIAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height) +NS_IMETHODIMP +HTMLLIAccessible::GetBounds(PRInt32* aX, PRInt32* aY, + PRInt32* aWidth, PRInt32* aHeight) { - nsresult rv = nsAccessibleWrap::GetBounds(x, y, width, height); + nsresult rv = nsAccessibleWrap::GetBounds(aX, aY, aWidth, aHeight); if (NS_FAILED(rv) || !mBullet) return rv; - PRInt32 bulletX, bulletY, bulletWidth, bulletHeight; + PRInt32 bulletX = 0, bulletY = 0, bulletWidth = 0, bulletHeight = 0; rv = mBullet->GetBounds(&bulletX, &bulletY, &bulletWidth, &bulletHeight); NS_ENSURE_SUCCESS(rv, rv); - *x = bulletX; // Move x coordinate of list item over to cover bullet as well - *width += bulletWidth; + *aX = bulletX; // Move x coordinate of list item over to cover bullet as well + *aWidth += bulletWidth; return NS_OK; } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLLIAccessible: public +// HTMLLIAccessible: public void -nsHTMLLIAccessible::UpdateBullet(bool aHasBullet) +HTMLLIAccessible::UpdateBullet(bool aHasBullet) { if (aHasBullet == !!mBullet) { NS_NOTREACHED("Bullet and accessible are in sync already!"); return; } nsDocAccessible* document = Document(); if (aHasBullet) { - mBullet = new nsHTMLListBulletAccessible(mContent, mDoc); + mBullet = new HTMLListBulletAccessible(mContent, mDoc); if (document->BindToDocument(mBullet, nsnull)) { InsertChildAt(0, mBullet); } } else { RemoveChild(mBullet); document->UnbindFromDocument(mBullet); mBullet = nsnull; } // XXXtodo: fire show/hide and reorder events. That's hard to make it // right now because coalescence happens by DOM node. } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLLIAccessible: nsAccessible protected +// HTMLLIAccessible: nsAccessible protected void -nsHTMLLIAccessible::CacheChildren() +HTMLLIAccessible::CacheChildren() { if (mBullet) AppendChild(mBullet); // Cache children from subtree. nsAccessibleWrap::CacheChildren(); } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLListBulletAccessible +// HTMLListBulletAccessible //////////////////////////////////////////////////////////////////////////////// -nsHTMLListBulletAccessible:: - nsHTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) -{ -} - //////////////////////////////////////////////////////////////////////////////// -// nsHTMLListBulletAccessible: nsAccessNode +// HTMLListBulletAccessible: nsAccessNode bool -nsHTMLListBulletAccessible::IsPrimaryForNode() const +HTMLListBulletAccessible::IsPrimaryForNode() const { return false; } //////////////////////////////////////////////////////////////////////////////// -// nsHTMLListBulletAccessible: nsAccessible +// HTMLListBulletAccessible: nsAccessible ENameValueFlag -nsHTMLListBulletAccessible::Name(nsString &aName) +HTMLListBulletAccessible::Name(nsString &aName) { aName.Truncate(); // Native anonymous content, ARIA can't be used. Get list bullet text. nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); NS_ASSERTION(blockFrame, "No frame for list item!"); if (blockFrame) { blockFrame->GetBulletText(aName); @@ -362,63 +167,35 @@ nsHTMLListBulletAccessible::Name(nsStrin // Append space otherwise bullets are jammed up against list text. aName.Append(' '); } return eNameOK; } role -nsHTMLListBulletAccessible::NativeRole() +HTMLListBulletAccessible::NativeRole() { return roles::STATICTEXT; } PRUint64 -nsHTMLListBulletAccessible::NativeState() +HTMLListBulletAccessible::NativeState() { PRUint64 state = nsLeafAccessible::NativeState(); state &= ~states::FOCUSABLE; state |= states::READONLY; return state; } void -nsHTMLListBulletAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, - PRUint32 aLength) +HTMLListBulletAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, + PRUint32 aLength) { nsAutoString bulletText; nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); NS_ASSERTION(blockFrame, "No frame for list item!"); if (blockFrame) blockFrame->GetBulletText(bulletText); aText.Append(Substring(bulletText, aStartOffset, aLength)); } - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLListAccessible -//////////////////////////////////////////////////////////////////////////////// - -nsHTMLListAccessible:: - nsHTMLListAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsHyperTextAccessibleWrap(aContent, aDoc) -{ -} - -NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLListAccessible, nsHyperTextAccessible) - -role -nsHTMLListAccessible::NativeRole() -{ - if (mContent->Tag() == nsGkAtoms::dl) - return roles::DEFINITION_LIST; - - return roles::LIST; -} - -PRUint64 -nsHTMLListAccessible::NativeState() -{ - return nsHyperTextAccessibleWrap::NativeState() | states::READONLY; -} -
copy from accessible/src/html/nsHTMLTextAccessible.h copy to accessible/src/html/HTMLListAccessible.h --- a/accessible/src/html/nsHTMLTextAccessible.h +++ b/accessible/src/html/HTMLListAccessible.h @@ -1,196 +1,104 @@ /* -*- 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 - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Aaron Leventhal (aaronl@netscape.com) - * Kyle Yuan (kyle.yuan@sun.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 ***** */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef _nsHTMLTextAccessible_H_ -#define _nsHTMLTextAccessible_H_ +#ifndef mozilla_a11y_HTMLListAccessible_h__ +#define mozilla_a11y_HTMLListAccessible_h__ -#include "nsTextAccessibleWrap.h" -#include "nsAutoPtr.h" +#include "nsHyperTextAccessibleWrap.h" #include "nsBaseWidgetAccessible.h" +namespace mozilla { +namespace a11y { + +class HTMLListBulletAccessible; + /** - * Used for text nodes within HTML document. + * Used for HTML list (like HTML ul). */ -class nsHTMLTextAccessible : public nsTextAccessibleWrap +class HTMLListAccessible : public nsHyperTextAccessibleWrap { public: - nsHTMLTextAccessible(nsIContent* aContent, nsDocAccessible* aDoc); + HTMLListAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : + nsHyperTextAccessibleWrap(aContent, aDoc) { } + virtual ~HTMLListAccessible() { } // nsISupports NS_DECL_ISUPPORTS_INHERITED // nsAccessible - virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); - virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes); - virtual mozilla::a11y::role NativeRole(); - virtual PRUint64 NativeState(); -}; - -/** - * Used for HTML hr element. - */ -class nsHTMLHRAccessible : public nsLeafAccessible -{ -public: - nsHTMLHRAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - // nsAccessible - virtual mozilla::a11y::role NativeRole(); -}; - -/** - * Used for HTML br element. - */ -class nsHTMLBRAccessible : public nsLeafAccessible -{ -public: - nsHTMLBRAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - // nsAccessible - virtual nsresult GetNameInternal(nsAString& aName); - virtual mozilla::a11y::role NativeRole(); + virtual a11y::role NativeRole(); virtual PRUint64 NativeState(); }; -/** - * Used for HTML label element. - */ -class nsHTMLLabelAccessible : public nsHyperTextAccessibleWrap -{ -public: - nsHTMLLabelAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - NS_DECL_ISUPPORTS_INHERITED - - // nsAccessible - virtual nsresult GetNameInternal(nsAString& aName); - virtual mozilla::a11y::role NativeRole(); -}; - -/** - * Used for HTML output element. - */ -class nsHTMLOutputAccessible : public nsHyperTextAccessibleWrap -{ -public: - nsHTMLOutputAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - NS_DECL_ISUPPORTS_INHERITED - - // nsAccessible - virtual mozilla::a11y::role NativeRole(); - virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes); - virtual Relation RelationByType(PRUint32 aType); -}; - -/** - * Used for bullet of HTML list item element (for example, HTML li). - */ -class nsHTMLListBulletAccessible : public nsLeafAccessible -{ -public: - nsHTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - // nsAccessNode - virtual bool IsPrimaryForNode() const; - - // nsAccessible - virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); - virtual mozilla::a11y::role NativeRole(); - virtual PRUint64 NativeState(); - virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0, - PRUint32 aLength = PR_UINT32_MAX); -}; - -/** - * Used for HTML list (like HTML ul). - */ -class nsHTMLListAccessible : public nsHyperTextAccessibleWrap -{ -public: - nsHTMLListAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - // nsISupports - NS_DECL_ISUPPORTS_INHERITED - - // nsAccessible - virtual mozilla::a11y::role NativeRole(); - virtual PRUint64 NativeState(); -}; /** * Used for HTML list item (e.g. HTML li). */ -class nsHTMLLIAccessible : public nsHyperTextAccessibleWrap +class HTMLLIAccessible : public nsHyperTextAccessibleWrap { public: - nsHTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc); + HTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc); + virtual ~HTMLLIAccessible() { } // nsISupports NS_DECL_ISUPPORTS_INHERITED // nsAccessNode virtual void Shutdown(); // nsIAccessible - NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height); + NS_IMETHOD GetBounds(PRInt32* aX, PRInt32* aY, + PRInt32* aWidth, PRInt32* aHeight); // nsAccessible - virtual mozilla::a11y::role NativeRole(); + virtual a11y::role NativeRole(); virtual PRUint64 NativeState(); // nsHTMLLIAccessible void UpdateBullet(bool aHasBullet); protected: // nsAccessible virtual void CacheChildren(); private: - nsRefPtr<nsHTMLListBulletAccessible> mBullet; + nsRefPtr<HTMLListBulletAccessible> mBullet; }; -inline nsHTMLLIAccessible* + +/** + * Used for bullet of HTML list item element (for example, HTML li). + */ +class HTMLListBulletAccessible : public nsLeafAccessible +{ +public: + HTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : + nsLeafAccessible(aContent, aDoc) { } + virtual ~HTMLListBulletAccessible() { } + + // nsAccessNode + virtual bool IsPrimaryForNode() const; + + // nsAccessible + virtual ENameValueFlag Name(nsString& aName); + virtual a11y::role NativeRole(); + virtual PRUint64 NativeState(); + virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0, + PRUint32 aLength = PR_UINT32_MAX); +}; + +} // namespace a11y +} // namespace mozilla + + +inline mozilla::a11y::HTMLLIAccessible* nsAccessible::AsHTMLListItem() { return mFlags & eHTMLListItemAccessible ? - static_cast<nsHTMLLIAccessible*>(this) : nsnull; + static_cast<mozilla::a11y::HTMLLIAccessible*>(this) : nsnull; } #endif
--- a/accessible/src/html/Makefile.in +++ b/accessible/src/html/Makefile.in @@ -47,16 +47,17 @@ MODULE = accessibility LIBRARY_NAME = accessibility_html_s LIBXUL_LIBRARY = 1 CPPSRCS = \ nsHTMLCanvasAccessible.cpp \ HTMLFormControlAccessible.cpp \ + HTMLListAccessible.cpp \ nsHTMLImageAccessible.cpp \ nsHTMLImageMapAccessible.cpp \ nsHTMLLinkAccessible.cpp \ nsHTMLSelectAccessible.cpp \ nsHTMLTableAccessible.cpp \ nsHTMLTextAccessible.cpp \ nsHyperTextAccessible.cpp \ $(NULL)
--- a/accessible/src/html/nsHTMLImageMapAccessible.h +++ b/accessible/src/html/nsHTMLImageMapAccessible.h @@ -100,21 +100,21 @@ public: virtual bool IsPrimaryForNode() const; // nsAccessible virtual void Description(nsString& aDescription); virtual nsresult GetNameInternal(nsAString& aName); virtual PRUint64 NativeState(); virtual nsAccessible* ChildAtPoint(PRInt32 aX, PRInt32 aY, EWhichChildAtPoint aWhichChild); + virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame); // HyperLinkAccessible virtual PRUint32 StartOffset(); virtual PRUint32 EndOffset(); protected: // nsAccessible virtual void CacheChildren(); - virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame); }; #endif
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp +++ b/accessible/src/html/nsHTMLSelectAccessible.cpp @@ -251,32 +251,16 @@ nsHTMLSelectOptionAccessible::GetNameInt txtValue.CompressWhitespace(); aName.Assign(txtValue); return NS_OK; } return NS_OK; } -// nsAccessible protected -nsIFrame* nsHTMLSelectOptionAccessible::GetBoundsFrame() -{ - PRUint64 state = 0; - nsIContent* content = GetSelectState(&state); - if (state & states::COLLAPSED) { - if (content) { - return content->GetPrimaryFrame(); - } - - return nsnull; - } - - return nsAccessible::GetBoundsFrame(); -} - PRUint64 nsHTMLSelectOptionAccessible::NativeState() { // As a nsHTMLSelectOptionAccessible we can have the following states: // SELECTABLE, SELECTED, FOCUSED, FOCUSABLE, OFFSCREEN // Upcall to nsAccessible, but skip nsHyperTextAccessible impl // because we don't want EDITABLE or SELECTABLE_TEXT PRUint64 state = nsAccessible::NativeState(); @@ -343,18 +327,26 @@ nsHTMLSelectOptionAccessible::GetLevelIn parentContent->NodeInfo()->Equals(nsGkAtoms::optgroup) ? 2 : 1; if (level == 1 && Role() != roles::HEADING) level = 0; // In a single level list, the level is irrelevant return level; } -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLSelectOptionAccessible: nsIAccessible +void +nsHTMLSelectOptionAccessible::GetBoundsRect(nsRect& aTotalBounds, + nsIFrame** aBoundingFrame) +{ + nsAccessible* combobox = GetCombobox(); + if (combobox && (combobox->State() & states::COLLAPSED)) + combobox->GetBoundsRect(aTotalBounds, aBoundingFrame); + else + nsHyperTextAccessibleWrap::GetBoundsRect(aTotalBounds, aBoundingFrame); +} /** select us! close combo box if necessary*/ NS_IMETHODIMP nsHTMLSelectOptionAccessible::GetActionName(PRUint8 aIndex, nsAString& aName) { if (aIndex == eAction_Select) { aName.AssignLiteral("select"); return NS_OK; } @@ -546,28 +538,25 @@ nsHTMLComboboxAccessible::Shutdown() nsAccessibleWrap::Shutdown(); if (mListAccessible) { mListAccessible->Shutdown(); mListAccessible = nsnull; } } -/** - */ PRUint64 nsHTMLComboboxAccessible::NativeState() { // As a nsHTMLComboboxAccessible we can have the following states: // FOCUSED, FOCUSABLE, HASPOPUP, EXPANDED, COLLAPSED // Get focus status from base class PRUint64 state = nsAccessible::NativeState(); - nsIFrame *frame = GetBoundsFrame(); - nsIComboboxControlFrame *comboFrame = do_QueryFrame(frame); + nsIComboboxControlFrame* comboFrame = do_QueryFrame(GetFrame()); if (comboFrame && comboFrame->IsDroppedDown()) state |= states::EXPANDED; else state |= states::COLLAPSED; state |= states::HASPOPUP; return state; } @@ -745,18 +734,17 @@ nsHTMLComboboxListAccessible::IsPrimaryF PRUint64 nsHTMLComboboxListAccessible::NativeState() { // As a nsHTMLComboboxListAccessible we can have the following states: // FOCUSED, FOCUSABLE, FLOATING, INVISIBLE // Get focus status from base class PRUint64 state = nsAccessible::NativeState(); - nsIFrame *boundsFrame = GetBoundsFrame(); - nsIComboboxControlFrame* comboFrame = do_QueryFrame(boundsFrame); + nsIComboboxControlFrame* comboFrame = do_QueryFrame(mParent->GetFrame()); if (comboFrame && comboFrame->IsDroppedDown()) state |= states::FLOATING; else state |= states::INVISIBLE; return state; }
--- a/accessible/src/html/nsHTMLSelectAccessible.h +++ b/accessible/src/html/nsHTMLSelectAccessible.h @@ -117,35 +117,45 @@ public: NS_IMETHOD SetSelected(bool aSelect); // nsAccessible virtual nsresult GetNameInternal(nsAString& aName); virtual mozilla::a11y::role NativeRole(); virtual PRUint64 NativeState(); virtual PRInt32 GetLevelInternal(); + virtual void GetBoundsRect(nsRect& aTotalBounds, nsIFrame** aBoundingFrame); // ActionAccessible virtual PRUint8 ActionCount(); // Widgets virtual nsAccessible* ContainerWidget() const; -protected: - // nsAccessible - virtual nsIFrame* GetBoundsFrame(); - private: /** * Get Select element's accessible state * @param aState, Select element state * @return Select element content, returns null if not avaliable */ nsIContent* GetSelectState(PRUint64* aState); + + /** + * Return a combobox accessible the option belongs to if any. + */ + nsAccessible* GetCombobox() const + { + if (mParent && mParent->IsListControl()) { + nsAccessible* combobox = mParent->Parent(); + return combobox->IsCombobox() ? combobox : nsnull; + } + + return nsnull; + } }; /* * Opt Groups inside the select, contained within the list */ class nsHTMLSelectOptGroupAccessible : public nsHTMLSelectOptionAccessible { public:
--- a/accessible/src/html/nsHTMLTextAccessible.cpp +++ b/accessible/src/html/nsHTMLTextAccessible.cpp @@ -36,29 +36,22 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsHTMLTextAccessible.h" #include "nsDocAccessible.h" #include "nsAccUtils.h" +#include "nsIAccessibleRelation.h" #include "nsTextEquivUtils.h" #include "Relation.h" #include "Role.h" #include "States.h" -#include "nsIAccessibleRelation.h" -#include "nsIFrame.h" -#include "nsPresContext.h" -#include "nsBlockFrame.h" -#include "nsISelection.h" -#include "nsISelectionController.h" -#include "nsComponentManagerUtils.h" - using namespace mozilla::a11y; //////////////////////////////////////////////////////////////////////////////// // nsHTMLTextAccessible //////////////////////////////////////////////////////////////////////////////// nsHTMLTextAccessible:: nsHTMLTextAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : @@ -222,203 +215,8 @@ nsHTMLOutputAccessible::GetAttributesInt NS_ENSURE_SUCCESS(rv, rv); nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::live, NS_LITERAL_STRING("polite")); return NS_OK; } - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLLIAccessible -//////////////////////////////////////////////////////////////////////////////// - -nsHTMLLIAccessible:: - nsHTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsHyperTextAccessibleWrap(aContent, aDoc), mBullet(nsnull) -{ - mFlags |= eHTMLListItemAccessible; - - nsBlockFrame* blockFrame = do_QueryFrame(GetFrame()); - if (blockFrame && blockFrame->HasBullet()) { - mBullet = new nsHTMLListBulletAccessible(mContent, mDoc); - if (!Document()->BindToDocument(mBullet, nsnull)) - mBullet = nsnull; - } -} - -NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLLIAccessible, nsHyperTextAccessible) - -void -nsHTMLLIAccessible::Shutdown() -{ - mBullet = nsnull; - - nsHyperTextAccessibleWrap::Shutdown(); -} - -role -nsHTMLLIAccessible::NativeRole() -{ - if (mContent->Tag() == nsGkAtoms::dt) - return roles::TERM; - - return roles::LISTITEM; -} - -PRUint64 -nsHTMLLIAccessible::NativeState() -{ - return nsHyperTextAccessibleWrap::NativeState() | states::READONLY; -} - -NS_IMETHODIMP nsHTMLLIAccessible::GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height) -{ - nsresult rv = nsAccessibleWrap::GetBounds(x, y, width, height); - if (NS_FAILED(rv) || !mBullet) - return rv; - - PRInt32 bulletX, bulletY, bulletWidth, bulletHeight; - rv = mBullet->GetBounds(&bulletX, &bulletY, &bulletWidth, &bulletHeight); - NS_ENSURE_SUCCESS(rv, rv); - - *x = bulletX; // Move x coordinate of list item over to cover bullet as well - *width += bulletWidth; - return NS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLLIAccessible: public - -void -nsHTMLLIAccessible::UpdateBullet(bool aHasBullet) -{ - if (aHasBullet == !!mBullet) { - NS_NOTREACHED("Bullet and accessible are in sync already!"); - return; - } - - nsDocAccessible* document = Document(); - if (aHasBullet) { - mBullet = new nsHTMLListBulletAccessible(mContent, mDoc); - if (document->BindToDocument(mBullet, nsnull)) { - InsertChildAt(0, mBullet); - } - } else { - RemoveChild(mBullet); - document->UnbindFromDocument(mBullet); - mBullet = nsnull; - } - - // XXXtodo: fire show/hide and reorder events. That's hard to make it - // right now because coalescence happens by DOM node. -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLLIAccessible: nsAccessible protected - -void -nsHTMLLIAccessible::CacheChildren() -{ - if (mBullet) - AppendChild(mBullet); - - // Cache children from subtree. - nsAccessibleWrap::CacheChildren(); -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLListBulletAccessible -//////////////////////////////////////////////////////////////////////////////// - -nsHTMLListBulletAccessible:: - nsHTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsLeafAccessible(aContent, aDoc) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLListBulletAccessible: nsAccessNode - -bool -nsHTMLListBulletAccessible::IsPrimaryForNode() const -{ - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLListBulletAccessible: nsAccessible - -ENameValueFlag -nsHTMLListBulletAccessible::Name(nsString &aName) -{ - aName.Truncate(); - - // Native anonymous content, ARIA can't be used. Get list bullet text. - nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); - NS_ASSERTION(blockFrame, "No frame for list item!"); - if (blockFrame) { - blockFrame->GetBulletText(aName); - - // Append space otherwise bullets are jammed up against list text. - aName.Append(' '); - } - - return eNameOK; -} - -role -nsHTMLListBulletAccessible::NativeRole() -{ - return roles::STATICTEXT; -} - -PRUint64 -nsHTMLListBulletAccessible::NativeState() -{ - PRUint64 state = nsLeafAccessible::NativeState(); - - state &= ~states::FOCUSABLE; - state |= states::READONLY; - return state; -} - -void -nsHTMLListBulletAccessible::AppendTextTo(nsAString& aText, PRUint32 aStartOffset, - PRUint32 aLength) -{ - nsAutoString bulletText; - nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame()); - NS_ASSERTION(blockFrame, "No frame for list item!"); - if (blockFrame) - blockFrame->GetBulletText(bulletText); - - aText.Append(Substring(bulletText, aStartOffset, aLength)); -} - -//////////////////////////////////////////////////////////////////////////////// -// nsHTMLListAccessible -//////////////////////////////////////////////////////////////////////////////// - -nsHTMLListAccessible:: - nsHTMLListAccessible(nsIContent* aContent, nsDocAccessible* aDoc) : - nsHyperTextAccessibleWrap(aContent, aDoc) -{ -} - -NS_IMPL_ISUPPORTS_INHERITED0(nsHTMLListAccessible, nsHyperTextAccessible) - -role -nsHTMLListAccessible::NativeRole() -{ - if (mContent->Tag() == nsGkAtoms::dl) - return roles::DEFINITION_LIST; - - return roles::LIST; -} - -PRUint64 -nsHTMLListAccessible::NativeState() -{ - return nsHyperTextAccessibleWrap::NativeState() | states::READONLY; -} -
--- a/accessible/src/html/nsHTMLTextAccessible.h +++ b/accessible/src/html/nsHTMLTextAccessible.h @@ -114,83 +114,9 @@ public: NS_DECL_ISUPPORTS_INHERITED // nsAccessible virtual mozilla::a11y::role NativeRole(); virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes); virtual Relation RelationByType(PRUint32 aType); }; -/** - * Used for bullet of HTML list item element (for example, HTML li). - */ -class nsHTMLListBulletAccessible : public nsLeafAccessible -{ -public: - nsHTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - // nsAccessNode - virtual bool IsPrimaryForNode() const; - - // nsAccessible - virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); - virtual mozilla::a11y::role NativeRole(); - virtual PRUint64 NativeState(); - virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0, - PRUint32 aLength = PR_UINT32_MAX); -}; - -/** - * Used for HTML list (like HTML ul). - */ -class nsHTMLListAccessible : public nsHyperTextAccessibleWrap -{ -public: - nsHTMLListAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - // nsISupports - NS_DECL_ISUPPORTS_INHERITED - - // nsAccessible - virtual mozilla::a11y::role NativeRole(); - virtual PRUint64 NativeState(); -}; - -/** - * Used for HTML list item (e.g. HTML li). - */ -class nsHTMLLIAccessible : public nsHyperTextAccessibleWrap -{ -public: - nsHTMLLIAccessible(nsIContent* aContent, nsDocAccessible* aDoc); - - // nsISupports - NS_DECL_ISUPPORTS_INHERITED - - // nsAccessNode - virtual void Shutdown(); - - // nsIAccessible - NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height); - - // nsAccessible - virtual mozilla::a11y::role NativeRole(); - virtual PRUint64 NativeState(); - - // nsHTMLLIAccessible - void UpdateBullet(bool aHasBullet); - -protected: - // nsAccessible - virtual void CacheChildren(); - -private: - nsRefPtr<nsHTMLListBulletAccessible> mBullet; -}; - -inline nsHTMLLIAccessible* -nsAccessible::AsHTMLListItem() -{ - return mFlags & eHTMLListItemAccessible ? - static_cast<nsHTMLLIAccessible*>(this) : nsnull; -} - #endif
--- a/accessible/src/jsat/AccessFu.jsm +++ b/accessible/src/jsat/AccessFu.jsm @@ -48,57 +48,52 @@ var AccessFu = { } catch (x) { } if (this.amINeeded(accessPref)) this.enable(); }, /** - * Start the special AccessFu mode, this primarily means controlling the virtual - * cursor with arrow keys. Currently, on platforms other than Android this needs - * to be called explicitly. + * Start AccessFu mode, this primarily means controlling the virtual cursor + * with arrow keys. */ enable: function enable() { dump('AccessFu enable'); this.addPresenter(new VisualPresenter()); // Implicitly add the Android presenter on Android. if (Services.appinfo.OS == 'Android') this.addPresenter(new AndroidPresenter()); VirtualCursorController.attach(this.chromeWin); Services.obs.addObserver(this, 'accessible-event', false); this.chromeWin.addEventListener('DOMActivate', this, true); this.chromeWin.addEventListener('resize', this, true); this.chromeWin.addEventListener('scroll', this, true); this.chromeWin.addEventListener('TabOpen', this, true); - this.chromeWin.addEventListener('TabSelect', this, true); - this.chromeWin.addEventListener('TabClosed', this, true); }, /** * Disable AccessFu and return to default interaction mode. */ disable: function disable() { dump('AccessFu disable'); - this.presenters.forEach(function(p) {p.detach();}); + this.presenters.forEach(function(p) { p.detach(); }); this.presenters = []; VirtualCursorController.detach(); - Services.obs.addObserver(this, 'accessible-event', false); - this.chromeWin.removeEventListener('DOMActivate', this); - this.chromeWin.removeEventListener('resize', this); - this.chromeWin.removeEventListener('scroll', this); - this.chromeWin.removeEventListener('TabOpen', this); - this.chromeWin.removeEventListener('TabSelect', this); - this.chromeWin.removeEventListener('TabClose', this); + Services.obs.removeObserver(this, 'accessible-event'); + this.chromeWin.removeEventListener('DOMActivate', this, true); + this.chromeWin.removeEventListener('resize', this, true); + this.chromeWin.removeEventListener('scroll', this, true); + this.chromeWin.removeEventListener('TabOpen', this, true); }, amINeeded: function(aPref) { switch (aPref) { case ACCESSFU_ENABLE: return true; case ACCESSFU_AUTO: if (Services.appinfo.OS == 'Android') { @@ -120,24 +115,27 @@ var AccessFu = { addPresenter: function addPresenter(presenter) { this.presenters.push(presenter); presenter.attach(this.chromeWin); }, handleEvent: function handleEvent(aEvent) { switch (aEvent.type) { - case 'TabSelect': - { - this.getDocAccessible( - function(docAcc) { - this.presenters.forEach(function(p) {p.tabSelected(docAcc);}); - }); - break; - } + case 'TabOpen': + { + let browser = aEvent.target.linkedBrowser || aEvent.target; + // Store the new browser node. We will need to check later when a new + // content document is attached if it has been attached to this new tab. + // If it has, than we will need to send a 'loading' message along with + // the usual 'newdoc' to presenters. + this._pendingDocuments[browser] = true; + this.presenters.forEach(function(p) { p.tabStateChanged(null, 'newtab'); }); + break; + } case 'DOMActivate': { let activatedAcc = getAccessible(aEvent.originalTarget); let state = {}; activatedAcc.getState(state, {}); // Checkable objects will have a state changed event that we will use // instead of this hackish DOMActivate. We will also know the true @@ -148,35 +146,22 @@ var AccessFu = { this.presenters.forEach(function(p) { p.actionInvoked(activatedAcc, 'click'); }); break; } case 'scroll': case 'resize': { - this.presenters.forEach(function(p) {p.viewportChanged();}); + this.presenters.forEach(function(p) { p.viewportChanged(); }); break; } } }, - getDocAccessible: function getDocAccessible(aCallback) { - let browserApp = (Services.appinfo.OS == 'Android') ? - this.chromeWin.BrowserApp : this.chromeWin.gBrowser; - - let docAcc = getAccessible(browserApp.selectedBrowser.contentDocument); - if (!docAcc) { - // Wait for a reorder event fired by the parent of the new doc. - this._pendingDocuments[browserApp.selectedBrowser] = aCallback; - } else { - aCallback.apply(this, [docAcc]); - } - }, - observe: function observe(aSubject, aTopic, aData) { switch (aTopic) { case 'nsPref:changed': if (aData == 'accessfu') { if (this.amINeeded(this.prefsBranch.getIntPref('accessfu'))) this.enable(); else this.disable(); @@ -218,26 +203,96 @@ var AccessFu = { !(event.isExtraState())) { this.presenters.forEach( function(p) { p.actionInvoked(aEvent.accessible, event.isEnabled() ? 'check' : 'uncheck'); } ); } + else if (event.state == Ci.nsIAccessibleStates.STATE_BUSY && + !(event.isExtraState()) && event.isEnabled()) { + let role = event.accessible.role; + if ((role == Ci.nsIAccessibleRole.ROLE_DOCUMENT || + role == Ci.nsIAccessibleRole.ROLE_APPLICATION)) { + // An existing document has changed to state "busy", this means + // something is loading. Send a 'loading' message to presenters. + this.presenters.forEach( + function(p) { + p.tabStateChanged(event.accessible, 'loading'); + } + ); + } + } break; } case Ci.nsIAccessibleEvent.EVENT_REORDER: { - let node = aEvent.accessible.DOMNode; - let callback = this._pendingDocuments[node]; - if (callback && aEvent.accessible.childCount) { - // We have a callback associated with a document. - callback.apply(this, [aEvent.accessible.getChildAt(0)]); - delete this._pendingDocuments[node]; + let acc = aEvent.accessible; + if (acc.childCount) { + let docAcc = acc.getChildAt(0); + if (this._pendingDocuments[aEvent.DOMNode]) { + // This is a document in a new tab. Check if it is + // in a BUSY state (i.e. loading), and inform presenters. + // We need to do this because a state change event will not be + // fired when an object is created with the BUSY state. + // If this is not a new tab, don't bother because we sent 'loading' + // when the previous doc changed its state to BUSY. + let state = {}; + docAcc.getState(state, {}); + if (state.value & Ci.nsIAccessibleStates.STATE_BUSY && + this.isNotChromeDoc(docAcc)) + this.presenters.forEach( + function(p) { p.tabStateChanged(docAcc, 'loading'); } + ); + delete this._pendingDocuments[aEvent.DOMNode]; + } + if (this.isBrowserDoc(docAcc)) + // A new top-level content document has been attached + this.presenters.forEach( + function(p) { p.tabStateChanged(docAcc, 'newdoc'); } + ); + } + break; + } + case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE: + { + if (this.isNotChromeDoc(aEvent.accessible)) { + this.presenters.forEach( + function(p) { + p.tabStateChanged(aEvent.accessible, 'loaded'); + } + ); + } + break; + } + case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_STOPPED: + { + this.presenters.forEach( + function(p) { + p.tabStateChanged(aEvent.accessible, 'loadstopped'); + } + ); + break; + } + case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_RELOAD: + { + this.presenters.forEach( + function(p) { + p.tabStateChanged(aEvent.accessible, 'reload'); + } + ); + break; + } + case Ci.nsIAccessibleEvent.EVENT_FOCUS: + { + if (this.isBrowserDoc(aEvent.accessible)) { + // The document recieved focus, call tabSelected to present current tab. + this.presenters.forEach( + function(p) { p.tabSelected(aEvent.accessible); }); } break; } case Ci.nsIAccessibleEvent.EVENT_TEXT_INSERTED: case Ci.nsIAccessibleEvent.EVENT_TEXT_REMOVED: { if (aEvent.isFromUserInput) { // XXX support live regions as well. @@ -264,16 +319,48 @@ var AccessFu = { } break; } default: break; } }, + /** + * Check if accessible is a top-level content document (i.e. a child of a XUL + * browser node). + * @param {nsIAccessible} aDocAcc the accessible to check. + * @return {boolean} true if this is a top-level content document. + */ + isBrowserDoc: function isBrowserDoc(aDocAcc) { + let parent = aDocAcc.parent; + if (!parent) + return false; + + let domNode = parent.DOMNode; + if (!domNode) + return false; + + const ns = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; + return (domNode.localName == 'browser' && domNode.namespaceURI == ns); + }, + + /** + * Check if document is not a local "chrome" document, like about:home. + * @param {nsIDOMDocument} aDocument the document to check. + * @return {boolean} true if this is not a chrome document. + */ + isNotChromeDoc: function isNotChromeDoc(aDocument) { + let location = aDocument.DOMNode.location; + if (!location) + return false; + + return location.protocol != "about:"; + }, + getNewContext: function getNewContext(aOldObject, aNewObject) { let newLineage = []; let oldLineage = []; let parent = aNewObject; while ((parent = parent.parent)) newLineage.push(parent);
--- a/accessible/src/jsat/Presenters.jsm +++ b/accessible/src/jsat/Presenters.jsm @@ -61,25 +61,31 @@ Presenter.prototype = { /** * Selection has changed. TODO. * @param {nsIAccessible} aObject the object that has been selected. */ selectionChanged: function selectionChanged(aObject) {}, /** - * The page state has changed, loading, stopped loading, etc. TODO. + * The tab, or the tab's document state has changed. + * @param {nsIAccessible} aDocObj the tab document accessible that has had its + * state changed, or null if the tab has no associated document yet. + * @param {string} aPageState the state name for the tab, valid states are: + * 'newtab', 'loading', 'newdoc', 'loaded', 'stopped', and 'reload'. */ - pageStateChanged: function pageStateChanged() {}, + tabStateChanged: function tabStateChanged(aDocObj, aPageState) {}, /** - * The tab has changed. - * @param {nsIAccessible} aObject the document contained in the tab. + * The current tab has changed. + * @param {nsIAccessible} aObject the document contained by the tab + * accessible, or null if it is a new tab with no attached + * document yet. */ - tabSelected: function tabSelected(aObject) {}, + tabSelected: function tabSelected(aDocObj) {}, /** * The viewport has changed, either a scroll, pan, zoom, or * landscape/portrait toggle. */ viewportChanged: function viewportChanged() {} }; @@ -142,19 +148,27 @@ VisualPresenter.prototype.pivotChanged = aObject.scrollTo(Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE); this.highlight(aObject); } catch (e) { dump('Error getting bounds: ' + e); return; } }; -VisualPresenter.prototype.tabSelected = function(aObject) { - let vcDoc = aObject.QueryInterface(Ci.nsIAccessibleCursorable); - this.pivotChanged(vcDoc.virtualCursor.position); +VisualPresenter.prototype.tabSelected = function(aDocObj) { + let vcPos = aDocObj ? + aDocObj.QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor.position : + null; + + this.pivotChanged(vcPos); +}; + +VisualPresenter.prototype.tabStateChanged = function(aDocObj, aPageState) { + if (aPageState == "newdoc") + this.pivotChanged(null); }; // Internals VisualPresenter.prototype.hide = function hide() { this.highlightBox.style.display = 'none'; }; @@ -237,26 +251,50 @@ AndroidPresenter.prototype.actionInvoked gecko: { type: 'Accessibility:Event', eventType: ANDROID_TYPE_VIEW_CLICKED, text: UtteranceGenerator.genForAction(aObject, aActionName) } }); }; -AndroidPresenter.prototype.tabSelected = function(aObject) { - let vcDoc = aObject.QueryInterface(Ci.nsIAccessibleCursorable); +AndroidPresenter.prototype.tabSelected = function(aDocObj) { + // Send a pivot change message with the full context utterance for this doc. + let vcDoc = aDocObj.QueryInterface(Ci.nsIAccessibleCursorable); let context = []; - let parent = vcDoc.virtualCursor.position || aObject; - while ((parent = parent.parent)) + let parent = vcDoc.virtualCursor.position || aDocObj; + while ((parent = parent.parent)) { context.push(parent); + if (parent == aDocObj) + break; + } + context.reverse(); - this.pivotChanged(vcDoc.virtualCursor.position || aObject, context); + this.pivotChanged(vcDoc.virtualCursor.position || aDocObj, context); +}; + +AndroidPresenter.prototype.tabStateChanged = function(aDocObj, aPageState) { + let stateUtterance = UtteranceGenerator. + genForTabStateChange(aDocObj, aPageState); + + if (!stateUtterance.length) + return; + + this.sendMessageToJava({ + gecko: { + type: 'Accessibility:Event', + eventType: ANDROID_TYPE_VIEW_TEXT_CHANGED, + text: stateUtterance, + addedCount: stateUtterance.join(' ').length, + removedCount: 0, + fromIndex: 0 + } + }); }; AndroidPresenter.prototype.textChanged = function(aIsInserted, aStart, aLength, aText, aModifiedText) { let androidEvent = { type: 'Accessibility:Event', eventType: ANDROID_TYPE_VIEW_TEXT_CHANGED, text: [aText], fromIndex: aStart
--- a/accessible/src/jsat/UtteranceGenerator.jsm +++ b/accessible/src/jsat/UtteranceGenerator.jsm @@ -17,16 +17,32 @@ var gStringBundle = Cc['@mozilla.org/int getService(Ci.nsIStringBundleService). createBundle('chrome://global/locale/AccessFu.properties'); var gAccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1']. getService(Ci.nsIAccessibleRetrieval); var EXPORTED_SYMBOLS = ['UtteranceGenerator']; +/** + * Generates speech utterances from objects, actions and state changes. + * An utterance is an array of strings. + * + * It should not be assumed that flattening an utterance array would create a + * gramatically correct sentence. For example, {@link genForObject} might + * return: ['graphic', 'Welcome to my home page']. + * Each string element in an utterance should be gramatically correct in itself. + * Another example from {@link genForObject}: ['list item 2 of 5', 'Alabama']. + * + * An utterance is ordered from the least to the most important. Speaking the + * last string usually makes sense, but speaking the first often won't. + * For example {@link genForAction} might return ['button', 'clicked'] for a + * clicked event. Speaking only 'clicked' makes sense. Speaking 'button' does + * not. + */ var UtteranceGenerator = { gActionMap: { jump: 'jumpAction', press: 'pressAction', check: 'checkAction', uncheck: 'uncheckAction', select: 'selectAction', open: 'openAction', @@ -34,34 +50,82 @@ var UtteranceGenerator = { switch: 'switchAction', click: 'clickAction', collapse: 'collapseAction', expand: 'expandAction', activate: 'activateAction', cycle: 'cycleAction' }, + + /** + * Generates an utterance for an object. + * @param {nsIAccessible} aAccessible accessible object to generate utterance + * for. + * @param {boolean} aForceName include the object's name in the utterance + * even if this object type does not usually have it's name uttered. + * @return {Array} Two string array. The first string describes the object + * and its states. The second string is the object's name. Some object + * types may have the description or name omitted, instead an empty string + * is returned as a placeholder. Whether the object's description or it's role + * is included is determined by {@link verbosityRoleMap}. + */ genForObject: function(aAccessible, aForceName) { let roleString = gAccRetrieval.getStringRole(aAccessible.role); let func = this.objectUtteranceFunctions[roleString] || this.objectUtteranceFunctions.defaultFunc; let flags = this.verbosityRoleMap[roleString] || 0; if (aForceName) flags |= INCLUDE_NAME; return func.apply(this, [aAccessible, roleString, flags]); }, + /** + * Generates an utterance for an action performed. + * TODO: May become more verbose in the future. + * @param {nsIAccessible} aAccessible accessible object that the action was + * invoked in. + * @param {string} aActionName the name of the action, one of the keys in + * {@link gActionMap}. + * @return {Array} A one string array with the action. + */ genForAction: function(aObject, aActionName) { return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])]; }, + /** + * Generates an utterance for a tab state change. + * @param {nsIAccessible} aAccessible accessible object of the tab's attached + * document. + * @param {string} aTabState the tab state name, see + * {@link Presenter.tabStateChanged}. + * @return {Array} The tab state utterace. + */ + genForTabStateChange: function (aObject, aTabState) { + switch (aTabState) { + case 'newtab': + return [gStringBundle.GetStringFromName('tabNew')]; + case 'loading': + return [gStringBundle.GetStringFromName('tabLoading')]; + case 'loaded': + return [aObject.name || '', + gStringBundle.GetStringFromName('tabLoaded')]; + case 'loadstopped': + return [gStringBundle.GetStringFromName('tabLoadStopped')]; + case 'reload': + return [gStringBundle.GetStringFromName('tabReload')]; + default: + return []; + } + }, + verbosityRoleMap: { 'menubar': INCLUDE_ROLE, 'scrollbar': INCLUDE_ROLE, 'grip': INCLUDE_ROLE, 'alert': INCLUDE_ROLE, 'menupopup': INCLUDE_ROLE, 'menuitem': INCLUDE_ROLE, 'tooltip': INCLUDE_ROLE, @@ -110,57 +174,71 @@ var UtteranceGenerator = { 'option': INCLUDE_ROLE, 'listbox': INCLUDE_ROLE}, objectUtteranceFunctions: { defaultFunc: function defaultFunc(aAccessible, aRoleStr, aFlags) { let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : ''; let desc = (aFlags & INCLUDE_ROLE) ? this._getLocalizedRole(aRoleStr) : ''; - if (!name && !desc) - return []; + let utterance = []; + + if (desc) { + let state = {}; + let extState = {}; + aAccessible.getState(state, extState); - let state = {}; - let extState = {}; - aAccessible.getState(state, extState); + if (state.value & Ci.nsIAccessibleStates.STATE_CHECKABLE) { + let stateStr = (state.value & Ci.nsIAccessibleStates.STATE_CHECKED) ? + 'objChecked' : 'objNotChecked'; + desc = gStringBundle.formatStringFromName(stateStr, [desc], 1); + } - if (state.value & Ci.nsIAccessibleStates.STATE_CHECKABLE) { - let stateStr = (state.value & Ci.nsIAccessibleStates.STATE_CHECKED) ? - 'objChecked' : 'objNotChecked'; - desc = gStringBundle.formatStringFromName(stateStr, [desc], 1); + if (extState.value & Ci.nsIAccessibleStates.EXT_STATE_EXPANDABLE) { + let stateStr = (state.value & Ci.nsIAccessibleStates.STATE_EXPANDED) ? + 'objExpanded' : 'objCollapsed'; + desc = gStringBundle.formatStringFromName(stateStr, [desc], 1); + } + + utterance.push(desc); } - if (extState.value & Ci.nsIAccessibleStates.EXT_STATE_EXPANDABLE) { - let stateStr = (state.value & Ci.nsIAccessibleStates.STATE_EXPANDED) ? - 'objExpanded' : 'objCollapsed'; - desc = gStringBundle.formatStringFromName(stateStr, [desc], 1); - } + if (name) + utterance.push(name); - return [desc, name]; + return utterance; }, heading: function(aAccessible, aRoleStr, aFlags) { let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : ''; let level = {}; aAccessible.groupPosition(level, {}, {}); - let desc = gStringBundle.formatStringFromName('headingLevel', - [level.value], 1); - return [desc, name]; + let utterance = + [gStringBundle.formatStringFromName('headingLevel', [level.value], 1)]; + + if (name) + utterance.push(name); + + return utterance; }, listitem: function(aAccessible, aRoleStr, aFlags) { let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : ''; let localizedRole = this._getLocalizedRole(aRoleStr); let itemno = {}; let itemof = {}; aAccessible.groupPosition({}, itemof, itemno); - let desc = gStringBundle.formatStringFromName( - 'objItemOf', [localizedRole, itemno.value, itemof.value], 3); + let utterance = + [gStringBundle.formatStringFromName( + 'objItemOf', [localizedRole, itemno.value, itemof.value], 3)]; - return [desc, name]; + if (name) + utterance.push(name); + + return utterance; } }, _getLocalizedRole: function _getLocalizedRole(aRoleStr) { try { return gStringBundle.GetStringFromName(aRoleStr.replace(' ', '')); } catch (x) { return '';
--- a/accessible/src/jsat/VirtualCursorController.jsm +++ b/accessible/src/jsat/VirtualCursorController.jsm @@ -19,17 +19,17 @@ var gAccRetrieval = Cc['@mozilla.org/acc var VirtualCursorController = { attach: function attach(aWindow) { this.chromeWin = aWindow; this.chromeWin.document.addEventListener('keypress', this.onkeypress, true); }, detach: function detach() { - this.chromeWin.document.removeEventListener('keypress', this.onkeypress); + this.chromeWin.document.removeEventListener('keypress', this.onkeypress, true); }, getBrowserApp: function getBrowserApp() { switch (Services.appinfo.OS) { case 'Android': return this.chromeWin.BrowserApp; default: return this.chromeWin.gBrowser; @@ -109,43 +109,72 @@ var VirtualCursorController = { getVirtualCursor: function getVirtualCursor(document) { return gAccRetrieval.getAccessibleFor(document). QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor; }, SimpleTraversalRule: { getMatchRoles: function(aRules) { - aRules.value = []; - return 0; + aRules.value = this._matchRoles; + return this._matchRoles.length; }, preFilter: Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT | Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE, match: function(aAccessible) { - if (aAccessible.childCount) - // Non-leafs do not interest us. - return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE; - - // XXX: Find a better solution for ROLE_STATICTEXT. - // It allows to filter list bullets but the same time it - // filters CSS generated content too as unwanted side effect. - let ignoreRoles = [Ci.nsIAccessibleRole.ROLE_WHITESPACE, - Ci.nsIAccessibleRole.ROLE_STATICTEXT]; - - if (ignoreRoles.indexOf(aAccessible.role) < 0) { - let name = aAccessible.name; - if (name && name.trim()) + switch (aAccessible.role) { + case Ci.nsIAccessibleRole.ROLE_COMBOBOX: + // We don't want to ignore the subtree because this is often + // where the list box hangs out. + return Ci.nsIAccessibleTraversalRule.FILTER_MATCH; + case Ci.nsIAccessibleRole.ROLE_TEXT_LEAF: + { + // Nameless text leaves are boring, skip them. + let name = aAccessible.name; + if (name && name.trim()) + return Ci.nsIAccessibleTraversalRule.FILTER_MATCH; + else + return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE; + } + case Ci.nsIAccessibleRole.ROLE_LINK: + // If the link has children we should land on them instead. + // Image map links don't have children so we need to match those. + if (aAccessible.childCount == 0) return Ci.nsIAccessibleTraversalRule.FILTER_MATCH; + else + return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE; + default: + // Ignore the subtree, if there is one. So that we don't land on + // the same content that was already presented by its parent. + return Ci.nsIAccessibleTraversalRule.FILTER_MATCH | + Ci.nsIAccessibleTraversalRule.FILTER_IGNORE_SUBTREE; } - - let state = {}; - aAccessible.getState(state, {}); - if (state.value & Ci.nsIAccessibleStates.STATE_FOCUSABLE) - return Ci.nsIAccessibleTraversalRule.FILTER_MATCH; - - return Ci.nsIAccessibleTraversalRule.FILTER_IGNORE; }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule]) + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessibleTraversalRule]), + + _matchRoles: [ + Ci.nsIAccessibleRole.ROLE_MENUITEM, + Ci.nsIAccessibleRole.ROLE_LINK, + Ci.nsIAccessibleRole.ROLE_PAGETAB, + Ci.nsIAccessibleRole.ROLE_GRAPHIC, + // XXX: Find a better solution for ROLE_STATICTEXT. + // It allows to filter list bullets but at the same time it + // filters CSS generated content too as an unwanted side effect. + // Ci.nsIAccessibleRole.ROLE_STATICTEXT, + Ci.nsIAccessibleRole.ROLE_TEXT_LEAF, + Ci.nsIAccessibleRole.ROLE_PUSHBUTTON, + Ci.nsIAccessibleRole.ROLE_CHECKBUTTON, + Ci.nsIAccessibleRole.ROLE_RADIOBUTTON, + Ci.nsIAccessibleRole.ROLE_COMBOBOX, + Ci.nsIAccessibleRole.ROLE_PROGRESSBAR, + Ci.nsIAccessibleRole.ROLE_BUTTONDROPDOWN, + Ci.nsIAccessibleRole.ROLE_BUTTONMENU, + Ci.nsIAccessibleRole.ROLE_CHECK_MENU_ITEM, + Ci.nsIAccessibleRole.ROLE_PASSWORD_TEXT, + Ci.nsIAccessibleRole.ROLE_RADIO_MENU_ITEM, + Ci.nsIAccessibleRole.ROLE_TOGGLE_BUTTON, + Ci.nsIAccessibleRole.ROLE_ENTRY + ] } };
--- a/accessible/src/mac/mozAccessible.mm +++ b/accessible/src/mac/mozAccessible.mm @@ -448,17 +448,17 @@ GetNativeFromGeckoAccessible(nsIAccessib mGeckoAccessible->GetBounds (&x, &y, &width, &height); return [NSValue valueWithSize:NSMakeSize (width, height)]; NS_OBJC_END_TRY_ABORT_BLOCK_NIL; } - (NSString*)role { -#ifdef DEBUG_A11Y +#ifdef DEBUG NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(mGeckoAccessible), "Does not support nsIAccessibleText when it should"); #endif #define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role) \ case roles::geckoRole: \ return macRole;
--- a/accessible/src/msaa/nsAccessibleWrap.cpp +++ b/accessible/src/msaa/nsAccessibleWrap.cpp @@ -367,17 +367,17 @@ STDMETHODIMP nsAccessibleWrap::get_accRo nsAccessible* xpAccessible = GetXPAccessibleFor(varChild); if (!xpAccessible) return E_INVALIDARG; if (xpAccessible->IsDefunct()) return CO_E_OBJNOTCONNECTED; -#ifdef DEBUG_A11Y +#ifdef DEBUG NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(xpAccessible), "Does not support nsIAccessibleText when it should"); #endif a11y::role geckoRole = xpAccessible->Role(); PRUint32 msaaRole = 0; #define ROLE(_geckoRole, stringRole, atkRole, macRole, _msaaRole, ia2Role) \ @@ -1665,17 +1665,17 @@ nsAccessibleWrap::FirePlatformEvent(AccE nsIContent* cnt = accessible->GetContent(); if (cnt) { cnt->Tag()->ToString(tag); nsIAtom* aid = cnt->GetID(); if (aid) aid->ToUTF8String(id); } -#ifdef DEBUG_A11Y +#ifdef DEBUG printf("\n\nMSAA event: event: %d, target: %s@id='%s', childid: %d, hwnd: %d\n\n", eventType, NS_ConvertUTF16toUTF8(tag).get(), id.get(), childID, hWnd); #endif // Fire MSAA event for client area window. ::NotifyWinEvent(winEvent, hWnd, OBJID_CLIENT, childID);
--- a/accessible/src/xul/nsXULMenuAccessible.cpp +++ b/accessible/src/xul/nsXULMenuAccessible.cpp @@ -458,33 +458,29 @@ nsXULMenupopupAccessible:: mSelectControl = do_QueryInterface(mContent->GetParent()); } PRUint64 nsXULMenupopupAccessible::NativeState() { PRUint64 state = nsAccessible::NativeState(); -#ifdef DEBUG_A11Y +#ifdef DEBUG // We are onscreen if our parent is active - bool isActive = mContent->HasAttr(kNameSpaceID_None, - nsGkAtoms::menuactive); + bool isActive = mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::menuactive); if (!isActive) { nsAccessible* parent = Parent(); - if (!parent) - return state; - - nsIContent *parentContent = parnet->GetContent(); - NS_ENSURE_TRUE(parentContent, state); - - isActive = parentContent->HasAttr(kNameSpaceID_None, - nsGkAtoms::open); + if (parent) { + nsIContent* parentContent = parent->GetContent(); + if (parentContent) + isActive = parentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::open); + } } - NS_ASSERTION(isActive || states & states::INVISIBLE, + NS_ASSERTION(isActive || (state & states::INVISIBLE), "XULMenupopup doesn't have INVISIBLE when it's inactive"); #endif if (state & states::INVISIBLE) state |= states::OFFSCREEN | states::COLLAPSED; return state; }
--- a/accessible/src/xul/nsXULTabAccessible.cpp +++ b/accessible/src/xul/nsXULTabAccessible.cpp @@ -155,17 +155,17 @@ nsXULTabAccessible::RelationByType(PRUin nsCOMPtr<nsIDOMNode> domNode(DOMNode()); nsCOMPtr<nsIDOMNode> tabpanelNode; tabsElm->GetRelatedElement(domNode, getter_AddRefs(tabpanelNode)); if (!tabpanelNode) return rel; nsCOMPtr<nsIContent> tabpanelContent(do_QueryInterface(tabpanelNode)); - rel.AppendTarget(tabpanelContent); + rel.AppendTarget(mDoc, tabpanelContent); return rel; } //////////////////////////////////////////////////////////////////////////////// // nsXULTabsAccessible //////////////////////////////////////////////////////////////////////////////// @@ -249,11 +249,11 @@ nsXULTabpanelAccessible::RelationByType( nsCOMPtr<nsIDOMNode> domNode(DOMNode()); nsCOMPtr<nsIDOMNode> tabNode; tabpanelsElm->GetRelatedElement(domNode, getter_AddRefs(tabNode)); if (!tabNode) return rel; nsCOMPtr<nsIContent> tabContent(do_QueryInterface(tabNode)); - rel.AppendTarget(tabContent); + rel.AppendTarget(mDoc, tabContent); return rel; }
--- a/accessible/tests/mochitest/bounds/Makefile.in +++ b/accessible/tests/mochitest/bounds/Makefile.in @@ -41,13 +41,14 @@ topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ relativesrcdir = accessible/bounds include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _TEST_FILES =\ + test_select.html \ test_zoom.html \ $(NULL) libs:: $(_TEST_FILES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644 --- /dev/null +++ b/accessible/tests/mochitest/bounds/test_select.html @@ -0,0 +1,85 @@ +<!DOCTYPE html> +<html> +<head> + <title>Accessible boundaries when page is zoomed</title> + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../layout.js"></script> + <script type="application/javascript" + src="../events.js"></script> + + <script type="application/javascript"> + function openComboboxNCheckBounds(aID) + { + this.combobox = getAccessible(aID); + this.comboboxList = this.combobox.firstChild; + this.comboboxOption = this.comboboxList.firstChild; + + this.eventSeq = [ + new invokerChecker(EVENT_FOCUS, this.comboboxOption) + ]; + + this.invoke = function openComboboxNCheckBounds_invoke() + { + getNode(aID).focus(); + synthesizeKey("VK_DOWN", { altKey: true }); + } + + this.finalCheck = function openComboboxNCheckBounds_invoke() + { + testBounds(this.comboboxOption); + } + + this.getID = function openComboboxNCheckBounds_getID() + { + return "open combobox and test boundaries"; + } + } + + //gA11yEventDumpToConsole = true; + + var gQueue = null; + + function doTest() + { + // Combobox + testBounds("combobox"); + + // Option boundaries matches to combobox boundaries when collapsed. + var selectBounds = getBoundsForDOMElm("combobox"); + testBounds("option1", selectBounds); + + // Open combobox and test option boundaries. + gQueue = new eventQueue(); + gQueue.push(new openComboboxNCheckBounds("combobox")); + gQueue.invoke(); // Will call SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <select id="combobox"> + <option id="option1">item1</option> + <option>item2</option> + </select> +</body> +</html>
--- a/accessible/tests/mochitest/layout.js +++ b/accessible/tests/mochitest/layout.js @@ -89,20 +89,20 @@ function getChildAtPoint(aIdentifier, aX } catch (e) { } return null; } /** * Test the accessible boundaries. */ -function testBounds(aID) +function testBounds(aID, aRect) { var [expectedX, expectedY, expectedWidth, expectedHeight] = - getBoundsForDOMElm(aID); + (aRect != undefined) ? aRect : getBoundsForDOMElm(aID); var [x, y, width, height] = getBounds(aID); is(x, expectedX, "Wrong x coordinate of " + prettyName(aID)); is(y, expectedY, "Wrong y coordinate of " + prettyName(aID)); is(width, expectedWidth, "Wrong width of " + prettyName(aID)); is(height, expectedHeight, "Wrong height of " + prettyName(aID)); } @@ -161,11 +161,14 @@ function getBoundsForDOMElm(aID) function CSSToDevicePixels(aWindow, aX, aY, aWidth, aHeight) { var winUtil = aWindow. QueryInterface(Components.interfaces.nsIInterfaceRequestor). getInterface(Components.interfaces.nsIDOMWindowUtils); var ratio = winUtil.screenPixelsPerCSSPixel; - return [aX * ratio, aY * ratio, aWidth * ratio, aHeight * ratio]; + + // CSS pixels and ratio can be not integer. Device pixels are always integer. + // Do our best and hope it works. + return [ Math.round(aX * ratio), Math.round(aY * ratio), + Math.round(aWidth * ratio), Math.round(aHeight * ratio) ]; } -
--- a/accessible/tests/mochitest/states.js +++ b/accessible/tests/mochitest/states.js @@ -12,16 +12,17 @@ // const STATE_BUSY is defined in common.js const STATE_CHECKED = nsIAccessibleStates.STATE_CHECKED; const STATE_CHECKABLE = nsIAccessibleStates.STATE_CHECKABLE; const STATE_COLLAPSED = nsIAccessibleStates.STATE_COLLAPSED; const STATE_DEFAULT = nsIAccessibleStates.STATE_DEFAULT; const STATE_EXPANDED = nsIAccessibleStates.STATE_EXPANDED; const STATE_EXTSELECTABLE = nsIAccessibleStates.STATE_EXTSELECTABLE; +const STATE_FLOATING = nsIAccessibleStates.STATE_FLOATING; const STATE_FOCUSABLE = nsIAccessibleStates.STATE_FOCUSABLE; const STATE_FOCUSED = nsIAccessibleStates.STATE_FOCUSED; const STATE_HASPOPUP = nsIAccessibleStates.STATE_HASPOPUP; const STATE_INVALID = nsIAccessibleStates.STATE_INVALID; const STATE_INVISIBLE = nsIAccessibleStates.STATE_INVISIBLE; const STATE_LINKED = nsIAccessibleStates.STATE_LINKED; const STATE_MIXED = nsIAccessibleStates.STATE_MIXED; const STATE_MULTISELECTABLE = nsIAccessibleStates.STATE_MULTISELECTABLE;
--- a/accessible/tests/mochitest/states/test_selects.html +++ b/accessible/tests/mochitest/states/test_selects.html @@ -3,33 +3,72 @@ <head> <title>HTML selects accessible states tests</title> <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + + <script type="application/javascript" src="../common.js"></script> <script type="application/javascript" src="../role.js"></script> <script type="application/javascript" src="../states.js"></script> + <script type="application/javascript" + src="../events.js"></script> <script type="application/javascript"> + function openComboboxNCheckStates(aID) + { + this.combobox = getAccessible(aID); + this.comboboxList = this.combobox.firstChild; + this.comboboxOption = this.comboboxList.firstChild; + + this.eventSeq = [ + new invokerChecker(EVENT_FOCUS, this.comboboxOption) + ]; + + this.invoke = function openComboboxNCheckStates_invoke() + { + getNode(aID).focus(); + synthesizeKey("VK_DOWN", { altKey: true }); + } + + this.finalCheck = function openComboboxNCheckStates_invoke() + { + // Expanded state on combobox. + testStates(this.combobox, STATE_EXPANDED); + + // Floating state on combobox list. + testStates(this.comboboxList, STATE_FLOATING); + } + + this.getID = function openComboboxNCheckStates_getID() + { + return "open combobox and test states"; + } + } + + //gA11yEventDumpToConsole = true; + + var gQueue = null; function doTest() { // combobox var combobox = getAccessible("combobox"); testStates(combobox, STATE_HASPOPUP | STATE_COLLAPSED | STATE_FOCUSABLE, 0, STATE_FOCUSED, 0); var comboboxList = combobox.firstChild; - testStates(comboboxList, 0, 0, STATE_FOCUSABLE, 0); + testStates(comboboxList, STATE_INVISIBLE, 0, STATE_FOCUSABLE, 0); var opt1 = comboboxList.firstChild; testStates(opt1, STATE_SELECTABLE | STATE_SELECTED | STATE_FOCUSABLE, EXT_STATE_ACTIVE, STATE_FOCUSED, 0); var opt2 = comboboxList.lastChild; testStates(opt2, STATE_SELECTABLE | STATE_FOCUSABLE, 0, STATE_SELECTED, 0, STATE_FOCUSED, EXT_STATE_ACTIVE); @@ -41,17 +80,20 @@ testStates(listbox.firstChild, STATE_SELECTABLE, EXT_STATE_ACTIVE, STATE_SELECTED | STATE_FOCUSED | STATE_FOCUSED); testStates(listbox.lastChild, STATE_SELECTABLE, 0, STATE_SELECTED | STATE_FOCUSED | STATE_FOCUSED, 0, 0, EXT_STATE_ACTIVE); - SimpleTest.finish(); + // open combobox + gQueue = new eventQueue(); + gQueue.push(new openComboboxNCheckStates("combobox")); + gQueue.invoke(); // Will call SimpleTest.finish(); } SimpleTest.waitForExplicitFinish(); addA11yLoadEvent(doTest); </script> </head>
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -498,8 +498,17 @@ pref("app.update.timerFirstInterval", 30 pref("app.update.timerMinimumDelay", 30); // seconds // Don't throttle background updates. pref("app.update.download.backgroundInterval", 0); // Enable update logging for now, to diagnose growing pains in the // field. pref("app.update.log", true); #endif + +// Extensions preferences +pref("extensions.update.enabled", false); +pref("extensions.getAddons.cache.enabled", false); + +// Context Menu +pref("ui.click_hold_context_menus", true); +pref("ui.click_hold_context_menus.delay", 1000); +
--- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -9,46 +9,41 @@ const Ci = Components.interfaces; const Cu = Components.utils; const Cr = Components.results; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/ContactService.jsm'); Cu.import('resource://gre/modules/Webapps.jsm'); -XPCOMUtils.defineLazyGetter(Services, 'env', function() { - return Cc['@mozilla.org/process/environment;1'] - .getService(Ci.nsIEnvironment); -}); +XPCOMUtils.defineLazyServiceGetter(Services, 'env', + '@mozilla.org/process/environment;1', + 'nsIEnvironment'); -XPCOMUtils.defineLazyGetter(Services, 'ss', function() { - return Cc['@mozilla.org/content/style-sheet-service;1'] - .getService(Ci.nsIStyleSheetService); -}); +XPCOMUtils.defineLazyServiceGetter(Services, 'ss', + '@mozilla.org/content/style-sheet-service;1', + 'nsIStyleSheetService'); -XPCOMUtils.defineLazyGetter(Services, 'idle', function() { - return Cc['@mozilla.org/widget/idleservice;1'] - .getService(Ci.nsIIdleService); -}); +XPCOMUtils.defineLazyServiceGetter(Services, 'idle', + '@mozilla.org/widget/idleservice;1', + 'nsIIdleService'); -XPCOMUtils.defineLazyGetter(Services, 'audioManager', function() { #ifdef MOZ_WIDGET_GONK - return Cc['@mozilla.org/telephony/audiomanager;1'] - .getService(Ci.nsIAudioManager); +XPCOMUtils.defineLazyServiceGetter(Services, 'audioManager', + '@mozilla.org/telephony/audiomanager;1', + 'nsIAudioManager'); #else - return { - "masterVolume": 0 - }; +Services.audioManager = { + 'masterVolume': 0 +}; #endif -}); -XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function() { - return Cc['@mozilla.org/focus-manager;1'] - .getService(Ci.nsFocusManager); -}); +XPCOMUtils.defineLazyServiceGetter(Services, 'fm', + '@mozilla.org/focus-manager;1', + 'nsIFocusManager'); XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() { Cu.import('resource://gre/modules/devtools/dbg-server.jsm'); return DebuggerServer; }); // FIXME Bug 707625 // until we have a proper security model, add some rights to @@ -139,19 +134,30 @@ var shell = { WebappsHelper.init(); let browser = this.contentBrowser; browser.homePage = homeURL; browser.goHome(); }, stop: function shell_stop() { + ['keydown', 'keypress', 'keyup'].forEach((function unlistenKey(type) { + window.removeEventListener(type, this, false, true); + window.removeEventListener(type, this, true, true); + }).bind(this)); + + window.addEventListener('MozApplicationManifest', this); window.removeEventListener('MozApplicationManifest', this); window.removeEventListener('mozfullscreenchange', this); window.removeEventListener('sizemodechange', this); + this.contentBrowser.removeEventListener('load', this, true); + +#ifndef MOZ_WIDGET_GONK + delete Services.audioManager; +#endif }, toggleDebug: function shell_toggleDebug() { this.isDebug = !this.isDebug; if (this.isDebug) { Services.prefs.setBoolPref("layers.acceleration.draw-fps", true); Services.prefs.setBoolPref("nglayout.debug.paint_flashing", true); @@ -296,128 +302,16 @@ var shell = { }, sendEvent: function shell_sendEvent(content, type, details) { let event = content.document.createEvent('CustomEvent'); event.initCustomEvent(type, true, true, details ? details : {}); content.dispatchEvent(event); } }; -(function PowerManager() { - // This will eventually be moved to content, so use content API as - // much as possible here. TODO: Bug 738530 - let power = navigator.mozPower; - let idleHandler = function idleHandler(subject, topic, time) { - if (topic === "idle") { - if (power.getWakeLockState("screen") != "locked-foreground") { - navigator.mozPower.screenEnabled = false; - } - } - } - - let wakeLockHandler = function wakeLockHandler(topic, state) { - // Turn off the screen when no one needs the it or all of them are - // invisible, otherwise turn the screen on. Note that the CPU - // might go to sleep as soon as the screen is turned off and - // acquiring wake lock will not bring it back (actually the code - // is not executed at all). - if (topic == "screen") { - if (state != "locked-foreground") { - if (Services.idle.idleTime > idleTimeout*1000) { - navigator.mozPower.screenEnabled = false; - } - } else { - navigator.mozPower.screenEnabled = true; - } - } - if (topic == "cpu") { - navigator.mozPower.cpuSleepAllowed = (state != "locked-foreground" && - state != "locked-background"); - } - } - - let idleTimeout = Services.prefs.getIntPref("power.screen.timeout"); - if (!('mozSettings' in navigator)) - return; - - let request = navigator.mozSettings.getLock().get("power.screen.timeout"); - request.onsuccess = function onSuccess() { - idleTimeout = request.result["power.screen.timeout"] || idleTimeout; - if (idleTimeout) { - Services.idle.addIdleObserver(idleHandler, idleTimeout); - power.addWakeLockListener(wakeLockHandler); - } - }; - - request.onerror = function onError() { - if (idleTimeout) { - Services.idle.addIdleObserver(idleHandler, idleTimeout); - power.addWakeLockListener(wakeLockHandler); - } - }; - - // XXX We may override other's callback here, but this is the only - // user of mozSettings in shell.js at this moment. - navigator.mozSettings.onsettingchange = function onSettingChange(e) { - if (e.settingName == "power.screen.timeout" && e.settingValue) { - Services.idle.removeIdleObserver(idleHandler, idleTimeout); - idleTimeout = e.settingValue; - Services.idle.addIdleObserver(idleHandler, idleTimeout); - } - }; -})(); - -const DATA_CALL_SETTING_BOLKEYS = ["ril.data.enabled", - "ril.data.roaming.enabled"]; -const DATA_CALL_SETTING_CHARKEYS = ["ril.data.apn", - "ril.data.user", - "ril.data.passwd"]; -(function DataCallSettings() { - let sm = navigator.mozSettings; - let lock = sm.getLock(); - DATA_CALL_SETTING_BOLKEYS.forEach(function(key) { - let request = lock.get(key); - request.onsuccess = function onSuccess() { - let value = request.result[key] || false; - Services.prefs.setBoolPref(key, value); - dump("DataCallSettings - " + key + ":" + value); - }; - request.onerror = function onError() { - Services.prefs.setBoolPref(key, false); - }; - }); - - DATA_CALL_SETTING_CHARKEYS.forEach(function(key) { - let request = lock.get(key); - request.onsuccess = function onSuccess() { - let value = request.result[key] || ""; - Services.prefs.setCharPref(key, value); - dump("DataCallSettings - " + key + ":" + value); - }; - request.onerror = function onError() { - Services.prefs.setCharPref(key, ""); - }; - }); - - navigator.mozSettings.onsettingchange = function onSettingChange(e) { - dump("DataCallSettings - onsettingchange: " + e.settingName + - ": " + e.settingValue); - if (e.settingValue) { - if (DATA_CALL_SETTING_BOLKEYS.indexOf(e.settingName) > -1 ) { - Services.prefs.setBoolPref(e.settingName, e.settingValue); - return; - } - if (DATA_CALL_SETTING_CHARKEYS.indexOf(e.settingName) > -1) { - Services.prefs.setCharPref(e.settingName, e.settingValue); - } - } - }; - -})(); - function nsBrowserAccess() { } nsBrowserAccess.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow]), openURI: function openURI(uri, opener, where, context) { // TODO This should be replaced by an 'open-browser-window' intent @@ -588,17 +482,21 @@ var WebappsHelper = { let json = JSON.parse(data); switch(topic) { case "webapps-launch": DOMApplicationRegistry.getManifestFor(json.origin, function(aManifest) { if (!aManifest) return; let manifest = new DOMApplicationManifest(aManifest, json.origin); - shell.sendEvent(content, "mozChromeEvent", { type: "webapps-launch", url: manifest.fullLaunchPath(), origin: json.origin }); + shell.sendEvent(content, "mozChromeEvent", { + "type": "webapps-launch", + "url": manifest.fullLaunchPath(json.startPoint), + "origin": json.origin + }); }); break; case "webapps-ask-install": let id = this.registerInstaller(json); shell.sendEvent(content, "mozChromeEvent", { type: "webapps-ask-install", id: id, app: json.app } ); break; } } @@ -618,9 +516,141 @@ function startDebugger() { dump('Unable to start debugger server: ' + e + '\n'); } } window.addEventListener('ContentStart', function(evt) { if (Services.prefs.getBoolPref('devtools.debugger.enabled')) { startDebugger(); } -}, false); +}); + + +// Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget +// is resolved this helper could be removed. +var SettingsListener = { + _callbacks: {}, + + init: function sl_init() { + if ('mozSettings' in navigator && navigator.mozSettings) + navigator.mozSettings.onsettingchange = this.onchange.bind(this); + }, + + onchange: function sl_onchange(evt) { + var callback = this._callbacks[evt.settingName]; + if (callback) { + callback(evt.settingValue); + } + }, + + observe: function sl_observe(name, defaultValue, callback) { + var settings = window.navigator.mozSettings; + if (!settings) { + window.setTimeout(function() { callback(defaultValue); }); + return; + } + + if (!callback || typeof callback !== 'function') { + throw new Error('Callback is not a function'); + } + + var req = settings.getLock().get(name); + req.addEventListener('success', (function onsuccess() { + callback(typeof(req.result[name]) != 'undefined' ? + req.result[name] : defaultValue); + })); + + this._callbacks[name] = callback; + } +}; + +SettingsListener.init(); + +SettingsListener.observe('language.current', 'en-US', function(value) { + Services.prefs.setCharPref('intl.accept_languages', value); +}); + + +(function PowerManager() { + // This will eventually be moved to content, so use content API as + // much as possible here. TODO: Bug 738530 + let power = navigator.mozPower; + let idleHandler = function idleHandler(subject, topic, time) { + if (topic !== 'idle') + return; + + if (power.getWakeLockState("screen") != "locked-foreground") { + navigator.mozPower.screenEnabled = false; + } + } + + let wakeLockHandler = function(topic, state) { + // Turn off the screen when no one needs the it or all of them are + // invisible, otherwise turn the screen on. Note that the CPU + // might go to sleep as soon as the screen is turned off and + // acquiring wake lock will not bring it back (actually the code + // is not executed at all). + if (topic === 'screen') { + if (state != "locked-foreground") { + if (Services.idle.idleTime > idleTimeout*1000) { + navigator.mozPower.screenEnabled = false; + } + } else { + navigator.mozPower.screenEnabled = true; + } + } else if (topic == 'cpu') { + navigator.mozPower.cpuSleepAllowed = (state != 'locked-foreground' && + state != 'locked-background'); + } + } + + let idleTimeout = Services.prefs.getIntPref('power.screen.timeout'); + if (!('mozSettings' in navigator)) + return; + + let request = navigator.mozSettings.getLock().get('power.screen.timeout'); + request.onsuccess = function onSuccess() { + idleTimeout = request.result['power.screen.timeout'] || idleTimeout; + if (!idleTimeout) + return; + + Services.idle.addIdleObserver(idleHandler, idleTimeout); + power.addWakeLockListener(wakeLockHandler); + }; + + request.onerror = function onError() { + if (!idleTimeout) + return; + + Services.idle.addIdleObserver(idleHandler, idleTimeout); + power.addWakeLockListener(wakeLockHandler); + }; + + SettingsListener.observe('power.screen.timeout', 30, function(value) { + if (!value) + return; + + Services.idle.removeIdleObserver(idleHandler, idleTimeout); + idleTimeout = value; + Services.idle.addIdleObserver(idleHandler, idleTimeout); + }); + + window.addEventListener('unload', function removeIdleObjects() { + Services.idle.removeIdleObserver(idleHandler, idleTimeout); + power.removeWakeLockListener(wakeLockHandler); + }); +})(); + + +(function RILSettingsToPrefs() { + ['ril.data.enabled', 'ril.data.roaming.enabled'].forEach(function(key) { + SettingsListener.observe(key, false, function(value) { + Services.prefs.setBoolPref(key, value); + }); + }); + + ['ril.data.apn', 'ril.data.user', 'ril.data.passwd'].forEach(function(key) { + SettingsListener.observe(key, false, function(value) { + Services.prefs.setBoolPref(key, value); + }); + }); +})(); +
--- a/b2g/chrome/content/shell.xul +++ b/b2g/chrome/content/shell.xul @@ -11,19 +11,16 @@ #ifdef ANDROID sizemode="fullscreen" #endif style="background: black; overflow: hidden;" onload="shell.start();" onunload="shell.stop();"> <script type="application/javascript" src="chrome://browser/content/shell.js"/> -#ifndef MOZ_TOUCH - <script type="application/javascript" src="chrome://browser/content/touch.js"/> -#endif <browser id="homescreen" type="content-primary" flex="1" style="overflow: hidden;" src="data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;'>"/> </window>
deleted file mode 100644 --- a/b2g/chrome/content/touch.js +++ /dev/null @@ -1,201 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -(function touchEventHandler() { - let debugging = false; - function debug(str) { - if (debugging) - dump(str + '\n'); - }; - - let contextMenuTimeout = 0; - - // This guard is used to not re-enter the events processing loop for - // self dispatched events - let ignoreEvents = false; - - // During a 'touchstart' and the first 'touchmove' mouse events can be - // prevented for the current touch sequence. - let canPreventMouseEvents = false; - - // Used to track the first mousemove and to cancel click dispatc if it's not - // true. - let isNewTouchAction = false; - - // If this is set to true all mouse events will be cancelled by calling - // both evt.preventDefault() and evt.stopPropagation(). - // This will not prevent a contextmenu event to be fired. - // This can be turned on if canPreventMouseEvents is true and the consumer - // application call evt.preventDefault(); - let preventMouseEvents = false; - - let TouchEventHandler = { - events: ['mousedown', 'mousemove', 'mouseup', 'click', 'unload'], - start: function teh_start() { - this.events.forEach((function(evt) { - shell.contentBrowser.addEventListener(evt, this, true); - }).bind(this)); - }, - stop: function teh_stop() { - this.events.forEach((function(evt) { - shell.contentBrowser.removeEventListener(evt, this, true); - }).bind(this)); - }, - handleEvent: function teh_handleEvent(evt) { - if (evt.button || ignoreEvents) - return; - - let eventTarget = this.target; - let type = ''; - switch (evt.type) { - case 'mousedown': - debug('mousedown:'); - - this.target = evt.target; - this.timestamp = evt.timeStamp; - - preventMouseEvents = false; - canPreventMouseEvents = true; - isNewTouchAction = true; - - contextMenuTimeout = - this.sendContextMenu(evt.target, evt.pageX, evt.pageY, 2000); - this.startX = evt.pageX; - this.startY = evt.pageY; - type = 'touchstart'; - break; - - case 'mousemove': - if (!eventTarget) - return; - - // On device a mousemove event if fired right after the mousedown - // because of the size of the finger, so let's ignore what happens - // below 5ms - if (evt.timeStamp - this.timestamp < 30) - break; - - if (isNewTouchAction) { - canPreventMouseEvents = true; - isNewTouchAction = false; - } - - if (Math.abs(this.startX - evt.pageX) > 15 || - Math.abs(this.startY - evt.pageY) > 15) - window.clearTimeout(contextMenuTimeout); - type = 'touchmove'; - break; - - case 'mouseup': - if (!eventTarget) - return; - debug('mouseup:'); - - window.clearTimeout(contextMenuTimeout); - this.target = null; - type = 'touchend'; - break; - - case 'unload': - if (!eventTarget) - return; - - window.clearTimeout(contextMenuTimeout); - this.target = null; - TouchEventHandler.stop(); - return; - - case 'click': - if (isNewTouchAction) { - // Mouse events has been cancelled so dispatch a sequence - // of events to where touchend has been fired - if (preventMouseEvents) { - evt.preventDefault(); - evt.stopPropagation(); - - let target = evt.target; - ignoreEvents = true; - window.setTimeout(function dispatchMouseEvents(self) { - self.fireMouseEvent('mousemove', evt); - self.fireMouseEvent('mousedown', evt); - self.fireMouseEvent('mouseup', evt); - ignoreEvents = false; - }, 0, this); - } - - debug('click: fire'); - } - return; - } - - let target = eventTarget || this.target; - if (target && type) { - let touchEvent = this.sendTouchEvent(evt, target, type); - if (touchEvent.defaultPrevented && canPreventMouseEvents) - preventMouseEvents = true; - } - - if (preventMouseEvents) { - evt.preventDefault(); - evt.stopPropagation(); - - if (type != 'touchmove') - debug('cancelled (fire ' + type + ')'); - } - }, - fireMouseEvent: function teh_fireMouseEvent(type, evt) { - debug(type + ': fire'); - - let content = evt.target.ownerDocument.defaultView; - var utils = content.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - utils.sendMouseEvent(type, evt.pageX, evt.pageY, 0, 1, 0, true); - }, - sendContextMenu: function teh_sendContextMenu(target, x, y, delay) { - let doc = target.ownerDocument; - let evt = doc.createEvent('MouseEvent'); - evt.initMouseEvent('contextmenu', true, true, doc.defaultView, - 0, x, y, x, y, false, false, false, false, - 0, null); - - let timeout = window.setTimeout((function contextMenu() { - debug('fire context-menu'); - - target.dispatchEvent(evt); - if (!evt.defaultPrevented) - return; - - doc.releaseCapture(); - this.target = null; - - isNewTouchAction = false; - }).bind(this), delay); - return timeout; - }, - sendTouchEvent: function teh_sendTouchEvent(evt, target, name) { - let touchEvent = document.createEvent('touchevent'); - let point = document.createTouch(window, target, 0, - evt.pageX, evt.pageY, - evt.screenX, evt.screenY, - evt.clientX, evt.clientY, - 1, 1, 0, 0); - let touches = document.createTouchList(point); - let targetTouches = touches; - let changedTouches = touches; - touchEvent.initTouchEvent(name, true, true, window, 0, - false, false, false, false, - touches, targetTouches, changedTouches); - target.dispatchEvent(touchEvent); - return touchEvent; - } - }; - - window.addEventListener('ContentStart', function touchStart(evt) { - window.removeEventListener('ContentStart', touchStart); - TouchEventHandler.start(); - }); -})(); -
--- a/b2g/chrome/content/webapi.js +++ b/b2g/chrome/content/webapi.js @@ -8,20 +8,19 @@ dump('======================= webapi+apps.js ======================= \n'); let { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/Geometry.jsm'); -XPCOMUtils.defineLazyGetter(Services, 'fm', function() { - return Cc['@mozilla.org/focus-manager;1'] - .getService(Ci.nsIFocusManager); -}); +XPCOMUtils.defineLazyServiceGetter(Services, 'fm', + '@mozilla.org/focus-manager;1', + 'nsIFocusManager'); // MozKeyboard (function VirtualKeyboardManager() { let activeElement = null; let isKeyboardOpened = false; function fireEvent(type, details) { let event = content.document.createEvent('CustomEvent');
--- a/b2g/chrome/jar.mn +++ b/b2g/chrome/jar.mn @@ -2,19 +2,16 @@ chrome.jar: % content branding %content/branding/ % content browser %content/ content/dbg-browser-actors.js (content/dbg-browser-actors.js) * content/shell.xul (content/shell.xul) * content/shell.js (content/shell.js) -#ifndef MOZ_TOUCH - content/touch.js (content/touch.js) -#endif content/webapi.js (content/webapi.js) content/content.css (content/content.css) % override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml % override chrome://global/skin/netError.css chrome://browser/content/netError.css content/netError.xhtml (content/netError.xhtml) content/netError.css (content/netError.css) content/images/errorpage-larry-black.png (content/images/errorpage-larry-black.png)
--- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/setup.js +++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/setup.js @@ -339,17 +339,17 @@ let TestPilotSetup = { // Register listener for URL loads, that will notify all tasks about // new page: let appcontent = window.document.getElementById("appcontent"); if (appcontent) { appcontent.addEventListener("DOMContentLoaded", function(event) { let newUrl = event.originalTarget.URL; self._feedbackManager.fillInFeedbackPage(newUrl, window); - for (i = 0; i < self.taskList.length; i++) { + for (let i = 0; i < self.taskList.length; i++) { self.taskList[i].onUrlLoad(newUrl, event); } }, true); } // Let each task know about the new window. for (let i = 0; i < this.taskList.length; i++) { this.taskList[i].onNewWindow(window);
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -868,22 +868,16 @@ pref("places.frecency.unvisitedBookmarkB pref("places.frecency.unvisitedTypedBonus", 200); // Controls behavior of the "Add Exception" dialog launched from SSL error pages // 0 - don't pre-populate anything // 1 - pre-populate site URL, but don't fetch certificate // 2 - pre-populate site URL and pre-fetch certificate pref("browser.ssl_override_behavior", 2); -// Controls the display of domain in the identity box for SSL connections. -// 0 - do not show domain -// 1 - show effectiveTLD + 1 (e.g. mozilla.org) -// 2 - show full domain (e.g. bugzilla.mozilla.org) -pref("browser.identity.ssl_domain_display", 0); - // True if the user should be prompted when a web application supports // offline apps. pref("browser.offline-apps.notify", true); // if true, use full page zoom instead of text zoom pref("browser.zoom.full", true); // Whether or not to save and restore zoom levels on a per-site basis. @@ -1056,16 +1050,19 @@ pref("devtools.inspector.activeSidebar", pref("devtools.layoutview.enabled", false); pref("devtools.layoutview.open", false); // Enable the Debugger pref("devtools.debugger.enabled", false); pref("devtools.debugger.remote-enabled", false); pref("devtools.debugger.remote-host", "localhost"); pref("devtools.debugger.remote-port", 6000); +pref("devtools.debugger.remote-autoconnect", false); +pref("devtools.debugger.remote-connection-retries", 3); +pref("devtools.debugger.remote-timeout", 3000); // The default Debugger UI height pref("devtools.debugger.ui.height", 250); pref("devtools.debugger.ui.remote-win.width", 900); pref("devtools.debugger.ui.remote-win.height", 400); // Enable the style inspector pref("devtools.styleinspector.enabled", true);
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1020,37 +1020,41 @@ let gGestureSupport = { // Create a preference object with some defaults let def = function(aThreshold, aLatched) ({ threshold: aThreshold, latched: !!aLatched }); switch (aEvent.type) { case "MozSwipeGesture": aEvent.preventDefault(); - return this.onSwipe(aEvent); + this.onSwipe(aEvent); + break; case "MozMagnifyGestureStart": aEvent.preventDefault(); #ifdef XP_WIN - return this._setupGesture(aEvent, "pinch", def(25, 0), "out", "in"); + this._setupGesture(aEvent, "pinch", def(25, 0), "out", "in"); #else - return this._setupGesture(aEvent, "pinch", def(150, 1), "out", "in"); + this._setupGesture(aEvent, "pinch", def(150, 1), "out", "in"); #endif + break; case "MozRotateGestureStart": aEvent.preventDefault(); - return this._setupGesture(aEvent, "twist", def(25, 0), "right", "left"); + this._setupGesture(aEvent, "twist", def(25, 0), "right", "left"); + break; case "MozMagnifyGestureUpdate": case "MozRotateGestureUpdate": aEvent.preventDefault(); - return this._doUpdate(aEvent); + this._doUpdate(aEvent); + break; case "MozTapGesture": aEvent.preventDefault(); - return this._doAction(aEvent, ["tap"]); - case "MozPressTapGesture": - // Fall through to default behavior - return; + this._doAction(aEvent, ["tap"]); + break; + /* case "MozPressTapGesture": + break; */ } }, /** * Called at the start of "pinch" and "twist" gestures to setup all of the * information needed to process the gesture * * @param aEvent @@ -1125,18 +1129,16 @@ let gGestureSupport = { /** * Determine what action to do for the gesture based on which keys are * pressed and which commands are set * * @param aEvent * The original gesture event to convert into a fake click event * @param aGesture * Array of gesture name parts (to be joined by periods) - * @return Name of the command found for the event's keys and gesture. If no - * command is found, no value is returned (undefined). */ _doAction: function GS__doAction(aEvent, aGesture) { // Create an array of pressed keys in a fixed order so that a command for // "meta" is preferred over "ctrl" when both buttons are pressed (and a // command for both don't exist) let keyCombos = []; ["shift", "alt", "ctrl", "meta"].forEach(function (key) { if (aEvent[key + "Key"]) @@ -1164,19 +1166,18 @@ let gGestureSupport = { aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey, aEvent.metaKey, null); node.dispatchEvent(cmdEvent); } } else { goDoCommand(command); } - return command; - } - return null; + break; + } }, /** * Convert continual motion events into an action if it exceeds a threshold * in a given direction. This function will be set by _setupGesture to * capture state that needs to be shared across multiple gesture updates. * * @param aEvent @@ -1187,20 +1188,22 @@ let gGestureSupport = { /** * Convert the swipe gesture into a browser action based on the direction * * @param aEvent * The swipe event to handle */ onSwipe: function GS_onSwipe(aEvent) { // Figure out which one (and only one) direction was triggered - ["UP", "RIGHT", "DOWN", "LEFT"].forEach(function (dir) { - if (aEvent.direction == aEvent["DIRECTION_" + dir]) - return this._doAction(aEvent, ["swipe", dir.toLowerCase()]); - }, this); + for (let dir of ["UP", "RIGHT", "DOWN", "LEFT"]) { + if (aEvent.direction == aEvent["DIRECTION_" + dir]) { + this._doAction(aEvent, ["swipe", dir.toLowerCase()]); + break; + } + } }, /** * Get a gesture preference or use a default if it doesn't exist * * @param aPref * Name of the preference to load under the gesture branch * @param aDef @@ -5196,20 +5199,23 @@ var TabsProgressListener = { BrowserOnAboutPageLoad(aWebProgress.DOMWindow.document); } }, onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI, aFlags) { // Filter out any sub-frame loads if (aBrowser.contentWindow == aWebProgress.DOMWindow) { - // initialize the click-to-play state - aBrowser._clickToPlayDoorhangerShown = false; - aBrowser._clickToPlayPluginsActivated = false; - + // Filter out any onLocationChanges triggered by anchor navigation + // or history.push/pop/replaceState. + if (aRequest) { + // Initialize the click-to-play state. + aBrowser._clickToPlayDoorhangerShown = false; + aBrowser._clickToPlayPluginsActivated = false; + } FullZoom.onLocationChange(aLocationURI, false, aBrowser); } }, onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) { if (gPrefService.getBoolPref("accessibility.blockautorefresh")) { let brandBundle = document.getElementById("bundle_brand"); let brandShortName = brandBundle.getString("brandShortName"); @@ -8194,83 +8200,66 @@ var gIdentityHandler = { /** * Set up the messages for the primary identity UI based on the specified mode, * and the details of the SSL cert, where applicable * * @param newMode The newly set identity mode. Should be one of the IDENTITY_MODE_* constants. */ setIdentityMessages : function(newMode) { - if (newMode == this.IDENTITY_MODE_DOMAIN_VERIFIED) { - var iData = this.getIdentityData(); - - // It would be sort of nice to use the CN= field in the cert, since that's - // typically what we want here, but thanks to x509 certs being extensible, - // it's not the only place you have to check, there can be more than one domain, - // et cetera, ad nauseum. We know the cert is valid for location.host, so - // let's just use that. Check the pref to determine how much of the verified - // hostname to show - var icon_label = ""; - var icon_country_label = ""; - var icon_labels_dir = "ltr"; - switch (gPrefService.getIntPref("browser.identity.ssl_domain_display")) { - case 2 : // Show full domain - icon_label = this._lastLocation.hostname; - break; - case 1 : // Show eTLD. - icon_label = this.getEffectiveHost(); - } + let icon_label = ""; + let tooltip = ""; + let icon_country_label = ""; + let icon_labels_dir = "ltr"; + + switch (newMode) { + case this.IDENTITY_MODE_DOMAIN_VERIFIED: { + let iData = this.getIdentityData(); // Verifier is either the CA Org, for a normal cert, or a special string // for certs that are trusted because of a security exception. - var tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier", - [iData.caOrg]); + tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier", + [iData.caOrg]); // Check whether this site is a security exception. XPConnect does the right // thing here in terms of converting _lastLocation.port from string to int, but // the overrideService doesn't like undefined ports, so make sure we have // something in the default case (bug 432241). // .hostname can return an empty string in some exceptional cases - // hasMatchingOverride does not handle that, so avoid calling it. // Updating the tooltip value in those cases isn't critical. // FIXME: Fixing bug 646690 would probably makes this check unnecessary if (this._lastLocation.hostname && this._overrideService.hasMatchingOverride(this._lastLocation.hostname, (this._lastLocation.port || 443), iData.cert, {}, {})) tooltip = gNavigatorBundle.getString("identity.identified.verified_by_you"); - } - else if (newMode == this.IDENTITY_MODE_IDENTIFIED) { + break; } + case this.IDENTITY_MODE_IDENTIFIED: { // If it's identified, then we can populate the dialog with credentials - iData = this.getIdentityData(); + let iData = this.getIdentityData(); tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier", [iData.caOrg]); icon_label = iData.subjectOrg; if (iData.country) icon_country_label = "(" + iData.country + ")"; + // If the organization name starts with an RTL character, then // swap the positions of the organization and country code labels. // The Unicode ranges reflect the definition of the UCS2_CHAR_IS_BIDI // macro in intl/unicharutil/util/nsBidiUtils.h. When bug 218823 gets // fixed, this test should be replaced by one adhering to the // Unicode Bidirectional Algorithm proper (at the paragraph level). icon_labels_dir = /^[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufefc]/.test(icon_label) ? "rtl" : "ltr"; - } - else if (newMode == this.IDENTITY_MODE_CHROMEUI) { - icon_label = ""; - tooltip = ""; - icon_country_label = ""; - icon_labels_dir = "ltr"; - } - else { + break; } + case this.IDENTITY_MODE_CHROMEUI: + break; + default: tooltip = gNavigatorBundle.getString("identity.unknown.tooltip"); - icon_label = ""; - icon_country_label = ""; - icon_labels_dir = "ltr"; } // Push the appropriate strings out to the UI this._identityBox.tooltipText = tooltip; this._identityIconLabel.value = icon_label; this._identityIconCountryLabel.value = icon_country_label; // Set cropping and direction this._identityIconLabel.crop = icon_country_label ? "end" : "center"; @@ -8290,48 +8279,45 @@ var gIdentityHandler = { this._identityPopup.className = newMode; this._identityPopupContentBox.className = newMode; // Set the static strings up front this._identityPopupEncLabel.textContent = this._encryptionLabel[newMode]; // Initialize the optional strings to empty values - var supplemental = ""; - var verifier = ""; - - if (newMode == this.IDENTITY_MODE_DOMAIN_VERIFIED) { - var iData = this.getIdentityData(); - var host = this.getEffectiveHost(); - var owner = gNavigatorBundle.getString("identity.ownerUnknown2"); + let supplemental = ""; + let verifier = ""; + let host = ""; + let owner = ""; + + switch (newMode) { + case this.IDENTITY_MODE_DOMAIN_VERIFIED: + host = this.getEffectiveHost(); + owner = gNavigatorBundle.getString("identity.ownerUnknown2"); verifier = this._identityBox.tooltipText; - supplemental = ""; - } - else if (newMode == this.IDENTITY_MODE_IDENTIFIED) { + break; + case this.IDENTITY_MODE_IDENTIFIED: { // If it's identified, then we can populate the dialog with credentials - iData = this.getIdentityData(); + let iData = this.getIdentityData(); host = this.getEffectiveHost(); owner = iData.subjectOrg; verifier = this._identityBox.tooltipText; // Build an appropriate supplemental block out of whatever location data we have if (iData.city) supplemental += iData.city + "\n"; if (iData.state && iData.country) supplemental += gNavigatorBundle.getFormattedString("identity.identified.state_and_country", [iData.state, iData.country]); else if (iData.state) // State only supplemental += iData.state; else if (iData.country) // Country only supplemental += iData.country; - } - else { - // These strings will be hidden in CSS anyhow - host = ""; - owner = ""; + break; } } // Push the appropriate strings out to the UI this._identityPopupContentHost.textContent = host; this._identityPopupContentOwner.textContent = owner; this._identityPopupContentSupp.textContent = supplemental; this._identityPopupContentVerif.textContent = verifier; },
--- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -770,17 +770,18 @@ nsContextMenu.prototype = { // Open clicked-in frame in the same window. showOnlyThisFrame: function() { var doc = this.target.ownerDocument; var frameURL = doc.location.href; urlSecurityCheck(frameURL, this.browser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); var referrer = doc.referrer; - this.browser.loadURI(frameURL, referrer ? makeURI(referrer) : null); + openUILinkIn(frameURL, "current", { disallowInheritPrincipal: true, + referrerURI: referrer ? makeURI(referrer) : null }); }, // View Partial Source viewPartialSource: function(aContext) { var focusedWindow = document.commandDispatcher.focusedWindow; if (focusedWindow == window) focusedWindow = content; @@ -842,17 +843,18 @@ nsContextMenu.prototype = { else { viewURL = this.mediaURL; urlSecurityCheck(viewURL, this.browser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); } var doc = this.target.ownerDocument; - openUILink(viewURL, e, null, null, null, null, doc.documentURIObject ); + openUILink(viewURL, e, { disallowInheritPrincipal: true, + referrerURI: doc.documentURIObject }); }, saveVideoFrameAsImage: function () { urlSecurityCheck(this.mediaURL, this.browser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); let name = ""; try { let uri = makeURI(this.mediaURL); @@ -878,17 +880,18 @@ nsContextMenu.prototype = { }, // Change current window to the URL of the background image. viewBGImage: function(e) { urlSecurityCheck(this.bgImageURL, this.browser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); var doc = this.target.ownerDocument; - openUILink(this.bgImageURL, e, null, null, null, null, doc.documentURIObject ); + openUILink(this.bgImageURL, e, { disallowInheritPrincipal: true, + referrerURI: doc.documentURIObject }); }, disableSetDesktopBackground: function() { // Disable the Set as Desktop Background menu item if we're still trying // to load the image or the load failed. if (!(this.target instanceof Ci.nsIImageLoadingContent)) return true;
--- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -176,16 +176,18 @@ endif browser_bug623155.js \ browser_bug623893.js \ browser_bug624734.js \ browser_bug647886.js \ browser_bug655584.js \ browser_bug664672.js \ browser_bug710878.js \ browser_bug719271.js \ + browser_bug743421.js \ + browser_bug749738.js \ browser_canonizeURL.js \ browser_findbarClose.js \ browser_homeDrop.js \ browser_keywordBookmarklets.js \ browser_contextSearchTabPosition.js \ browser_ctrlTab.js \ browser_customize_popupNotification.js \ browser_disablechrome.js \ @@ -248,16 +250,17 @@ endif feed_tab.html \ plugin_unknown.html \ plugin_test.html \ plugin_test2.html \ plugin_test3.html \ plugin_alternate_content.html \ plugin_both.html \ plugin_both2.html \ + plugin_bug743421.html \ plugin_clickToPlayAllow.html \ plugin_clickToPlayDeny.html \ alltabslistener.html \ zoom_test.html \ dummy_page.html \ browser_tabMatchesInAwesomebar.js \ file_bug550565_popup.html \ file_bug550565_favicon.ico \ @@ -273,16 +276,17 @@ endif test_wyciwyg_copying.html \ authenticate.sjs \ browser_minimize.js \ browser_aboutSyncProgress.js \ browser_middleMouse_inherit.js \ redirect_bug623155.sjs \ browser_tabDrop.js \ browser_lastAccessedTab.js \ + browser_bug734076.js \ $(NULL) ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT)) _BROWSER_FILES += \ browser_bug462289.js \ $(NULL) else _BROWSER_FILES += \
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/browser_bug734076.js @@ -0,0 +1,107 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + waitForExplicitFinish(); + + let tab = gBrowser.selectedTab = gBrowser.addTab(); + registerCleanupFunction(function () { + gBrowser.removeTab(tab); + }); + + let browser = tab.linkedBrowser; + browser.stop(); // stop the about:blank load + + let writeDomainURL = encodeURI("data:text/html,<script>document.write(document.domain);</script>"); + let tests = [ + { + name: "view background image", + url: "http://mochi.test:8888/", + go: function (cb) { + let contentBody = browser.contentDocument.body; + contentBody.style.backgroundImage = "url('" + writeDomainURL + "')"; + doOnLoad(function () { + let domain = browser.contentDocument.body.textContent; + is(domain, "", "no domain was inherited for view background image"); + cb(); + }); + + let contextMenu = initContextMenu(contentBody); + contextMenu.viewBGImage(); + } + }, + { + name: "view image", + url: "http://mochi.test:8888/", + go: function (cb) { + doOnLoad(function () { + let domain = browser.contentDocument.body.textContent; + is(domain, "", "no domain was inherited for view image"); + cb(); + }); + + let doc = browser.contentDocument; + let img = doc.createElement("img"); + img.setAttribute("src", writeDomainURL); + doc.body.appendChild(img); + + let contextMenu = initContextMenu(img); + contextMenu.viewMedia(); + } + }, + { + name: "show only this frame", + url: "http://mochi.test:8888/", + go: function (cb) { + doOnLoad(function () { + let domain = browser.contentDocument.body.textContent; + is(domain, "", "no domain was inherited for 'show only this frame'"); + cb(); + }); + + let doc = browser.contentDocument; + let iframe = doc.createElement("iframe"); + iframe.setAttribute("src", writeDomainURL); + doc.body.appendChild(iframe); + + iframe.addEventListener("load", function onload() { + let contextMenu = initContextMenu(iframe.contentDocument.body); + contextMenu.showOnlyThisFrame(); + }, false); + } + } + ]; + + function doOnLoad(cb) { + browser.addEventListener("load", function onLoad(e) { + if (e.target != browser.contentDocument) + return; + browser.removeEventListener("load", onLoad, true); + cb(); + }, true); + } + + function doNext() { + let test = tests.shift(); + if (test) { + info("Running test: " + test.name); + doOnLoad(function () { + test.go(function () { + executeSoon(doNext); + }); + }); + browser.contentDocument.location = test.url; + } else { + executeSoon(finish); + } + } + + doNext(); +} + +function initContextMenu(aNode) { + document.popupNode = aNode; + let contentAreaContextMenu = document.getElementById("contentAreaContextMenu"); + let contextMenu = new nsContextMenu(contentAreaContextMenu, gBrowser); + return contextMenu; +}
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/browser_bug743421.js @@ -0,0 +1,107 @@ +var rootDir = getRootDirectory(gTestPath); +const gTestRoot = rootDir; + +var gTestBrowser = null; +var gNextTest = null; + +Components.utils.import("resource://gre/modules/Services.jsm"); + +function test() { + waitForExplicitFinish(); + registerCleanupFunction(function() { Services.prefs.clearUserPref("plugins.click_to_play"); }); + Services.prefs.setBoolPref("plugins.click_to_play", true); + + var newTab = gBrowser.addTab(); + gBrowser.selectedTab = newTab; + gTestBrowser = gBrowser.selectedBrowser; + gTestBrowser.addEventListener("load", pageLoad, true); + prepareTest(test1a, gTestRoot + "plugin_bug743421.html"); +} + +function finishTest() { + gTestBrowser.removeEventListener("load", pageLoad, true); + gBrowser.removeCurrentTab(); + window.focus(); + finish(); +} + +function pageLoad() { + // The plugin events are async dispatched and can come after the load event + // This just allows the events to fire before we then go on to test the states + executeSoon(gNextTest); +} + +function prepareTest(nextTest, url) { + gNextTest = nextTest; + gTestBrowser.contentWindow.location = url; +} + +// Tests that navigation within the page and the window.history API doesn't break click-to-play state. +function test1a() { + var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); + ok(!popupNotification, "Test 1a, Should not have a click-to-play notification"); + var plugin = gTestBrowser.contentWindow.addPlugin(); + + setTimeout(test1b, 500); +} + +function test1b() { + var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); + ok(popupNotification, "Test 1b, Should have a click-to-play notification"); + var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[0]; + var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + ok(!objLoadingContent.activated, "Test 1b, Plugin should not be activated"); + + EventUtils.synthesizeMouse(plugin, 100, 100, { }); + setTimeout(test1c, 500); +} + +function test1c() { + var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); + ok(!popupNotification, "Test 1c, Should not have a click-to-play notification"); + var plugin = gTestBrowser.contentWindow.addPlugin(); + + setTimeout(test1d, 500); +} + +function test1d() { + var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); + ok(!popupNotification, "Test 1d, Should not have a click-to-play notification"); + var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[1]; + var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + ok(objLoadingContent.activated, "Test 1d, Plugin should be activated"); + + gNextTest = test1e; + gTestBrowser.contentWindow.addEventListener("hashchange", test1e, false); + gTestBrowser.contentWindow.location += "#anchorNavigation"; +} + +function test1e() { + gTestBrowser.contentWindow.removeEventListener("hashchange", test1e, false); + var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); + ok(!popupNotification, "Test 1e, Should not have a click-to-play notification"); + var plugin = gTestBrowser.contentWindow.addPlugin(); + + setTimeout(test1f, 500); +} + +function test1f() { + var popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); + ok(!popupNotification, "Test 1f, Should not have a click-to-play notification"); + var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[2]; + var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + ok(objLoadingContent.activated, "Test 1f, Plugin should be activated"); + + gTestBrowser.contentWindow.history.replaceState({}, "", "replacedState"); + gTestBrowser.contentWindow.addPlugin(); + setTimeout(test1g, 500); +} + +function test1g() { + var popupNotification2 = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser); + ok(!popupNotification2, "Test 1g, Should not have a click-to-play notification after replaceState"); + var plugin = gTestBrowser.contentDocument.getElementsByTagName("embed")[3]; + var objLoadingContent2 = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + ok(objLoadingContent2.activated, "Test 1g, Plugin should be activated"); + finishTest(); +}
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/browser_bug749738.js @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const DUMMY_PAGE = "http://example.org/browser/browser/base/content/test/dummy_page.html"; + +function test() { + waitForExplicitFinish(); + + let tab = gBrowser.addTab(); + gBrowser.selectedTab = tab; + + load(tab, DUMMY_PAGE, function() { + gFindBar.onFindCommand(); + EventUtils.sendString("Dummy"); + gBrowser.removeTab(tab); + + try { + gFindBar.close(); + ok(true, "findbar.close should not throw an exception"); + } catch(e) { + ok(false, "findbar.close threw exception: " + e); + } + finish(); + }); +} + +function load(aTab, aUrl, aCallback) { + aTab.linkedBrowser.addEventListener("load", function onload(aEvent) { + aEvent.currentTarget.removeEventListener("load", onload, true); + waitForFocus(aCallback, content); + }, true); + aTab.linkedBrowser.loadURI(aUrl); +}
--- a/browser/base/content/test/browser_identity_UI.js +++ b/browser/base/content/test/browser_identity_UI.js @@ -1,14 +1,11 @@ /* Tests for correct behaviour of getEffectiveHost on identity handler */ function test() { waitForExplicitFinish(); - registerCleanupFunction(function() { - Services.prefs.clearUserPref("browser.identity.ssl_domain_display"); - }); ok(gIdentityHandler, "gIdentityHandler should exist"); gBrowser.selectedTab = gBrowser.addTab(); gBrowser.selectedBrowser.addEventListener("load", checkResult, true); nextTest(); } @@ -97,34 +94,26 @@ function nextTest() { } gCurrentTest = tests[gCurrentTestIndex]; gTestDesc = "#" + gCurrentTestIndex + " (" + gCurrentTest.name + ")"; if (!gForward) gTestDesc += " (second time)"; if (gCurrentTest.isHTTPS) { gCheckETLD = true; - Services.prefs.setIntPref("browser.identity.ssl_domain_display", 1); } content.location = gCurrentTest.location; } else { gCheckETLD = false; gTestDesc = "#" + gCurrentTestIndex + " (" + gCurrentTest.name + " without eTLD in identity icon label)"; if (!gForward) gTestDesc += " (second time)"; - Services.prefs.clearUserPref("browser.identity.ssl_domain_display"); content.location.reload(true); } } function checkResult() { - if (gCurrentTest.isHTTPS && Services.prefs.getIntPref("browser.identity.ssl_domain_display") == 1) { - // Check that the effective host is displayed in the UI - let label = document.getElementById("identity-icon-label"); - is(label.value, gCurrentTest.effectiveHost, "effective host is displayed in identity icon label for test " + gTestDesc); - } - // Sanity check other values, and the value of gIdentityHandler.getEffectiveHost() is(gIdentityHandler._lastLocation.host, gCurrentTest.host, "host matches for test " + gTestDesc); is(gIdentityHandler.getEffectiveHost(), gCurrentTest.effectiveHost, "effectiveHost matches for test " + gTestDesc); executeSoon(nextTest); }
--- a/browser/base/content/test/browser_popupNotification.js +++ b/browser/base/content/test/browser_popupNotification.js @@ -186,47 +186,47 @@ function basicNotification() { } var wrongBrowserNotificationObject = new basicNotification(); var wrongBrowserNotification; var tests = [ { // Test #0 run: function () { - this.notifyObj = new basicNotification(), + this.notifyObj = new basicNotification(); showNotification(this.notifyObj); }, onShown: function (popup) { checkPopup(popup, this.notifyObj); triggerMainCommand(popup); }, onHidden: function (popup) { ok(this.notifyObj.mainActionClicked, "mainAction was clicked"); ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered"); ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); } }, { // Test #1 run: function () { - this.notifyObj = new basicNotification(), + this.notifyObj = new basicNotification(); showNotification(this.notifyObj); }, onShown: function (popup) { checkPopup(popup, this.notifyObj); triggerSecondaryCommand(popup, 0); }, onHidden: function (popup) { ok(this.notifyObj.secondaryActionClicked, "secondaryAction was clicked"); ok(!this.notifyObj.dismissalCallbackTriggered, "dismissal callback wasn't triggered"); ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); } }, { // Test #2 run: function () { - this.notifyObj = new basicNotification(), + this.notifyObj = new basicNotification(); this.notification = showNotification(this.notifyObj); }, onShown: function (popup) { checkPopup(popup, this.notifyObj); dismissNotification(popup); }, onHidden: function (popup) { ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered"); @@ -280,17 +280,17 @@ var tests = [ is(PopupNotifications.isPanelOpen, false, "panel isn't open"); gBrowser.removeTab(gNewTab); } }, // Test that two notifications with the same ID result in a single displayed // notification. { // Test #6 run: function () { - this.notifyObj = new basicNotification(), + this.notifyObj = new basicNotification(); // Show the same notification twice this.notification1 = showNotification(this.notifyObj); this.notification2 = showNotification(this.notifyObj); }, onShown: function (popup) { checkPopup(popup, this.notifyObj); this.notification2.remove(); }, @@ -327,17 +327,17 @@ var tests = [ ok(!this.testNotif2.mainActionClicked, "main action #2 wasn't clicked"); ok(this.testNotif2.secondaryActionClicked, "secondary action #2 was clicked"); ok(!this.testNotif2.dismissalCallbackTriggered, "dismissal callback #2 wasn't called"); } }, // Test notification without mainAction { // Test #8 run: function () { - this.notifyObj = new basicNotification(), + this.notifyObj = new basicNotification(); this.notifyObj.mainAction = null; this.notification = showNotification(this.notifyObj); }, onShown: function (popup) { checkPopup(popup, this.notifyObj); dismissNotification(popup); }, onHidden: function (popup) { @@ -563,33 +563,33 @@ var tests = [ updateNotShowing: function() { isnot(document.getElementById("geo-notification-icon").boxObject.width, 0, "geo anchor should be visible"); } }, // Test notification "Not Now" menu item { // Test #17 run: function () { - this.notifyObj = new basicNotification(), + this.notifyObj = new basicNotification(); this.notification = showNotification(this.notifyObj); }, onShown: function (popup) { checkPopup(popup, this.notifyObj); triggerSecondaryCommand(popup, 1); }, onHidden: function (popup) { ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback triggered"); this.notification.remove(); ok(this.notifyObj.removedCallbackTriggered, "removed callback triggered"); } }, // Test notification close button { // Test #18 run: function () { - this.notifyObj = new basicNotification(), + this.notifyObj = new basicNotification(); this.notification = showNotification(this.notifyObj); }, onShown: function (popup) { checkPopup(popup, this.notifyObj); let notification = popup.childNodes[0]; EventUtils.synthesizeMouseAtCenter(notification.closebutton, {}); }, onHidden: function (popup) { @@ -672,17 +672,17 @@ var tests = [ }, function (popup) { this.notification1.remove(); ok(this.notifyObj1.removedCallbackTriggered, "removed callback triggered"); this.notification2.remove(); ok(this.notifyObj2.removedCallbackTriggered, "removed callback triggered"); } - ], + ] }, // Test that multiple notification icons are removed when switching tabs { // Test #22 run: function () { // show the notification on old tab. this.notifyObjOld = new basicNotification(); this.notifyObjOld.anchorID = "default-notification-icon"; this.notificationOld = showNotification(this.notifyObjOld); @@ -713,17 +713,17 @@ var tests = [ }, function (popup) { this.notificationNew.remove(); gBrowser.removeTab(gBrowser.selectedTab); gBrowser.selectedTab = this.oldSelectedTab; this.notificationOld.remove(); } - ], + ] } ]; function showNotification(notifyObj) { return PopupNotifications.show(notifyObj.browser, notifyObj.id, notifyObj.message, notifyObj.anchorID,
new file mode 100644 --- /dev/null +++ b/browser/base/content/test/plugin_bug743421.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +</head> +<body> +<script> +function addPlugin(callback) { + var embed = document.createElement("embed"); + embed.style.width = "200px"; + embed.style.height = "200px"; + embed.setAttribute("type", "application/x-test"); + return document.body.appendChild(embed); +} +</script> +</body> +</html>
--- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -2896,21 +2896,16 @@ SessionStoreService.prototype = { this.restoreHistoryPrecursor(aWindow, tabs, winData.tabs, (aOverwriteTabs ? (parseInt(winData.selected) || 1) : 0), 0, 0); if (aState.scratchpads) { ScratchpadManager.restoreSession(aState.scratchpads); } - // This will force the keypress listener that Panorama has to attach if it - // isn't already. This will be the case if tab view wasn't entered or there - // were only visible tabs when TabView.init was first called. - aWindow.TabView.init(); - // set smoothScroll back to the original value tabstrip.smoothScroll = smoothScroll; this._sendRestoreCompletedNotifications(); }, /** * Manage history restoration for a window
--- a/browser/config/mozconfigs/win32/debug +++ b/browser/config/mozconfigs/win32/debug @@ -2,12 +2,16 @@ ac_add_options --enable-debug ac_add_options --enable-trace-malloc ac_add_options --enable-signmar # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 mk_add_options MOZ_MAKE_FLAGS=-j1 -. $topsrcdir/build/win32/mozconfig.vs2010 +if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then + . $topsrcdir/build/win32/mozconfig.vs2010-win64 +else + . $topsrcdir/build/win32/mozconfig.vs2010 +fi # Package js shell. export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/win32/l10n-mozconfig +++ b/browser/config/mozconfigs/win32/l10n-mozconfig @@ -1,6 +1,10 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-official-branding ac_add_options --with-l10n-base=../../l10n-central -. $topsrcdir/build/win32/mozconfig.vs2010 +if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then + . $topsrcdir/build/win32/mozconfig.vs2010-win64 +else + . $topsrcdir/build/win32/mozconfig.vs2010 +fi
--- a/browser/config/mozconfigs/win32/nightly +++ b/browser/config/mozconfigs/win32/nightly @@ -11,12 +11,16 @@ ac_add_options --enable-js-diagnostics # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 mk_add_options MOZ_MAKE_FLAGS=-j1 -. $topsrcdir/build/win32/mozconfig.vs2010 +if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then + . $topsrcdir/build/win32/mozconfig.vs2010-win64 +else + . $topsrcdir/build/win32/mozconfig.vs2010 +fi # Package js shell. export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/win32/release +++ b/browser/config/mozconfigs/win32/release @@ -7,12 +7,16 @@ ac_add_options --enable-update-packaging ac_add_options --enable-jemalloc ac_add_options --enable-official-branding # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1 -. $topsrcdir/build/win32/mozconfig.vs2010 +if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then + . $topsrcdir/build/win32/mozconfig.vs2010-win64 +else + . $topsrcdir/build/win32/mozconfig.vs2010 +fi # Package js shell. export MOZ_PACKAGE_JSSHELL=1
--- a/browser/devtools/debugger/DebuggerUI.jsm +++ b/browser/devtools/debugger/DebuggerUI.jsm @@ -41,16 +41,17 @@ * ***** END LICENSE BLOCK ***** */ "use strict"; const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; const DBG_XUL = "chrome://browser/content/debugger.xul"; +const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties"; const REMOTE_PROFILE_NAME = "_remote-debug"; Cu.import("resource://gre/modules/devtools/dbg-server.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); let EXPORTED_SYMBOLS = ["DebuggerUI"]; @@ -77,71 +78,89 @@ DebuggerUI.prototype = { if (tab._scriptDebugger) { tab._scriptDebugger.close(); return null; } return new DebuggerPane(tab); }, /** - * Starts a remote debugger in a new process, or stops it if already started. - * @see DebuggerProcess.constructor - * @return DebuggerProcess if the debugger is started, null if it's stopped. + * Starts a remote debugger in a new window, or stops it if already started. + * @return RemoteDebuggerWindow if the debugger is started, null if stopped. */ - toggleRemoteDebugger: function DUI_toggleRemoteDebugger(aOnClose, aOnRun) { + toggleRemoteDebugger: function DUI_toggleRemoteDebugger() { let win = this.chromeWindow; if (win._remoteDebugger) { win._remoteDebugger.close(); return null; } - return new DebuggerProcess(win, aOnClose, aOnRun); + return new RemoteDebuggerWindow(this); }, /** * Starts a chrome debugger in a new process, or stops it if already started. - * @see DebuggerProcess.constructor - * @return DebuggerProcess if the debugger is started, null if it's stopped. + * @return ChromeDebuggerProcess if the debugger is started, null if stopped. */ toggleChromeDebugger: function DUI_toggleChromeDebugger(aOnClose, aOnRun) { let win = this.chromeWindow; if (win._chromeDebugger) { win._chromeDebugger.close(); return null; } - return new DebuggerProcess(win, aOnClose, aOnRun, true); + return new ChromeDebuggerProcess(win, aOnClose, aOnRun, true); }, /** * Get the debugger for a specified tab. - * @return DebuggerPane if a debugger exists for the tab, null otherwise + * @return DebuggerPane if a debugger exists for the tab, null otherwise. */ getDebugger: function DUI_getDebugger(aTab) { return aTab._scriptDebugger; }, /** + * Get the remote debugger for the current chrome window. + * @return RemoteDebuggerWindow if a remote debugger exists, null otherwise. + */ + getRemoteDebugger: function DUI_getRemoteDebugger() { + let win = this.chromeWindow; + return '_remoteDebugger' in win ? win._remoteDebugger : null; + }, + + /** + * Get the chrome debugger for the current firefox instance. + * @return ChromeDebuggerProcess if a chrome debugger exists, null otherwise. + */ + getChromeDebugger: function DUI_getChromeDebugger() { + let win = this.chromeWindow; + return '_chromeDebugger' in win ? win._chromeDebugger : null; + }, + + /** * Get the preferences associated with the debugger frontend. * @return object */ get preferences() { return DebuggerPreferences; } }; /** * Creates a pane that will host the debugger. * + * @param DebuggerUI aDebuggerUI + * The parent instance creating the new debugger. * @param XULElement aTab * The tab in which to create the debugger. */ function DebuggerPane(aTab) { this._tab = aTab; - + this._initServer(); this._create(); } DebuggerPane.prototype = { /** * Initializes the debugger server. @@ -176,17 +195,17 @@ DebuggerPane.prototype = { let self = this; this._frame.addEventListener("Debugger:Loaded", function dbgLoaded() { self._frame.removeEventListener("Debugger:Loaded", dbgLoaded, true); self._frame.addEventListener("Debugger:Close", self.close, true); self._frame.addEventListener("unload", self.close, true); // Bind shortcuts for accessing the breakpoint methods in the debugger. - let bkp = self.debuggerWindow.DebuggerController.Breakpoints; + let bkp = self.contentWindow.DebuggerController.Breakpoints; self.addBreakpoint = bkp.addBreakpoint; self.removeBreakpoint = bkp.removeBreakpoint; self.getBreakpoint = bkp.getBreakpoint; }, true); this._frame.setAttribute("src", DBG_XUL); }, @@ -211,57 +230,134 @@ DebuggerPane.prototype = { this._frame = null; this._nbox = null; }, /** * Gets the debugger content window. * @return nsIDOMWindow if a debugger window exists, null otherwise */ - get debuggerWindow() { + get contentWindow() { return this._frame ? this._frame.contentWindow : null; }, /** * Shortcut for accessing the list of breakpoints in the debugger. * @return object if a debugger window exists, null otherwise */ get breakpoints() { - let debuggerWindow = this.debuggerWindow; - if (debuggerWindow) { - return debuggerWindow.DebuggerController.Breakpoints.store; + let contentWindow = this.contentWindow; + if (contentWindow) { + return contentWindow.DebuggerController.Breakpoints.store; } return null; } }; /** - * Creates a process that will hold the remote debugger. + * Creates a window that will host a remote debugger. + * + * @param DebuggerUI aDebuggerUI + * The parent instance creating the new debugger. + */ +function RemoteDebuggerWindow(aDebuggerUI) { + this._globalUI = aDebuggerUI; + this._win = aDebuggerUI.chromeWindow; + + this._create(); +} + +RemoteDebuggerWindow.prototype = { + + /** + * Creates and initializes the widgets containing the remote debugger UI. + */ + _create: function DP__create() { + this._win._remoteDebugger = this; + + this._dbgwin = this._globalUI.chromeWindow.open(DBG_XUL, + L10N.getStr("remoteDebuggerWindowTitle"), + "width=" + DebuggerPreferences.remoteWinWidth + "," + + "height=" + DebuggerPreferences.remoteWinHeight + "," + + "chrome,dependent,resizable,centerscreen"); + + this._dbgwin._remoteFlag = true; + + this.close = this.close.bind(this); + let self = this; + + this._dbgwin.addEventListener("Debugger:Loaded", function dbgLoaded() { + self._dbgwin.removeEventListener("Debugger:Loaded", dbgLoaded, true); + self._dbgwin.addEventListener("Debugger:Close", self.close, true); + self._dbgwin.addEventListener("unload", self.close, true); + + // Bind shortcuts for accessing the breakpoint methods in the debugger. + let bkp = self.contentWindow.DebuggerController.Breakpoints; + self.addBreakpoint = bkp.addBreakpoint; + self.removeBreakpoint = bkp.removeBreakpoint; + self.getBreakpoint = bkp.getBreakpoint; + }, true); + }, + + /** + * Closes the remote debugger, along with the parent window if necessary. + */ + close: function DP_close() { + if (!this._win) { + return; + } + delete this._win._remoteDebugger; + this._win = null; + + this._dbgwin.close(); + this._dbgwin = null; + }, + + /** + * Gets the remote debugger content window. + * @return nsIDOMWindow if a debugger window exists, null otherwise. + */ + get contentWindow() { + return this._dbgwin; + }, + + /** + * Shortcut for accessing the list of breakpoints in the remote debugger. + * @return object if a debugger window exists, null otherwise. + */ + get breakpoints() { + let contentWindow = this.contentWindow; + if (contentWindow) { + return contentWindow.DebuggerController.Breakpoints.store; + } + return null; + } +}; + +/** + * Creates a process that will hold a chrome debugger. * * @param function aOnClose * Optional, a function called when the process exits. * @param function aOnRun * Optional, a function called when the process starts running. - * @param boolean aInitServerFlag - * True to initialize the server. This should happen only in the chrome - * debugging case. This should also be true by default after bug #747429. * @param nsIDOMWindow aWindow - * The chrome window for which the remote debugger instance is created. + * The chrome window for which the debugger instance is created. */ -function DebuggerProcess(aWindow, aOnClose, aOnRun, aInitServerFlag) { +function ChromeDebuggerProcess(aWindow, aOnClose, aOnRun) { this._win = aWindow; this._closeCallback = aOnClose; this._runCallback = aOnRun; - aInitServerFlag && this._initServer(); + this._initServer(); this._initProfile(); this._create(); } -DebuggerProcess.prototype = { +ChromeDebuggerProcess.prototype = { /** * Initializes the debugger server. */ _initServer: function RDP__initServer() { if (!DebuggerServer.initialized) { DebuggerServer.init(); DebuggerServer.addBrowserActors(); @@ -288,17 +384,17 @@ DebuggerProcess.prototype = { this._dbgProfile = profileService.createProfile(null, null, dbgProfileName); profileService.flush(); }, /** * Creates and initializes the profile & process for the remote debugger. */ _create: function RDP__create() { - this._win._remoteDebugger = this; + this._win._chromeDebugger = this; let file = FileUtils.getFile("CurProcD", [Services.appinfo.OS == "WINNT" ? "firefox.exe" : "firefox-bin"]); let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); process.init(file); @@ -318,17 +414,17 @@ DebuggerProcess.prototype = { /** * Closes the remote debugger, removing the profile and killing the process. */ close: function RDP_close() { if (!this._win) { return; } - delete this._win._remoteDebugger; + delete this._win._chromeDebugger; this._win = null; if (this._dbgProcess.isRunning) { this._dbgProcess.kill(); } if (this._dbgProfile) { this._dbgProfile.remove(false); } @@ -337,16 +433,36 @@ DebuggerProcess.prototype = { } this._dbgProcess = null; this._dbgProfile = null; } }; /** + * Localization convenience methods. + */ +let L10N = { + + /** + * L10N shortcut function. + * + * @param string aName + * @return string + */ + getStr: function L10N_getStr(aName) { + return this.stringBundle.GetStringFromName(aName); + } +}; + +XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() { + return Services.strings.createBundle(DBG_STRINGS_URI); +}); + +/** * Various debugger preferences. */ let DebuggerPreferences = { /** * Gets the preferred height of the debugger pane. * @return number */
--- a/browser/devtools/debugger/debugger-controller.js +++ b/browser/devtools/debugger/debugger-controller.js @@ -82,16 +82,17 @@ let DebuggerController = { } this._isInitialized = true; window.removeEventListener("DOMContentLoaded", this._startupDebugger, true); DebuggerView.initializeEditor(); DebuggerView.StackFrames.initialize(); DebuggerView.Properties.initialize(); DebuggerView.Scripts.initialize(); + DebuggerView.showCloseButton(!this._isRemoteDebugger && !this._isChromeDebugger); this.dispatchEvent("Debugger:Loaded"); this._connect(); }, /** * Destroys the debugger view, disconnects the debugger client and cleans up * any active listeners. @@ -109,27 +110,74 @@ let DebuggerController = { DebuggerView.Properties.destroy(); DebuggerController.SourceScripts.disconnect(); DebuggerController.StackFrames.disconnect(); DebuggerController.ThreadState.disconnect(); this.dispatchEvent("Debugger:Unloaded"); this._disconnect(); - this._isRemote && this._quitApp(); + this._isChromeDebugger && this._quitApp(); + }, + + /** + * Prepares the hostname and port number for a remote debugger connection + * and handles connection retries and timeouts. + * + * @return boolean true if connection should proceed normally + */ + _prepareConnection: function DC__prepareConnection() { + // If we exceeded the total number of connection retries, bail. + if (this._remoteConnectionTry === Prefs.remoteConnectionRetries) { + Services.prompt.alert(null, + L10N.getStr("remoteDebuggerPromptTitle"), + L10N.getStr("remoteDebuggerConnectionFailedMessage")); + this.dispatchEvent("Debugger:Close"); + return false; + } + + // TODO: This is ugly, need to rethink the design for the UI in #751677. + if (!Prefs.remoteAutoConnect) { + let prompt = new RemoteDebuggerPrompt(); + let result = prompt.show(!!this._remoteConnectionTimeout); + if (!result) { + this.dispatchEvent("Debugger:Close"); + return false; + } + Prefs.remoteHost = prompt.uri.host; + Prefs.remotePort = prompt.uri.port; + } + + // If this debugger is connecting remotely to a server, we need to check + // after a while if the connection actually succeeded. + this._remoteConnectionTry = ++this._remoteConnectionTry || 1; + this._remoteConnectionTimeout = window.setTimeout(function() { + // If we couldn't connect to any server yet, try again... + if (!DebuggerController.activeThread) { + DebuggerController._connect(); + } + }, Prefs.remoteTimeout); + + return true; }, /** * Initializes a debugger client and connects it to the debugger server, * wiring event handlers as necessary. */ _connect: function DC__connect() { - let transport = - this._isRemote ? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort) - : DebuggerServer.connectPipe(); + if (this._isRemoteDebugger) { + if (!this._prepareConnection()) { + return; + } + } + + let transport = (this._isChromeDebugger || this._isRemoteDebugger) + ? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort) + : DebuggerServer.connectPipe(); let client = this.client = new DebuggerClient(transport); client.addListener("tabNavigated", this._onTabNavigated); client.addListener("tabDetached", this._onTabDetached); client.connect(function(aType, aTraits) { client.listTabs(function(aResponse) { @@ -218,18 +266,26 @@ let DebuggerController = { }.bind(this)); }.bind(this)); }, /** * Returns true if this is a remote debugger instance. * @return boolean */ - get _isRemote() { - return !window.parent.content; + get _isRemoteDebugger() { + return window._remoteFlag; + }, + + /** + * Returns true if this is a chrome debugger instance. + * @return boolean + */ + get _isChromeDebugger() { + return !window.parent.content && !this._isRemoteDebugger; }, /** * Attempts to quit the current process if allowed. */ _quitApp: function DC__quitApp() { let canceled = Cc["@mozilla.org/supports-PRBool;1"] .createInstance(Ci.nsISupportsPRBool); @@ -1320,17 +1376,39 @@ let L10N = { XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() { return Services.strings.createBundle(DBG_STRINGS_URI); }); /** * Shortcuts for accessing various debugger preferences. */ -let Prefs = {}; +let Prefs = { + + /** + * Gets a flag specifying if the the debugger should automatically connect to + * the default host and port number. + * @return boolean + */ + get remoteAutoConnect() { + if (this._autoConn === undefined) { + this._autoConn = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect"); + } + return this._autoConn; + }, + + /** + * Sets a flag specifying if the the debugger should automatically connect. + * @param boolean value + */ + set remoteAutoConnect(value) { + Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", value); + this._autoConn = value; + } +}; /** * Gets the preferred default remote debugging host. * @return string */ XPCOMUtils.defineLazyGetter(Prefs, "remoteHost", function() { return Services.prefs.getCharPref("devtools.debugger.remote-host"); }); @@ -1339,16 +1417,32 @@ XPCOMUtils.defineLazyGetter(Prefs, "remo * Gets the preferred default remote debugging port. * @return number */ XPCOMUtils.defineLazyGetter(Prefs, "remotePort", function() { return Services.prefs.getIntPref("devtools.debugger.remote-port"); }); /** + * Gets the max number of attempts to reconnect to a remote server. + * @return number + */ +XPCOMUtils.defineLazyGetter(Prefs, "remoteConnectionRetries", function() { + return Services.prefs.getIntPref("devtools.debugger.remote-connection-retries"); +}); + +/** + * Gets the remote debugging connection timeout (in milliseconds). + * @return number + */ +XPCOMUtils.defineLazyGetter(Prefs, "remoteTimeout", function() { + return Services.prefs.getIntPref("devtools.debugger.remote-timeout"); +}); + +/** * Preliminary setup for the DebuggerController object. */ DebuggerController.init(); DebuggerController.ThreadState = new ThreadState(); DebuggerController.StackFrames = new StackFrames(); DebuggerController.SourceScripts = new SourceScripts(); DebuggerController.Breakpoints = new Breakpoints();
--- a/browser/devtools/debugger/debugger-view.js +++ b/browser/devtools/debugger/debugger-view.js @@ -77,16 +77,71 @@ let DebuggerView = { }, /** * The load event handler for the source editor. This method does post-load * editor initialization. */ _onEditorLoad: function DV__onEditorLoad() { DebuggerController.Breakpoints.initialize(); + }, + + /** + * Sets the close button hidden or visible. It's hidden by default. + * @param boolean aVisibleFlag + */ + showCloseButton: function DV_showCloseButton(aVisibleFlag) { + document.getElementById("close").setAttribute("hidden", !aVisibleFlag); + } +}; + +/** + * A simple way of displaying a "Connect to..." prompt. + */ +function RemoteDebuggerPrompt() { + + /** + * The remote uri the user wants to connect to. + */ + this.uri = null; +} + +RemoteDebuggerPrompt.prototype = { + + /** + * Shows the prompt and sets the uri using the user input. + * + * @param boolean aIsReconnectingFlag + * True to show the reconnect message instead. + */ + show: function RDP_show(aIsReconnectingFlag) { + let check = { value: Prefs.remoteAutoConnect }; + let input = { value: "http://" + Prefs.remoteHost + + ":" + Prefs.remotePort + "/" }; + + while (true) { + let result = Services.prompt.prompt(null, + L10N.getStr("remoteDebuggerPromptTitle"), + L10N.getStr(aIsReconnectingFlag + ? "remoteDebuggerReconnectMessage" + : "remoteDebuggerPromptMessage"), input, + L10N.getStr("remoteDebuggerPromptCheck"), check); + + Prefs.remoteAutoConnect = check.value; + + try { + let uri = Services.io.newURI(input.value, null, null); + let url = uri.QueryInterface(Ci.nsIURL); + + // If a url could be successfully retrieved, then the uri is correct. + this.uri = uri; + return result; + } + catch(e) { } + } } }; /** * Functions handling the scripts UI. */ function ScriptsView() { this._onScriptsChange = this._onScriptsChange.bind(this);
--- a/browser/devtools/debugger/debugger.xul +++ b/browser/devtools/debugger/debugger.xul @@ -70,17 +70,17 @@ </xul:popupset> <xul:commandset id="editMenuCommands"/> <xul:commandset id="sourceEditorCommands"/> <xul:keyset id="sourceEditorKeys"/> <div id="body" class="vbox flex"> <xul:toolbar id="dbg-toolbar"> - <xul:button id="close">&debuggerUI.closeButton;</xul:button> + <xul:button id="close" hidden="false">&debuggerUI.closeButton;</xul:button> <xul:button id="resume"/> <xul:button id="step-over">&debuggerUI.stepOverButton;</xul:button> <xul:button id="step-in">&debuggerUI.stepInButton;</xul:button> <xul:button id="step-out">&debuggerUI.stepOutButton;</xul:button> <xul:menulist id="scripts"/> <xul:textbox id="scripts-search" type="search" emptytext="&debuggerUI.emptyFilterText;"/> </xul:toolbar>
--- a/browser/devtools/debugger/test/Makefile.in +++ b/browser/devtools/debugger/test/Makefile.in @@ -42,16 +42,17 @@ srcdir = @srcdir@ VPATH = @srcdir@ relativesrcdir = browser/devtools/debugger/test include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _BROWSER_TEST_FILES = \ browser_dbg_createRemote.js \ + browser_dbg_createChrome.js \ browser_dbg_debuggerstatement.js \ browser_dbg_listtabs.js \ browser_dbg_tabactor-01.js \ browser_dbg_tabactor-02.js \ browser_dbg_contextactor-01.js \ browser_dbg_contextactor-02.js \ testactors.js \ browser_dbg_nav-01.js \
--- a/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js +++ b/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js @@ -25,17 +25,17 @@ function test() let framesAdded = false; let resumed = false; let testStarted = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; resumed = true; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; executeSoon(startTest); }); executeSoon(function() {
--- a/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js +++ b/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js @@ -23,17 +23,17 @@ function test() let framesAdded = false; let resumed = false; let testStarted = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; resumed = true; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; executeSoon(startTest); }); executeSoon(function() {
--- a/browser/devtools/debugger/test/browser_dbg_clean-exit.js +++ b/browser/devtools/debugger/test/browser_dbg_clean-exit.js @@ -10,17 +10,17 @@ var gTab = null; var gDebugger = null; const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html"; function test() { debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testCleanExit(); }); } function testCleanExit() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
new file mode 100644 --- /dev/null +++ b/browser/devtools/debugger/test/browser_dbg_createChrome.js @@ -0,0 +1,89 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Tests that a chrome debugger can be created in a new process. + +var gProcess = null; +var gTab = null; +var gDebuggee = null; + +function test() { + debug_chrome(STACK_URL, aOnClosing, function(aTab, aDebuggee, aProcess) { + gTab = aTab; + gDebuggee = aDebuggee; + gProcess = aProcess; + + testSimpleCall(); + }); +} + +function testSimpleCall() { + Services.tm.currentThread.dispatch({ run: function() { + + ok(gProcess._dbgProcess, + "The remote debugger process wasn't created properly!"); + ok(gProcess._dbgProcess.isRunning, + "The remote debugger process isn't running!"); + is(typeof gProcess._dbgProcess.pid, "number", + "The remote debugger process doesn't have a pid (?!)"); + + info("process location: " + gProcess._dbgProcess.location); + info("process pid: " + gProcess._dbgProcess.pid); + info("process name: " + gProcess._dbgProcess.processName); + info("process sig: " + gProcess._dbgProcess.processSignature); + + ok(gProcess._dbgProfile, + "The remote debugger profile wasn't created properly!"); + ok(gProcess._dbgProfile.localDir, + "The remote debugger profile doesn't have a localDir..."); + ok(gProcess._dbgProfile.rootDir, + "The remote debugger profile doesn't have a rootDir..."); + ok(gProcess._dbgProfile.name, + "The remote debugger profile doesn't have a name..."); + + info("profile localDir: " + gProcess._dbgProfile.localDir); + info("profile rootDir: " + gProcess._dbgProfile.rootDir); + info("profile name: " + gProcess._dbgProfile.name); + + let profileService = Cc["@mozilla.org/toolkit/profile-service;1"] + .createInstance(Ci.nsIToolkitProfileService); + + let profile = profileService.getProfileByName(gProcess._dbgProfile.name); + + ok(profile, + "The remote debugger profile wasn't *actually* created properly!"); + is(profile.localDir.path, gProcess._dbgProfile.localDir.path, + "The remote debugger profile doesn't have the correct localDir!"); + is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path, + "The remote debugger profile doesn't have the correct rootDir!"); + + DebuggerUI.toggleChromeDebugger(); + }}, 0); +} + +function aOnClosing() { + ok(!gProcess._dbgProcess.isRunning, + "The remote debugger process isn't closed as it should be!"); + is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256), + "The remote debugger process didn't die cleanly."); + + info("process exit value: " + gProcess._dbgProcess.exitValue); + + info("profile localDir: " + gProcess._dbgProfile.localDir.path); + info("profile rootDir: " + gProcess._dbgProfile.rootDir.path); + info("profile name: " + gProcess._dbgProfile.name); + + executeSoon(function() { + finish(); + }); +} + +registerCleanupFunction(function() { + removeTab(gTab); + gProcess = null; + gTab = null; + gDebuggee = null; +});
--- a/browser/devtools/debugger/test/browser_dbg_createRemote.js +++ b/browser/devtools/debugger/test/browser_dbg_createRemote.js @@ -1,86 +1,80 @@ -/* vim:set ts=2 sw=2 sts=2 et: */ /* * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ -var gProcess = null; + +// Tests that a remote debugger can be created in a new window. + +var gWindow = null; var gTab = null; -var gDebuggee = null; +var gAutoConnect = null; + +const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html"; function test() { - remote_debug_tab_pane(STACK_URL, aOnClosing, function(aTab, aDebuggee, aProcess) { + debug_remote(TEST_URL, function(aTab, aDebuggee, aWindow) { gTab = aTab; - gDebuggee = aDebuggee; - gProcess = aProcess; + gWindow = aWindow; + let gDebugger = gWindow.contentWindow; - testSimpleCall(); - }); -} + is(gDebugger.document.getElementById("close").getAttribute("hidden"), "true", + "The close button should be hidden in a remote debugger."); -function testSimpleCall() { - Services.tm.currentThread.dispatch({ run: function() { + is(gDebugger.DebuggerController.activeThread.paused, false, + "Should be running after debug_remote."); - ok(gProcess._dbgProcess, - "The remote debugger process wasn't created properly!"); - ok(gProcess._dbgProcess.isRunning, - "The remote debugger process isn't running!"); - is(typeof gProcess._dbgProcess.pid, "number", - "The remote debugger process doesn't have a pid (?!)"); + gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { + Services.tm.currentThread.dispatch({ run: function() { + + let frames = gDebugger.DebuggerView.StackFrames._frames; + let childNodes = frames.childNodes; - info("process location: " + gProcess._dbgProcess.location); - info("process pid: " + gProcess._dbgProcess.pid); - info("process name: " + gProcess._dbgProcess.processName); - info("process sig: " + gProcess._dbgProcess.processSignature); + is(gDebugger.DebuggerController.activeThread.paused, true, + "Should be paused after an interrupt request."); - ok(gProcess._dbgProfile, - "The remote debugger profile wasn't created properly!"); - ok(gProcess._dbgProfile.localDir, - "The remote debugger profile doesn't have a localDir..."); - ok(gProcess._dbgProfile.rootDir, - "The remote debugger profile doesn't have a rootDir..."); - ok(gProcess._dbgProfile.name, - "The remote debugger profile doesn't have a name..."); + is(frames.querySelectorAll(".dbg-stackframe").length, 1, + "Should have one frame in the stack."); - info("profile localDir: " + gProcess._dbgProfile.localDir); - info("profile rootDir: " + gProcess._dbgProfile.rootDir); - info("profile name: " + gProcess._dbgProfile.name); - - let profileService = Cc["@mozilla.org/toolkit/profile-service;1"] - .createInstance(Ci.nsIToolkitProfileService); + gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() { + Services.tm.currentThread.dispatch({ run: function() { + closeDebuggerAndFinish(gTab, true); + }}, 0); + }); - let profile = profileService.getProfileByName(gProcess._dbgProfile.name); + EventUtils.sendMouseEvent({ type: "click" }, + gDebugger.document.getElementById("resume"), + gDebugger); + }}, 0); + }); - ok(profile, - "The remote debugger profile wasn't *actually* created properly!"); - is(profile.localDir.path, gProcess._dbgProfile.localDir.path, - "The remote debugger profile doesn't have the correct localDir!"); - is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path, - "The remote debugger profile doesn't have the correct rootDir!"); + let iframe = gTab.linkedBrowser.contentWindow.wrappedJSObject.frames[0]; + + is(iframe.document.title, "Browser Debugger Test Tab", "Found the iframe"); - DebuggerUI.toggleRemoteDebugger(); - }}, 0); -} + iframe.runDebuggerStatement(); + }, + function beforeTabAdded() { + if (!DebuggerServer.initialized) { + DebuggerServer.init(); + DebuggerServer.addBrowserActors(); + } + DebuggerServer.closeListener(); -function aOnClosing() { - ok(!gProcess._dbgProcess.isRunning, - "The remote debugger process isn't closed as it should be!"); - is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256), - "The remote debugger process didn't die cleanly."); + gAutoConnect = Services.prefs.getBoolPref("devtools.debugger.remote-autoconnect"); + Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", true); - info("process exit value: " + gProcess._dbgProcess.exitValue); - - info("profile localDir: " + gProcess._dbgProfile.localDir.path); - info("profile rootDir: " + gProcess._dbgProfile.rootDir.path); - info("profile name: " + gProcess._dbgProfile.name); - - executeSoon(function() { - finish(); + // Open the listener at some point in the future to test automatic reconnect. + window.setTimeout(function() { + DebuggerServer.openListener( + Services.prefs.getIntPref("devtools.debugger.remote-port")); + }, Math.random() * 1000); }); } registerCleanupFunction(function() { + Services.prefs.setBoolPref("devtools.debugger.remote-autoconnect", gAutoConnect); removeTab(gTab); - gProcess = null; + gWindow = null; gTab = null; - gDebuggee = null; + gAutoConnect = null; });
--- a/browser/devtools/debugger/test/browser_dbg_displayName.js +++ b/browser/devtools/debugger/test/browser_dbg_displayName.js @@ -10,17 +10,17 @@ var gDebugger = null; const TAB_URL = EXAMPLE_URL + "browser_dbg_displayName.html"; function test() { debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testAnonCall(); }); } function testAnonCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_iframes.js +++ b/browser/devtools/debugger/test/browser_dbg_iframes.js @@ -9,17 +9,20 @@ var gPane = null; var gTab = null; const TEST_URL = EXAMPLE_URL + "browser_dbg_iframes.html"; function test() { debug_tab_pane(TEST_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gPane = aPane; - let gDebugger = gPane.debuggerWindow; + let gDebugger = gPane.contentWindow; + + is(gDebugger.document.getElementById("close").getAttribute("hidden"), "false", + "The close button should be visible in a normal content debugger."); is(gDebugger.DebuggerController.activeThread.paused, false, "Should be running after debug_tab_pane."); gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() { let frames = gDebugger.DebuggerView.StackFrames._frames;
--- a/browser/devtools/debugger/test/browser_dbg_location-changes.js +++ b/browser/devtools/debugger/test/browser_dbg_location-changes.js @@ -12,17 +12,17 @@ var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({
--- a/browser/devtools/debugger/test/browser_dbg_pause-resume.js +++ b/browser/devtools/debugger/test/browser_dbg_pause-resume.js @@ -7,17 +7,17 @@ var gPane = null; var gTab = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testPause(); }); } function testPause() { is(gDebugger.DebuggerController.activeThread.paused, false, "Should be running after debug_tab_pane.");
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js @@ -8,17 +8,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-02.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-02.js @@ -8,17 +8,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-03.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-03.js @@ -8,17 +8,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-04.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-04.js @@ -8,17 +8,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-05.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-05.js @@ -8,17 +8,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-06.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-06.js @@ -8,28 +8,31 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() { let globalScope = gDebugger.DebuggerView.Properties.globalScope; let localScope = gDebugger.DebuggerView.Properties.localScope; + globalScope.empty(); + localScope.empty(); + let windowVar = globalScope.addVar("window"); let documentVar = globalScope.addVar("document"); let localVar0 = localScope.addVar("localVariable"); let localVar1 = localScope.addVar("localVar1"); let localVar2 = localScope.addVar("localVar2"); let localVar3 = localScope.addVar("localVar3"); let localVar4 = localScope.addVar("localVar4"); let localVar5 = localScope.addVar("localVar5"); @@ -74,20 +77,28 @@ function testSimpleCall() { ok(localVar0, "The localVar0 hasn't been created correctly."); ok(localVar1, "The localVar1 hasn't been created correctly."); ok(localVar2, "The localVar2 hasn't been created correctly."); ok(localVar3, "The localVar3 hasn't been created correctly."); ok(localVar4, "The localVar4 hasn't been created correctly."); ok(localVar5, "The localVar5 hasn't been created correctly."); + for each (let elt in globalScope.querySelector(".details").childNodes) { + info("globalScope :: " + { + id: elt.id, className: elt.className }.toSource()); + } is(globalScope.querySelector(".details").childNodes.length, 2, "The globalScope doesn't contain all the created variable elements."); - is(localScope.querySelector(".details").childNodes.length, 7, + for each (let elt in localScope.querySelector(".details").childNodes) { + info("localScope :: " + { + id: elt.id, className: elt.className }.toSource()); + } + is(localScope.querySelector(".details").childNodes.length, 6, "The localScope doesn't contain all the created variable elements."); is(localVar5.querySelector(".details").childNodes.length, 6, "The localVar5 doesn't contain all the created properties."); is(localVar5.someProp5.querySelector(".details").childNodes.length, 6, "The localVar5.someProp5 doesn't contain all the created properties.");
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-07.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-07.js @@ -12,17 +12,17 @@ var gPane = null; var gTab = null; var gDebugger = null; function test() { debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testFrameParameters(); }); } function testFrameParameters() { dump("Started testFrameParameters!\n");
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-08.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-08.js @@ -12,17 +12,17 @@ var gPane = null; var gTab = null; var gDebugger = null; function test() { debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testFrameParameters(); }); } function testFrameParameters() { dump("Started testFrameParameters!\n");
--- a/browser/devtools/debugger/test/browser_dbg_script-switching.js +++ b/browser/devtools/debugger/test/browser_dbg_script-switching.js @@ -20,17 +20,17 @@ function test() let framesAdded = false; let resumed = false; let testStarted = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; resumed = true; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; executeSoon(startTest); }); executeSoon(function() {
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js +++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js @@ -15,17 +15,17 @@ function test() { let scriptShown = false; let framesAdded = false; debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; runTest(); }); gDebuggee.simpleCall(); });
--- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js +++ b/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js @@ -17,17 +17,17 @@ function test() { let scriptShown = false; let framesAdded = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; runTest(); }); gDebuggee.firstCall(); });
--- a/browser/devtools/debugger/test/browser_dbg_scripts-sorting.js +++ b/browser/devtools/debugger/test/browser_dbg_scripts-sorting.js @@ -8,17 +8,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_select-line.js +++ b/browser/devtools/debugger/test/browser_dbg_select-line.js @@ -19,17 +19,17 @@ var gDebugger = null; var gScripts = null; function test() { debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSelectLine(); }); } function testSelectLine() { gDebugger.DebuggerController.activeThread.addOneTimeListener("scriptsadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_stack-01.js +++ b/browser/devtools/debugger/test/browser_dbg_stack-01.js @@ -9,17 +9,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testSimpleCall(); }); } function testSimpleCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_stack-02.js +++ b/browser/devtools/debugger/test/browser_dbg_stack-02.js @@ -9,17 +9,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testEvalCall(); }); } function testEvalCall() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_stack-03.js +++ b/browser/devtools/debugger/test/browser_dbg_stack-03.js @@ -9,17 +9,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testRecurse(); }); } function testRecurse() { gDebuggee.gRecurseLimit = (gDebugger.DebuggerController.StackFrames.pageSize * 2) + 1;
--- a/browser/devtools/debugger/test/browser_dbg_stack-04.js +++ b/browser/devtools/debugger/test/browser_dbg_stack-04.js @@ -9,17 +9,17 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; function test() { debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; testEvalCallResume(); }); } function testEvalCallResume() { gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { Services.tm.currentThread.dispatch({ run: function() {
--- a/browser/devtools/debugger/test/browser_dbg_stack-05.js +++ b/browser/devtools/debugger/test/browser_dbg_stack-05.js @@ -17,17 +17,17 @@ var gDebugger = null; function test() { let scriptShown = false; let framesAdded = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; runTest(); }); gDebuggee.firstCall(); });
--- a/browser/devtools/debugger/test/browser_dbg_update-editor-mode.js +++ b/browser/devtools/debugger/test/browser_dbg_update-editor-mode.js @@ -24,17 +24,17 @@ function test() let framesAdded = false; let testStarted = false; let resumed = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; - gDebugger = gPane.debuggerWindow; + gDebugger = gPane.contentWindow; resumed = true; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; executeSoon(startTest); }); executeSoon(function() {
--- a/browser/devtools/debugger/test/head.js +++ b/browser/devtools/debugger/test/head.js @@ -44,22 +44,26 @@ function addTab(aURL, aOnload) return tab; } function removeTab(aTab) { gBrowser.removeTab(aTab); } -function closeDebuggerAndFinish(aTab) { +function closeDebuggerAndFinish(aTab, aRemoteFlag) { DebuggerUI.chromeWindow.addEventListener("Debugger:Shutdown", function cleanup() { DebuggerUI.chromeWindow.removeEventListener("Debugger:Shutdown", cleanup, false); finish(); }, false); - DebuggerUI.getDebugger(aTab).close(); + if (!aRemoteFlag) { + DebuggerUI.getDebugger(aTab).close(); + } else { + DebuggerUI.getRemoteDebugger().close(); + } } function get_tab_actor_for_url(aClient, aURL, aCallback) { aClient.listTabs(function(aResponse) { for each (let tab in aResponse.tabs) { if (tab.url == aURL) { aCallback(tab); return; @@ -94,28 +98,49 @@ function debug_tab_pane(aURL, aOnDebuggi gBrowser.selectedTab = gTab; let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject; let pane = DebuggerUI.toggleDebugger(); pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() { pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true); // Wait for the initial resume... - pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() { + pane.contentWindow.gClient.addOneTimeListener("resumed", function() { aOnDebugging(tab, debuggee, pane); }); }, true); }); } -function remote_debug_tab_pane(aURL, aOnClosing, aOnDebugging) +function debug_remote(aURL, aOnDebugging, aBeforeTabAdded) +{ + // Make any necessary preparations (start the debugger server etc.) + aBeforeTabAdded(); + + let tab = addTab(aURL, function() { + gBrowser.selectedTab = gTab; + let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject; + + let win = DebuggerUI.toggleRemoteDebugger(); + win._dbgwin.addEventListener("Debugger:Connecting", function dbgConnected() { + win._dbgwin.removeEventListener("Debugger:Connecting", dbgConnected, true); + + // Wait for the initial resume... + win.contentWindow.gClient.addOneTimeListener("resumed", function() { + aOnDebugging(tab, debuggee, win); + }); + }, true); + }); +} + +function debug_chrome(aURL, aOnClosing, aOnDebugging) { let tab = addTab(aURL, function() { gBrowser.selectedTab = gTab; let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject; - DebuggerUI.toggleRemoteDebugger(aOnClosing, function dbgRan(process) { + DebuggerUI.toggleChromeDebugger(aOnClosing, function dbgRan(process) { // Wait for the remote debugging process to start... aOnDebugging(tab, debuggee, process); }); }); }
--- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -56,16 +56,17 @@ const Ci = Components.interfaces; const Cu = Components.utils; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource:///modules/PropertyPanel.jsm"); Cu.import("resource:///modules/source-editor.jsm"); Cu.import("resource:///modules/devtools/scratchpad-manager.jsm"); +Cu.import("resource://gre/modules/jsdebugger.jsm"); const SCRATCHPAD_CONTEXT_CONTENT = 1; const SCRATCHPAD_CONTEXT_BROWSER = 2; const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties"; const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled"; const BUTTON_POSITION_SAVE = 0; const BUTTON_POSITION_CANCEL = 1; @@ -290,16 +291,17 @@ var Scratchpad = { return; } if (!this._chromeSandbox || this.browserWindow != this._previousBrowserWindow) { this._chromeSandbox = new Cu.Sandbox(this.browserWindow, { sandboxPrototype: this.browserWindow, wantXrays: false, sandboxName: 'scratchpad-chrome'}); + addDebuggerToGlobal(this._chromeSandbox); this._previousBrowserWindow = this.browserWindow; } return this._chromeSandbox; }, /**
--- a/browser/devtools/webconsole/GcliCommands.jsm +++ b/browser/devtools/webconsole/GcliCommands.jsm @@ -224,17 +224,17 @@ gcli.addCommand({ name: "file", type: { name: "selection", data: function() { let win = HUDService.currentContext(); let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab); let files = []; if (dbg) { - let scriptsView = dbg.debuggerWindow.DebuggerView.Scripts; + let scriptsView = dbg.contentWindow.DebuggerView.Scripts; for each (let script in scriptsView.scriptLocations) { files.push(script); } } return files; } }, description: gcli.lookup("breakaddlineFileDesc")
--- a/browser/devtools/webconsole/test/browser_gcli_break.js +++ b/browser/devtools/webconsole/test/browser_gcli_break.js @@ -68,27 +68,27 @@ function testCreateCommands() { type("break add line"); is(requisition.getStatus().toString(), "ERROR", "break add line is ERROR"); let pane = DebuggerUI.toggleDebugger(); pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() { pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true); // Wait for the initial resume. - pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() { - pane.debuggerWindow.gClient.activeThread.addOneTimeListener("framesadded", function() { + pane.contentWindow.gClient.addOneTimeListener("resumed", function() { + pane.contentWindow.gClient.activeThread.addOneTimeListener("framesadded", function() { type("break add line " + TEST_URI + " " + content.wrappedJSObject.line0); is(requisition.getStatus().toString(), "VALID", "break add line is VALID"); requisition.exec(); type("break list"); is(requisition.getStatus().toString(), "VALID", "break list is VALID"); requisition.exec(); - pane.debuggerWindow.gClient.activeThread.resume(function() { + pane.contentWindow.gClient.activeThread.resume(function() { type("break del 0"); is(requisition.getStatus().toString(), "VALID", "break del 0 is VALID"); requisition.exec(); closeConsole(); finishTest(); }); });
--- a/browser/installer/Makefile.in +++ b/browser/installer/Makefile.in @@ -109,16 +109,20 @@ endif ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET))) DEFINES += -DMOZ_SHARED_MOZGLUE=1 endif ifdef MOZ_JSDEBUGGER DEFINES += -DMOZ_JSDEBUGGER endif +ifdef NECKO_WIFI +DEFINES += -DNECKO_WIFI +endif + ifdef MOZ_PKG_MANIFEST_P MOZ_PKG_MANIFEST = package-manifest $(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) $(GLOBAL_DEPS) $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@ GARBAGE += $(MOZ_PKG_MANIFEST) endif
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.dtd +++ b/browser/locales/en-US/chrome/browser/devtools/debugger.dtd @@ -12,17 +12,17 @@ <!ENTITY debuggerMenu.label "Script Debugger"> <!-- LOCALIZATION NOTE (remoteDebuggerMenu.label): This is the label for the - application menu item that opens the remote debugger UI. --> <!ENTITY remoteDebuggerMenu.label "Remote Debugger"> <!-- LOCALIZATION NOTE (chromeDebuggerMenu.label): This is the label for the - application menu item that opens the browser debugger UI. --> -<!ENTITY chromeDebuggerMenu.label "Browser Debugger"> +<!ENTITY chromeDebuggerMenu.label "Browser Debugger"> <!-- LOCALIZATION NOTE (debuggerMenu.commandkey): This is the command key that - launches the debugger UI. Do not translate this one! --> <!ENTITY debuggerMenu.commandkey "S"> <!-- LOCALIZATION NOTE (debuggerUI.closeButton): This is the label for the - button that closes the debugger UI. --> <!ENTITY debuggerUI.closeButton "Close">
--- a/browser/locales/en-US/chrome/browser/devtools/debugger.properties +++ b/browser/locales/en-US/chrome/browser/devtools/debugger.properties @@ -1,16 +1,40 @@ # LOCALIZATION NOTE These strings are used inside the Script Debugger # which is available from the Web Developer sub-menu -> 'Script Debugger'. # The correct localization of this file might be to keep it in # English, or another language commonly spoken among web developers. # You want to make that choice consistent across the developer tools. # A good criteria is the language in which you'd find the best # documentation on web development on the web. +# LOCALIZATION NOTE (remoteDebuggerWindowTitle): The title displayed for the +# remote debugger window. +remoteDebuggerWindowTitle=Remote Debugger + +# LOCALIZATION NOTE (remoteDebuggerPromptTitle): The title displayed on the +# debugger prompt asking for the remote host and port to connect to. +remoteDebuggerPromptTitle=Remote Connection + +# LOCALIZATION NOTE (remoteDebuggerPromptMessage): The message displayed on the +# debugger prompt asking for the remote host and port to connect to. +remoteDebuggerPromptMessage=Enter hostname and port number (host:port) + +# LOCALIZATION NOTE (remoteDebuggerPromptCheck): The message displayed on the +# debugger prompt asking if the prompt should be shown again next time. +remoteDebuggerPromptCheck=Don't ask me again + +# LOCALIZATION NOTE (remoteDebuggerReconnectMessage): The message displayed on the +# debugger prompt asking for the remote host and port to connect to. +remoteDebuggerReconnectMessage=Server not found. Try again? (host:port) + +# LOCALIZATION NOTE (remoteDebuggerReconnectMessage): The message displayed on the +# debugger prompt asking for the remote host and port to connect to. +remoteDebuggerConnectionFailedMessage=Could not find a server at the specified hostname and port number. + # LOCALIZATION NOTE (pauseLabel): The label that is displayed on the pause # button when the debugger is in a running state. pauseLabel=Pause # LOCALIZATION NOTE (resumeLabel): The label that is displayed on the pause # button when the debugger is in a paused state. resumeLabel=Resume
index fed3d7f7cde2835388bf7ad5694e18d8042dba77..bb9cdf30a0ce9f4598513ca47ea93c54eeb5f52d GIT binary patch literal 244 zc$@+B01N+#P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0002HNkl<Zc-q~Q zy$ZrG7)2c%1Yg)OgTIa9<m-s84t)m^E5%|>4J6o*&)k4T!KR{%7&uVMxrb0_i-^AB zM*=vrIqy&SupCDN3IPW$HdTNz){ds5t5S-Z4jj1HJO(=MrGX%&41xm}o0kD0M2O}< zo}WV02i(Uo)>_K4V-PrSp8}lo?mdvEhY(c&8y|4j={ab%Uhbv5P?GF6j%^)9arQ1Y ujs*f_OzF{DzeD9?i$IKr4~hTaXSx9sav2rIV%A~+0000<MNUMnLSTZ*e_*Tt
--- a/browser/themes/gnomestripe/browser.css +++ b/browser/themes/gnomestripe/browser.css @@ -1064,16 +1064,17 @@ toolbar[iconsize="small"] #feed-button { opacity: 0.3; } /* Identity indicator */ #identity-box { padding: 1px; margin: -1px; -moz-margin-end: 0; + font-size: .9em; } #identity-box:-moz-locale-dir(ltr) { border-top-left-radius: 2.5px; border-bottom-left-radius: 2.5px; } #identity-box:-moz-locale-dir(rtl) { @@ -1088,19 +1089,29 @@ toolbar[iconsize="small"] #feed-button { #identity-icon-labels { -moz-padding-start: 2px; -moz-padding-end: 5px; } #identity-box.verifiedIdentity { background-color: #fff; - color: hsl(92,81%,16%); - -moz-border-end: 1px solid hsla(92,81%,16%,.2); + color: hsl(92,100%,30%); -moz-margin-end: 4px; + background-image: -moz-linear-gradient(hsla(92,81%,16%,0), + hsla(92,81%,16%,.2) 25%, + hsla(92,81%,16%,.2) 75%, + hsla(92,81%,16%,0)); + background-position: right; + background-size: 1px; + background-repeat: no-repeat; +} + +#identity-box.verifiedIdentity:-moz-locale-dir(rtl) { + background-position: left; } /* Identity popup icons */ #identity-popup-icon { height: 64px; width: 64px; padding: 0; list-style-image: url("chrome://browser/skin/identity.png"); @@ -1330,16 +1341,17 @@ toolbar[iconsize="small"] #feed-button { .ac-url-text, .ac-action-text { color: -moz-nativehyperlinktext; } richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon { list-style-image: url("chrome://browser/skin/actionicon-tab.png"); + padding: 0 3px; } .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) { color: GrayText; } .ac-comment[selected="true"], .ac-url-text[selected="true"], @@ -1725,17 +1737,17 @@ richlistitem[type~="action"][actiontype= } .alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon { list-style-image: url("chrome://global/skin/icons/loading_16.png"); } .alltabs-item[tabIsVisible] { /* box-shadow instead of background-color to work around native styling */ - box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15); + box-shadow: inset -5px 0 ThreeDShadow; } /* Sidebar */ #sidebar-header > .tabs-closebutton { margin-bottom: 0px !important; padding: 0px 2px 0px 2px !important; }
index fed3d7f7cde2835388bf7ad5694e18d8042dba77..ae2c789cbd2ecbc57ff8dbb40940a04f5f3d50d8 GIT binary patch literal 649 zc$@)=0(Sk0P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80006|Nkl<Zc-rli z-)mA~9LBBXov^Dew(h%Ml2c?|NdCG${=zxE5axwmcp;*A69ol>MeI*lbcA9u*|ZU{ zy9Uk84GW~vVrvwmpw`^g1nv8P@8J|>@4NS+n{)Be^S<Z#ygqu~<1zL7{r`$lKs#`| z-B<m7|AS~WT93!$^+Y03(}OvjLk3yqS*_N2m&>*0@px(?z=5k3@cDcX)9G}jSS*%H zrIPw5a4wU{RH(!P^Xzu}qd*|AL<LnU$_27;;A#cJ;qYocpDz~*1$7w6P`1WAo6TnT zdcBLWSnO#snN)c|77ko}fqE{NQ+YrZ4#VMaOoT$A<y0!A@_;NkH-Fg!!C<hK&1O{| zkkuD(I-QplMOmfGqw;_(IcB)B3rK$f*`HAQ5=w6(*-b2c8_C|r(tjiu{UbA;1x5j* z0K;Uqi~|hDh$qA`@#QZZBQwY{uS$Hyc|qV*wF13fZ;2*86G#8x6J=LefzH`k6>~Tz z0vx#d0v~DefRiH>AVwNnJJaXq-4-1m3iyX`;OZ{{3cTk8S>{@*E6)`yEZ`rky;zUH z)ff0cv^hamb8q_<3yt>${Qbzx>?mCJ;UmO5qQwcaX1EL*?+N&O<XqAhm?Yj3O-|l) zyWOeZ3bY0MHuE6fq7C?x-W$YgP8x9F>NfE%jW;=5WLjDQ+Kr2Y$yb7G!etAc{5UNS z*4Y^1Y#?*m={(a4&;SLR#FijUxNM=j_vdeX`+oA6=C_A9+sNFxH)mxYUak?>F9=-I jfGZetI>^E?9!930abuuPi=uRE00000NkvXXu0mjf4ka=I
--- a/browser/themes/pinstripe/browser.css +++ b/browser/themes/pinstripe/browser.css @@ -975,16 +975,17 @@ toolbar[mode="icons"] #zoom-in-button { } #identity-box { -moz-margin-end: 3px; padding-top: 1px; padding-bottom: 1px; -moz-padding-start: 4px; -moz-padding-end: 0; + font-size: .9em; } #identity-box:-moz-locale-dir(ltr) { border-top-left-radius: 2px; border-bottom-left-radius: 2px; } #identity-box:-moz-locale-dir(rtl) { @@ -1020,19 +1021,29 @@ toolbar[mode="icons"] #zoom-in-button { padding-left: 10.01px; } @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { padding-right: 10.01px; } #identity-box.verifiedIdentity { - color: hsl(92,100%,20%); - -moz-border-end: 1px solid hsla(92,81%,16%,.2); + color: hsl(92,100%,30%); -moz-padding-end: 4px; + background-image: -moz-linear-gradient(hsla(92,81%,16%,0), + hsla(92,81%,16%,.2) 25%, + hsla(92,81%,16%,.2) 75%, + hsla(92,81%,16%,0)); + background-position: right; + background-size: 1px; + background-repeat: no-repeat; +} + +#identity-box.verifiedIdentity:-moz-locale-dir(rtl) { + background-position: left; } #identity-box:-moz-focusring { box-shadow: 0 0 2px 1px -moz-mac-focusring inset, 0 0 2px 2px -moz-mac-focusring; -moz-border-end-style: none; -moz-padding-end: 5px; } @@ -1165,16 +1176,30 @@ richlistitem[selected="true"][current="t .ac-url-text, .ac-action-text { color: -moz-nativehyperlinktext; font: message-box; } richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon { list-style-image: url("chrome://browser/skin/actionicon-tab.png"); + -moz-image-region: rect(0, 16px, 16px, 0); + padding: 0 3px; +} + +richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon { + -moz-image-region: rect(16px, 16px, 32px, 0); +} + +window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon { + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon { + -moz-image-region: rect(16px, 32px, 32px, 16px); } .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) { color: GrayText; } .ac-comment[selected="true"], .ac-url-text[selected="true"], @@ -2166,17 +2191,17 @@ toolbarbutton.chevron > .toolbarbutton-m } .alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon { list-style-image: url("chrome://global/skin/icons/loading_16.png") !important; } .alltabs-item[tabIsVisible] { /* box-shadow instead of background-color to work around native styling */ - box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15); + box-shadow: inset -5px 0 ThreeDShadow; } /* Tabstrip close button */ .tabs-closebutton { -moz-padding-end: 4px; list-style-image: url("chrome://global/skin/icons/close.png"); -moz-image-region: rect(0, 16px, 16px, 0); border: none;
index fed3d7f7cde2835388bf7ad5694e18d8042dba77..f60f218e724db02776b92175919cf553ec007191 GIT binary patch literal 434 zc$@*U0ZsmiP)<h;3K|Lk000e1NJLTq000mG001Be1^@s68;SVL0004bNkl<Zc-rmL zPfNmZ7zgly*r_*Q-g^t3vQyA&>k>ghe~4l=lf;&-n)qj|Qp7ojrYM40YK3&nQ%-z( zp0H51>bDH)(BXsgx9|50j>!SQSpLw!b|~%LJ<`I5u~ILrlp(BCM$j4EqYPy&1H71t zMv^s9^%k7x?rhP$Na`9et6Bzva^X3VX@H_NKSh~fq|mbr9LRZyrEi!})-tevVt{;E zV}jYyffZhH3CB7}YL$r~<p4Vq?*q#_@i{><K#Z4}_%Vx}`PYG^t?0r=AlV3<=JDYa znNW5!kZMqu1`@oOr9(%kLtSoh{Y+lnQ(?`2;Rto8JNB#mKkyR+?#U@aUpz=aZS?qo z_8{Z24D|c`5FR|B))($EE7=V+@!*zG%kC%8K#ft;ZlI1TjOxP!bm2l(bj66W?%{zM zR6+)$qG_75Z|{K*A7C6mvnazTJLvehZr9}TLPIHsH0p9soem8cNO#DfE<FP;n*Jv5 c@Bf)z0DuQ9TfU7lIsgCw07*qoM6N<$f)nY<6#xJL
--- a/browser/themes/winstripe/browser.css +++ b/browser/themes/winstripe/browser.css @@ -1354,16 +1354,17 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl -moz-margin-start: 0; color: GrayText; } /* identity box */ #identity-box { padding: 2px; + font-size: .9em; } #identity-box:-moz-locale-dir(ltr) { border-top-left-radius: 1.5px; border-bottom-left-radius: 1.5px; } #identity-box:-moz-locale-dir(rtl) { @@ -1401,19 +1402,29 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl } @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) { /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */ padding-right: 5.01px; } #identity-box.verifiedIdentity { - color: hsl(92,100%,20%); - -moz-border-end: 1px solid hsla(92,81%,16%,.2); + color: hsl(92,100%,30%); -moz-margin-end: 4px; + background-image: -moz-linear-gradient(hsla(92,81%,16%,0), + hsla(92,81%,16%,.2) 25%, + hsla(92,81%,16%,.2) 75%, + hsla(92,81%,16%,0)); + background-position: right; + background-size: 1px; + background-repeat: no-repeat; +} + +#identity-box.verifiedIdentity:-moz-locale-dir(rtl) { + background-position: left; } #identity-box.verifiedIdentity:not(:-moz-lwtheme) { background-color: #fff; } #identity-box:-moz-focusring { outline: 1px dotted #000; @@ -1531,16 +1542,22 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl .ac-action-text { color: #006600; } } %endif richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon { list-style-image: url("chrome://browser/skin/actionicon-tab.png"); + -moz-image-region: rect(0, 16px, 16px, 0); + padding: 0 3px; +} + +richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon { + -moz-image-region: rect(16px, 16px, 32px, 0); } .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) { color: GrayText; } .ac-comment[selected="true"], .ac-url-text[selected="true"], @@ -2064,17 +2081,17 @@ richlistitem[type~="action"][actiontype= } .alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon { list-style-image: url("chrome://global/skin/icons/loading_16.png"); } .alltabs-item[tabIsVisible] { /* box-shadow instead of background-color to work around native styling */ - box-shadow: inset 0 0 0 2em hsla(0,0%,50%,.15); + box-shadow: inset -5px 0 ThreeDShadow; } /* Tabstrip close button */ .tabs-closebutton { -moz-appearance: none; list-style-image: url("chrome://global/skin/icons/close.png"); -moz-image-region: rect(0, 16px, 16px, 0); padding: 4px 2px;
deleted file mode 100644 --- a/build/asan/asan-blacklist.txt +++ /dev/null @@ -1,8 +0,0 @@ -fun:_ZN2js6Parser* -fun:_ZN2js13FoldConstants* -fun:_ZN2js8frontend.Emit* -fun:_ZN2js8frontend..Emit* -fun:_ZL.Emit* -fun:_ZL..Emit* -fun:_ZN2jsL23MarkRangeConservativelyEP8JSTracerPKmS3_ -fun:_ZN2jsL23MarkRangeConservativelyEP8JSTracerPKjS3_
--- a/build/automationutils.py +++ b/build/automationutils.py @@ -454,17 +454,17 @@ def wrapCommand(cmd): return cmd class ShutdownLeakLogger(object): """ Parses the mochitest run log when running a debug build, assigns all leaked DOM windows (that are still around after test suite shutdown, despite running the GC) to the tests that created them and prints leak statistics. """ - MAX_LEAK_COUNT = 23 + MAX_LEAK_COUNT = 21 def __init__(self, logger): self.logger = logger self.tests = [] self.leakedWindows = {} self.leakedDocShells = set() self.currentTest = None self.seenShutdown = False
--- a/build/package/mac_osx/pkg-dmg +++ b/build/package/mac_osx/pkg-dmg @@ -302,20 +302,20 @@ my(@gCleanup, %gConfig, $gDarwinMajor, $ %gConfig = ('cmd_bless' => 'bless', 'cmd_chmod' => 'chmod', 'cmd_diskutil' => 'diskutil', 'cmd_du' => 'du', 'cmd_hdid' => 'hdid', 'cmd_hdiutil' => 'hdiutil', 'cmd_mkdir' => 'mkdir', 'cmd_mktemp' => 'mktemp', - 'cmd_Rez' => '/Developer/Tools/Rez', + 'cmd_Rez' => 'Rez', 'cmd_rm' => 'rm', 'cmd_rsync' => 'rsync', - 'cmd_SetFile' => '/Developer/Tools/SetFile', + 'cmd_SetFile' => 'SetFile', # create_directly indicates whether hdiutil create supports # -srcfolder and -srcdevice. It does on >= 10.3 (Panther). # This is fixed up for earlier systems below. If false, # hdiutil create is used to create empty disk images that # are manually filled. 'create_directly' => 1,
--- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -358,20 +358,17 @@ nsScriptSecurityManager::GetCurrentJSCon return nsnull; return cx; } JSContext * nsScriptSecurityManager::GetSafeJSContext() { // Get JSContext from stack. - JSContext *cx; - if (NS_FAILED(sJSContextStack->GetSafeJSContext(&cx))) - return nsnull; - return cx; + return sJSContextStack->GetSafeJSContext(); } /* static */ bool nsScriptSecurityManager::SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI) { return NS_SecurityCompareURIs(aSourceURI, aTargetURI, sStrictFileOriginPolicy);
--- a/chrome/src/nsChromeProtocolHandler.cpp +++ b/chrome/src/nsChromeProtocolHandler.cpp @@ -209,16 +209,19 @@ nsChromeProtocolHandler::NewChannel(nsIU file->GetNativePath(path); printf("Chrome file doesn't exist: %s\n", path.get()); } } #endif // Make sure that the channel remembers where it was // originally loaded from. + nsLoadFlags loadFlags = 0; + result->GetLoadFlags(&loadFlags); + result->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE); rv = result->SetOriginalURI(aURI); if (NS_FAILED(rv)) return rv; // Get a system principal for content files and set the owner // property of the result nsCOMPtr<nsIURL> url = do_QueryInterface(aURI); nsCAutoString path; rv = url->GetPath(path);
--- a/client.mk +++ b/client.mk @@ -166,17 +166,17 @@ MOZ_MAKE = $(MAKE) $(MOZ_MAKE_FLAGS) -C endif # MOZ_BUILD_PROJECTS # 'configure' scripts generated by autoconf. CONFIGURES := $(TOPSRCDIR)/configure CONFIGURES += $(TOPSRCDIR)/js/src/configure # Make targets that are going to be passed to the real build system -OBJDIR_TARGETS = install export libs clean realclean distclean alldep maybe_clobber_profiledbuild upload sdk installer package package-compare stage-package source-package l10n-check +OBJDIR_TARGETS = install export libs clean realclean distclean alldep maybe_clobber_profiledbuild upload sdk installer package fast-package package-compare stage-package source-package l10n-check ####################################################################### # Rules # The default rule is build build:: $(MAKE) -f $(TOPSRCDIR)/client.mk $(if $(MOZ_PGO),profiledbuild,realbuild) @@ -194,17 +194,17 @@ all realbuild clean depend distclean exp # Windows equivalents build_all: build build_all_dep: alldep build_all_depend: alldep clobber clobber_all: clean # helper target for mobile -build_and_deploy: build package install +build_and_deploy: build fast-package install # Do everything from scratch everything: clean build #################################### # Profile-Guided Optimization # To use this, you should set the following variables in your mozconfig # mk_add_options PROFILE_GEN_SCRIPT=/path/to/profile-script
--- a/config/Preprocessor.py +++ b/config/Preprocessor.py @@ -164,17 +164,17 @@ class Preprocessor: """ p = self.getCommandLineParser() (options, args) = p.parse_args(args=args) includes = options.I if defaultToStdin and len(args) == 0: args = [sys.stdin] includes.extend(args) for f in includes: - self.do_include(f) + self.do_include(f, False) pass def getCommandLineParser(self, unescapeDefines = False): escapedValue = re.compile('".*"$') numberValue = re.compile('\d+$') def handleE(option, opt, value, parser): for k,v in os.environ.iteritems(): self.context[k] = v @@ -409,33 +409,36 @@ class Preprocessor: return str(self.context[varname]) if fatal: raise Preprocessor.Error(self, 'UNDEFINED_VAR', varname) return '' return self.varsubst.sub(repl, aLine) def filter_attemptSubstitution(self, aLine): return self.filter_substitution(aLine, fatal=False) # File ops - def do_include(self, args): + def do_include(self, args, filters=True): """ Preprocess a given file. args can either be a file name, or a file-like object. Files should be opened, and will be closed after processing. """ isName = type(args) == str or type(args) == unicode oldWrittenLines = self.writtenLines oldCheckLineNumbers = self.checkLineNumbers self.checkLineNumbers = False if isName: try: args = str(args) - args = self.applyFilters(args) + if filters: + args = self.applyFilters(args) if not os.path.isabs(args): args = os.path.join(self.context['DIRECTORY'], args) args = open(args, 'rU') + except Preprocessor.Error: + raise except: raise Preprocessor.Error(self, 'FILE_NOT_FOUND', str(args)) self.checkLineNumbers = bool(re.search('\.(js|java)(?:\.in)?$', args.name)) oldFile = self.context['FILE'] oldLine = self.context['LINE'] oldDir = self.context['DIRECTORY'] if args.isatty(): # we're stdin, use '-' and '' for file and dir @@ -471,12 +474,12 @@ def preprocess(includes=[sys.stdin], def output = sys.stdout, line_endings='\n', marker='#'): pp = Preprocessor() pp.context.update(defines) pp.setLineEndings(line_endings) pp.setMarker(marker) pp.out = output for f in includes: - pp.do_include(f) + pp.do_include(f, False) if __name__ == "__main__": main()
--- a/config/tests/unit-Preprocessor.py +++ b/config/tests/unit-Preprocessor.py @@ -1,23 +1,51 @@ +from __future__ import with_statement import unittest from StringIO import StringIO import os import sys import os.path sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from Preprocessor import Preprocessor class NamedIO(StringIO): def __init__(self, name, content): self.name = name StringIO.__init__(self, content) +class MockedOpen(object): + """ + Context manager diverting the open builtin such that opening files + can open NamedIO instances given when creating a MockedOpen. + + with MockedOpen(NamedIO('foo', 'foo'), NamedIO('bar', 'bar')): + f = open('foo', 'r') + + will thus assign the NamedIO instance for the file 'foo' to f. + """ + def __init__(self, *files): + self.files = {} + for f in files: + self.files[os.path.abspath(f.name)] = f + def __call__(self, name, args): + absname = os.path.abspath(name) + if absname in self.files: + return self.files[absname] + return self.open(name, args) + def __enter__(self): + import __builtin__ + self.open = __builtin__.open + __builtin__.open = self + def __exit__(self, type, value, traceback): + import __builtin__ + __builtin__.open = self.open + class TestPreprocessor(unittest.TestCase): """ Unit tests for the Context class """ def setUp(self): self.pp = Preprocessor() self.pp.out = StringIO() @@ -494,10 +522,74 @@ octal value is equal #else octal value is not equal #endif """) self.pp.handleCommandLine(['-DFOO="0100"']) self.pp.do_include(f) self.assertEqual(self.pp.out.getvalue(), "octal value is not equal\n") + def test_undefined_variable(self): + f = NamedIO("undefined_variable.in", """#filter substitution +@foo@ +""") + try: + self.pp.do_include(f) + except Preprocessor.Error, exception: + self.assertEqual(exception.key, 'UNDEFINED_VAR') + else: + self.fail("Expected a Preprocessor.Error") + + def test_include(self): + with MockedOpen(NamedIO("foo/test", """#define foo foobarbaz +#include @inc@ +@bar@ +"""), + NamedIO("bar", """#define bar barfoobaz +@foo@ +""")): + f = NamedIO("include.in", """#filter substitution +#define inc ../bar +#include foo/test""") + self.pp.do_include(f) + self.assertEqual(self.pp.out.getvalue(), """foobarbaz +barfoobaz +""") + + def test_include_missing_file(self): + f = NamedIO("include_missing_file.in", "#include foo") + try: + self.pp.do_include(f) + except Preprocessor.Error, exception: + self.assertEqual(exception.key, 'FILE_NOT_FOUND') + else: + self.fail("Expected a Preprocessor.Error") + + def test_include_undefined_variable(self): + f = NamedIO("include_undefined_variable.in", """#filter substitution +#include @foo@ +""") + try: + self.pp.do_include(f) + except Preprocessor.Error, exception: + self.assertEqual(exception.key, 'UNDEFINED_VAR') + else: + self.fail("Expected a Preprocessor.Error") + + def test_include_literal_at(self): + with MockedOpen(NamedIO("@foo@", "#define foo foobarbaz")): + f = NamedIO("include_literal_at.in", """#include @foo@ +#filter substitution +@foo@ +""") + self.pp.do_include(f) + self.assertEqual(self.pp.out.getvalue(), """foobarbaz +""") + + def test_command_line_literal_at(self): + with MockedOpen(NamedIO("@foo@.in", """@foo@ +""")): + self.pp.handleCommandLine(['-Fsubstitution', '-Dfoo=foobarbaz', '@foo@.in']) + self.assertEqual(self.pp.out.getvalue(), """foobarbaz +""") + if __name__ == '__main__': unittest.main()
--- a/configure.in +++ b/configure.in @@ -286,17 +286,17 @@ if test -n "$gonkdir" ; then LD="$gonk_toolchain_prefix"ld AR="$gonk_toolchain_prefix"ar RANLIB="$gonk_toolchain_prefix"ranlib STRIP="$gonk_toolchain_prefix"strip STLPORT_CPPFLAGS="-I$gonkdir/ndk/sources/cxx-stl/stlport/stlport/" STLPORT_LIBS="-lstlport" - CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/arch-arm/include -isystem $gonkdir/bionic/libc/kernel/arch-arm -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice" + CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/arch-arm/include -isystem $gonkdir/bionic/libc/kernel/arch-arm -isystem $gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system/core/include -isystem $gonkdir/bionic -I$gonkdir/frameworks/base/include -I$gonkdir/external/dbus $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice" CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS" CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions $CXXFLAGS $STLPORT_CPPFLAGS" LIBS="$LIBS $STLPORT_LIBS" dnl Add -llog by default, since we use it all over the place. LDFLAGS="-mandroid -L$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib -Wl,-rpath-link=$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib --sysroot=$gonkdir/out/target/product/$GONK_PRODUCT/obj/ -llog $LDFLAGS" dnl prevent cross compile section from using these flags as host flags @@ -1719,16 +1719,29 @@ if test "$GNU_CC"; then # Don't allow undefined symbols in libraries DSO_LDOPTS="$DSO_LDOPTS -Wl,-z,defs" fi fi WARNINGS_AS_ERRORS='-Werror -Wno-error=uninitialized' DSO_CFLAGS='' DSO_PIC_CFLAGS='-fPIC' ASFLAGS="$ASFLAGS -fPIC" + AC_MSG_CHECKING([for --noexecstack option to as]) + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -Wa,--noexecstack" + AC_TRY_COMPILE(,,AC_MSG_RESULT([yes]) + [ASFLAGS="$ASFLAGS -Wa,--noexecstack"], + AC_MSG_RESULT([no])) + CFLAGS=$_SAVE_CFLAGS + AC_MSG_CHECKING([for -z noexecstack option to ld]) + _SAVE_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-z,noexecstack" + AC_TRY_LINK(,,AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no]) + LDFLAGS=$_SAVE_LDFLAGS) _MOZ_RTTI_FLAGS_ON=-frtti _MOZ_RTTI_FLAGS_OFF=-fno-rtti # Turn on GNU-specific warnings: # -Wall - turn on a lot of warnings # -pedantic - this is turned on below # -Wpointer-arith - enabled with -pedantic, but good to have even if not # -Wdeclaration-after-statement - MSVC doesn't like these @@ -1921,16 +1934,21 @@ AC_SUBST(MOZ_OS2_HIGH_MEMORY) dnl ======================================================== dnl = Use profiling compile flags dnl ======================================================== MOZ_ARG_ENABLE_BOOL(profiling, [ --enable-profiling Set compile flags necessary for using sampling profilers (e.g. shark, perf)], MOZ_PROFILING=1, MOZ_PROFILING= ) +# For profiling builds keep the symbol information +if test "$MOZ_PROFILING" -a -z "$STRIP_FLAGS"; then + STRIP_FLAGS="--strip-debug" +fi + dnl ======================================================== dnl = Use Valgrind dnl ======================================================== MOZ_ARG_ENABLE_BOOL(valgrind, [ --enable-valgrind Enable Valgrind integration hooks (default=no)], MOZ_VALGRIND=1, MOZ_VALGRIND= ) if test -n "$MOZ_VALGRIND"; then @@ -3576,25 +3594,25 @@ AC_FUNC_MEMCMP AC_CHECK_FUNCS(random strerror lchown fchmod snprintf statvfs memmove rint stat64 lstat64 truncate64 statvfs64 setbuf isatty) AC_CHECK_FUNCS(flockfile getpagesize) AC_CHECK_FUNCS(localtime_r strtok_r) dnl check for clock_gettime(), the CLOCK_MONOTONIC clock AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC), ac_cv_clock_monotonic, [for libs in "" -lrt; do - _SAVE_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $libs" + _SAVE_LIBS="$LIBS" + LIBS="$LIBS $libs" AC_TRY_LINK([#include <time.h>], [ struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); ], ac_cv_clock_monotonic=$libs break, ac_cv_clock_monotonic=no) - LDFLAGS="$_SAVE_LDFLAGS" + LIBS="$_SAVE_LIBS" done]) if test "$ac_cv_clock_monotonic" != "no"; then HAVE_CLOCK_MONOTONIC=1 REALTIME_LIBS=$ac_cv_clock_monotonic AC_DEFINE(HAVE_CLOCK_MONOTONIC) AC_SUBST(HAVE_CLOCK_MONOTONIC) AC_SUBST(REALTIME_LIBS) fi @@ -5966,20 +5984,16 @@ esac if test -n "$MOZ_ANGLE"; then MOZ_ARG_DISABLE_BOOL(angle, [ --disable-angle Disable building of ANGLE for WebGL->D3D translation], MOZ_ANGLE=, MOZ_ANGLE=1) if test -n "$MOZ_ANGLE"; then - if test -z "$_WIN32_MSVC"; then - AC_MSG_ERROR([Building ANGLE requires MSVC. To build without ANGLE, reconfigure with --disable-angle.]) - fi - # Get the SDK path from the registry. # First try to get the June 2010 SDK MOZ_DIRECTX_SDK_REG_KEY=`reg query 'HKLM\Software\Microsoft\DirectX' //s | grep 'Microsoft DirectX SDK (June 2010)' | head -n 1` if test -z "$MOZ_DIRECTX_SDK_REG_KEY" ; then # Otherwise just take whatever comes first MOZ_DIRECTX_SDK_REG_KEY=`reg query 'HKLM\Software\Microsoft\DirectX' //s | grep 'Microsoft DirectX SDK' | head -n 1` fi @@ -7433,16 +7447,23 @@ dnl = --disable-elf-hack dnl ======================================================== USE_ELF_HACK=1 MOZ_ARG_DISABLE_BOOL(elf-hack, [ --disable-elf-hack Disable elf hacks], USE_ELF_HACK=, USE_ELF_HACK=1) +# Disable elf hack for profiling because the built in profiler +# doesn't read the segments properly with elf hack. This is +# temporary and should be fixed soon in the profiler. +if test "$MOZ_PROFILING" = 1; then + USE_ELF_HACK= +fi + # Only enable elfhack where supported if test "$USE_ELF_HACK" = 1; then case "${HOST_OS_ARCH},${OS_ARCH}" in Linux,Linux) case "${CPU_ARCH}" in arm | x86 | x86_64) USE_ELF_HACK=1 ;;
--- a/content/base/public/nsIContent.h +++ b/content/base/public/nsIContent.h @@ -868,17 +868,17 @@ public: */ bool HasIndependentSelection(); /** * If the content is a part of HTML editor, this returns editing * host content. When the content is in designMode, this returns its body * element. Also, when the content isn't editable, this returns null. */ - nsIContent* GetEditingHost(); + mozilla::dom::Element* GetEditingHost(); /** * Determing language. Look at the nearest ancestor element that has a lang * attribute in the XML namespace or is an HTML/SVG element and has a lang in * no namespace attribute. */ void GetLang(nsAString& aResult) const { for (const nsIContent* content = this; content; content = content->GetParent()) {
--- a/content/base/public/nsLineBreaker.h +++ b/content/base/public/nsLineBreaker.h @@ -196,16 +196,22 @@ public: * This must be called at least once between any call to AppendText() and * destroying the object. * @param aTrailingBreak this is set to true when there is a break opportunity * at the end of the text. This will normally only be declared true when there * is breakable whitespace at the end. */ nsresult Reset(bool* aTrailingBreak); + /* + * Set word-break mode for linebreaker. This is set by word-break property. + * @param aMode is nsILineBreaker::kWordBreak_* value. + */ + void SetWordBreak(PRUint8 aMode) { mWordBreak = aMode; } + private: // This is a list of text sources that make up the "current word" (i.e., // run of text which does not contain any whitespace). All the mLengths // are are nonzero, these cannot overlap. struct TextItem { TextItem(nsILineBreakSink* aSink, PRUint32 aSinkOffset, PRUint32 aLength, PRUint32 aFlags) : mSink(aSink), mSinkOffset(aSinkOffset), mLength(aLength), mFlags(aFlags) {} @@ -238,11 +244,13 @@ private: bool mCurrentWordContainsMixedLang; bool mCurrentWordContainsComplexChar; // True if the previous character was breakable whitespace bool mAfterBreakableSpace; // True if a break must be allowed at the current position because // a run of breakable whitespace ends here bool mBreakHere; + // line break mode by "word-break" style + PRUint8 mWordBreak; }; #endif /*NSLINEBREAKER_H_*/
--- a/content/base/src/nsContentAreaDragDrop.cpp +++ b/content/base/src/nsContentAreaDragDrop.cpp @@ -80,16 +80,17 @@ #include "nsIDocShellTreeItem.h" #include "nsIWebBrowserPersist.h" #include "nsEscape.h" #include "nsContentUtils.h" #include "nsIMIMEService.h" #include "imgIContainer.h" #include "imgIRequest.h" #include "nsDOMDataTransfer.h" +#include "mozilla/dom/Element.h" class NS_STACK_CLASS DragDataProducer { public: DragDataProducer(nsIDOMWindow* aWindow, nsIContent* aTarget, nsIContent* aSelectionTargetNode, bool aIsAltKeyPressed);
--- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -1670,18 +1670,17 @@ nsContentUtils::GetContextFromDocument(n //static void nsContentUtils::TraceSafeJSContext(JSTracer* aTrc) { if (!sThreadJSContextStack) { return; } - JSContext* cx = nsnull; - sThreadJSContextStack->GetSafeJSContext(&cx); + JSContext* cx = sThreadJSContextStack->GetSafeJSContext(); if (!cx) { return; } if (JSObject* global = JS_GetGlobalObject(cx)) { JS_CALL_OBJECT_TRACER(aTrc, global, "safe context"); } }
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -3858,17 +3858,17 @@ nsDocument::SetScriptGlobalObject(nsIScr JSObject *obj = GetWrapperPreserveColor(); if (obj) { JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject(); nsIScriptContext *scx = aScriptGlobalObject->GetContext(); JSContext *cx = scx ? scx->GetNativeContext() : nsnull; if (!cx) { nsContentUtils::ThreadJSContextStack()->Peek(&cx); if (!cx) { - nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx); + cx = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(); NS_ASSERTION(cx, "Uhoh, no context, this is bad!"); } } if (cx) { NS_ASSERTION(JS_GetGlobalForObject(cx, obj) == newScope, "Wrong scope, this is really bad!"); } } @@ -6067,17 +6067,17 @@ GetContextAndScope(nsIDocument* aOldDocu // No context reachable from the old or new document, use the // calling context, or the safe context if no caller can be // found. nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack(); stack->Peek(&cx); if (!cx) { - stack->GetSafeJSContext(&cx); + cx = stack->GetSafeJSContext(); if (!cx) { // No safe context reachable, bail. NS_WARNING("No context reachable in GetContextAndScopes()!"); return NS_ERROR_NOT_AVAILABLE; } }
--- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -374,17 +374,17 @@ nsFrameMessageManager::ReceiveMessage(ns const nsAString& aMessage, bool aSync, const nsAString& aJSON, JSObject* aObjectsArray, InfallibleTArray<nsString>* aJSONRetVal, JSContext* aContext) { JSContext* ctx = mContext ? mContext : aContext; if (!ctx) { - nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&ctx); + ctx = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(); } if (mListeners.Length()) { nsCOMPtr<nsIAtom> name = do_GetAtom(aMessage); MMListenerRemover lr(this); for (PRUint32 i = 0; i < mListeners.Length(); ++i) { if (mListeners[i].mMessage == name) { nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = @@ -718,18 +718,17 @@ CachedScriptUnrooter(const nsAString& aK return PL_DHASH_REMOVE; } // static void nsFrameScriptExecutor::Shutdown() { if (sCachedScripts) { - JSContext* cx = nsnull; - nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx); + JSContext* cx = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(); if (cx) { #ifdef DEBUG_smaug printf("Will clear cached frame manager scripts!\n"); #endif JSAutoRequest ar(cx); NS_ASSERTION(sCachedScripts != nsnull, "Need cached scripts"); sCachedScripts->Enumerate(CachedScriptUnrooter, cx); } else {
--- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -1547,36 +1547,36 @@ nsIContent::GetDesiredIMEState() bool nsIContent::HasIndependentSelection() { nsIFrame* frame = GetPrimaryFrame(); return (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION); } -nsIContent* +dom::Element* nsIContent::GetEditingHost() { // If this isn't editable, return NULL. NS_ENSURE_TRUE(IsEditableInternal(), nsnull); nsIDocument* doc = GetCurrentDoc(); NS_ENSURE_TRUE(doc, nsnull); // If this is in designMode, we should return <body> if (doc->HasFlag(NODE_IS_EDITABLE)) { return doc->GetBodyElement(); } nsIContent* content = this; - for (nsIContent* parent = GetParent(); + for (dom::Element* parent = GetElementParent(); parent && parent->HasFlag(NODE_IS_EDITABLE); - parent = content->GetParent()) { + parent = content->GetElementParent()) { content = parent; } - return content; + return content->AsElement(); } nsresult nsIContent::LookupNamespaceURIInternal(const nsAString& aNamespacePrefix, nsAString& aNamespaceURI) const { if (aNamespacePrefix.EqualsLiteral("xml")) { // Special-case for xml prefix
--- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -66,16 +66,17 @@ GK_ATOM(moz, "_moz") GK_ATOM(mozallowfullscreen, "mozallowfullscreen") GK_ATOM(moztype, "_moz-type") GK_ATOM(mozdirty, "_moz_dirty") GK_ATOM(mozdonotsend, "moz-do-not-send") GK_ATOM(mozeditorbogusnode, "_moz_editor_bogus_node") GK_ATOM(mozgeneratedcontentbefore, "_moz_generated_content_before") GK_ATOM(mozgeneratedcontentafter, "_moz_generated_content_after") GK_ATOM(mozgeneratedcontentimage, "_moz_generated_content_image") +GK_ATOM(mozquote, "_moz_quote") GK_ATOM(_moz_original_size, "_moz_original_size") GK_ATOM(_moz_target, "_moz_target") GK_ATOM(_moz_type, "_moz-type") GK_ATOM(menuactive, "_moz-menuactive") GK_ATOM(_poundDefault, "#default") GK_ATOM(_asterix, "*") GK_ATOM(a, "a") GK_ATOM(abbr, "abbr")
--- a/content/base/src/nsLineBreaker.cpp +++ b/content/base/src/nsLineBreaker.cpp @@ -42,17 +42,18 @@ #include "gfxFont.h" // for the gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_* values #include "nsHyphenationManager.h" #include "nsHyphenator.h" nsLineBreaker::nsLineBreaker() : mCurrentWordLangGroup(nsnull), mCurrentWordContainsMixedLang(false), mCurrentWordContainsComplexChar(false), - mAfterBreakableSpace(false), mBreakHere(false) + mAfterBreakableSpace(false), mBreakHere(false), + mWordBreak(nsILineBreaker::kWordBreak_Normal) { } nsLineBreaker::~nsLineBreaker() { NS_ASSERTION(mCurrentWord.Length() == 0, "Should have Reset() before destruction!"); } @@ -91,23 +92,27 @@ nsLineBreaker::FlushCurrentWord() PRUint32 length = mCurrentWord.Length(); nsAutoTArray<PRUint8,4000> breakState; if (!breakState.AppendElements(length)) return NS_ERROR_OUT_OF_MEMORY; nsTArray<bool> capitalizationState; if (!mCurrentWordContainsComplexChar) { - // Just set everything internal to "no break"! + // For break-strict set everything internal to "break", otherwise + // to "no break"! memset(breakState.Elements(), - gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE, + mWordBreak == nsILineBreaker::kWordBreak_BreakAll ? + gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL : + gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE, length*sizeof(PRUint8)); } else { nsContentUtils::LineBreaker()-> - GetJISx4051Breaks(mCurrentWord.Elements(), length, breakState.Elements()); + GetJISx4051Breaks(mCurrentWord.Elements(), length, mWordBreak, + breakState.Elements()); } bool autoHyphenate = mCurrentWordLangGroup && !mCurrentWordContainsMixedLang; PRUint32 i; for (i = 0; autoHyphenate && i < mTextItems.Length(); ++i) { TextItem* ti = &mTextItems[i]; if (!(ti->mFlags & BREAK_USE_AUTO_HYPHENATION)) { @@ -245,32 +250,34 @@ nsLineBreaker::AppendText(nsIAtom* aLang for (;;) { PRUnichar ch = aText[offset]; bool isSpace = IsSpace(ch); bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE); if (aSink) { breakState[offset] = - mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ? + mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) || + (mWordBreak == nsILineBreaker::kWordBreak_BreakAll) ? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL : gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE; } mBreakHere = false; mAfterBreakableSpace = isBreakableSpace; if (isSpace) { if (offset > wordStart && aSink) { if (!(aFlags & BREAK_SUPPRESS_INSIDE)) { if (wordHasComplexChar) { // Save current start-of-word state because GetJISx4051Breaks will // set it to false PRUint8 currentStart = breakState[wordStart]; nsContentUtils::LineBreaker()-> GetJISx4051Breaks(aText + wordStart, offset - wordStart, + mWordBreak, breakState.Elements() + wordStart); breakState[wordStart] = currentStart; } if (hyphenator) { FindHyphenationPoints(hyphenator, aText + wordStart, aText + offset, breakState.Elements() + wordStart); } @@ -406,32 +413,36 @@ nsLineBreaker::AppendText(nsIAtom* aLang bool wordHasComplexChar = false; for (;;) { PRUint8 ch = aText[offset]; bool isSpace = IsSpace(ch); bool isBreakableSpace = isSpace && !(aFlags & BREAK_SUPPRESS_INSIDE); if (aSink) { + // Consider word-break style. Since the break position of CJK scripts + // will be set by nsILineBreaker, we don't consider CJK at this point. breakState[offset] = - mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) ? + mBreakHere || (mAfterBreakableSpace && !isBreakableSpace) || + (mWordBreak == nsILineBreaker::kWordBreak_BreakAll) ? gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NORMAL : gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_NONE; } mBreakHere = false; mAfterBreakableSpace = isBreakableSpace; if (isSpace) { if (offset > wordStart && wordHasComplexChar) { if (aSink && !(aFlags & BREAK_SUPPRESS_INSIDE)) { // Save current start-of-word state because GetJISx4051Breaks will // set it to false PRUint8 currentStart = breakState[wordStart]; nsContentUtils::LineBreaker()-> GetJISx4051Breaks(aText + wordStart, offset - wordStart, + mWordBreak, breakState.Elements() + wordStart); breakState[wordStart] = currentStart; } wordHasComplexChar = false; } ++offset; if (offset >= aLength)
--- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -519,17 +519,17 @@ nsresult nsObjectLoadingContent::IsPlugi MOZ_ASSERT(thisContent); nsIDocument* ownerDoc = thisContent->OwnerDoc(); nsCOMPtr<nsIDOMWindow> window = ownerDoc->GetWindow(); if (!window) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIDOMWindow> topWindow; - window->GetTop(getter_AddRefs(topWindow)); + rv = window->GetTop(getter_AddRefs(topWindow)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMDocument> topDocument; rv = topWindow->GetDocument(getter_AddRefs(topDocument)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDocument> topDoc = do_QueryInterface(topDocument); nsIURI* topUri = topDoc->GetDocumentURI(); nsCOMPtr<nsIPermissionManager> permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);