Merge mozilla-central into services-central

This commit is contained in:
Gregory Szorc 2012-07-08 20:48:04 -07:00
Родитель ef75a478a9 f5007f0194
Коммит 2df88561d9
1193 изменённых файлов: 36104 добавлений и 17662 удалений

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

@ -32,6 +32,10 @@ SHARED_LIBRARY_LIBS = \
../src/xforms/$(LIB_PREFIX)accessibility_xforms_s.$(LIB_SUFFIX) \
$(NULL)
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
SHARED_LIBRARY_LIBS += ../src/windows/uia/$(LIB_PREFIX)accessibility_toolkit_uia_s.$(LIB_SUFFIX)
endif
ifdef MOZ_XUL
SHARED_LIBRARY_LIBS += ../src/xul/$(LIB_PREFIX)accessibility_xul_s.$(LIB_SUFFIX)
endif

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

@ -62,8 +62,8 @@ interface nsIAccessibleProvider : nsISupports
const long XULTab = 0x00001017;
/** Used for XUL tabs element, a container for tab elements */
const long XULTabs = 0x00001018;
/** Used for XUL tabpanels container element */
const long XULTabpanels = 0x00001019;
/** Used for XUL deck frame */
const long XULDeck = 0x00001019;
const long XULText = 0x0000101A;
const long XULTextBox = 0x0000101B;

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

@ -14,7 +14,10 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
PLATFORM_DIR = atk
else
ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
PLATFORM_DIR = msaa
PLATFORM_DIR = \
msaa \
windows \
$(null)
else
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
PLATFORM_DIR += mac

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

@ -1153,11 +1153,14 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
}
if (!newAcc) {
// Create generic accessibles for SVG and MathML nodes.
if (content->IsSVG(nsGkAtoms::svg)) {
// xul:deck does not have XBL and nsIFrame::CreateAccessible() is only called
// on HTML elements
nsIAtom* tag = content->Tag();
if ((tag == nsGkAtoms::deck) || (tag == nsGkAtoms::tabpanels)) {
newAcc = new XULDeckAccessible(content, docAcc);
} else if (content->IsSVG(nsGkAtoms::svg)) {
newAcc = new EnumRoleAccessible(content, docAcc, roles::DIAGRAM);
}
else if (content->IsMathML(nsGkAtoms::math)) {
} else if (content->IsMathML(nsGkAtoms::math)) {
newAcc = new EnumRoleAccessible(content, docAcc, roles::EQUATION);
}
}
@ -1326,6 +1329,10 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
accessible = new XULComboboxAccessible(aContent, aDoc);
break;
case nsIAccessibleProvider::XULDeck:
accessible = new XULDeckAccessible(aContent, aDoc);
break;
case nsIAccessibleProvider::XULDropmarker:
accessible = new XULDropmarkerAccessible(aContent, aDoc);
break;
@ -1430,10 +1437,6 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
accessible = new XULTabsAccessible(aContent, aDoc);
break;
case nsIAccessibleProvider::XULTabpanels:
accessible = new XULTabpanelsAccessible(aContent, aDoc);
break;
case nsIAccessibleProvider::XULText:
accessible = new XULLabelAccessible(aContent, aDoc);
break;

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

@ -508,6 +508,8 @@ public:
inline bool IsXULTree() const { return mFlags & eXULTreeAccessible; }
mozilla::a11y::XULTreeAccessible* AsXULTree();
inline bool IsXULDeck() const { return mFlags & eXULDeckAccessible; }
inline bool IsListControl() const { return mFlags & eListControlAccessible; }
inline bool IsMenuButton() const { return mFlags & eMenuButtonAccessible; }
@ -766,7 +768,8 @@ protected:
eMenuPopupAccessible = 1 << 16,
eRootAccessible = 1 << 17,
eTextLeafAccessible = 1 << 18,
eXULTreeAccessible = 1 << 19
eXULDeckAccessible = 1 << 19,
eXULTreeAccessible = 1 << 20
};
//////////////////////////////////////////////////////////////////////////////

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

@ -59,6 +59,9 @@ AccessibleWrap::GetNativeType ()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
if (IsXULDeck())
return [mozPaneAccessible class];
roles::Role role = Role();
switch (role) {
case roles::PUSHBUTTON:
@ -81,15 +84,17 @@ AccessibleWrap::GetNativeType ()
case roles::PAGETABLIST:
return [mozTabsAccessible class];
case roles::ENTRY:
case roles::STATICTEXT:
case roles::CAPTION:
case roles::ACCEL_LABEL:
case roles::TEXT_LEAF:
case roles::PASSWORD_TEXT:
// normal textfield (static or editable)
return [mozTextAccessible class];
return [mozTextAccessible class];
case roles::TEXT_LEAF:
return [mozTextLeafAccessible class];
case roles::LINK:
return [mozLinkAccessible class];

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

@ -14,8 +14,6 @@ LIBRARY_NAME = accessibility_toolkit_s
EXPORT_LIBRARY = ..
LIBXUL_LIBRARY = 1
CMMSRCS = \
AccessibleWrap.mm \
ApplicationAccessibleWrap.mm \
@ -48,5 +46,7 @@ LOCAL_INCLUDES += \
-I$(srcdir)/../xul \
-I$(topsrcdir)/widget/cocoa \
-I$(topsrcdir)/widget/xpwidgets \
-I$(topsrcdir)/layout/xul/base/src \
-I$(topsrcdir)/layout/generic \
$(NULL)

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

@ -23,6 +23,14 @@ GetObjectOrRepresentedView(id <mozAccessible> aObject)
return [aObject hasRepresentedView] ? [aObject representedView] : aObject;
}
inline mozAccessible*
GetNativeFromGeckoAccessible(nsIAccessible* aAccessible)
{
mozAccessible* native = nil;
aAccessible->GetNativeInterface((void**)&native);
return native;
}
@interface mozAccessible : NSObject <mozAccessible>
{
/**
@ -39,15 +47,7 @@ GetObjectOrRepresentedView(id <mozAccessible> aObject)
* Weak reference to the parent
*/
mozAccessible* mParent;
/**
* We can be marked as 'expired' if Shutdown() is called on our geckoAccessible.
* since we might still be retained by some third-party, we need to do cleanup
* in |expire|, and prevent any potential harm that could come from someone using us
* after this point.
*/
BOOL mIsExpired;
/**
* The nsIAccessible role of our gecko accessible.
*/

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

@ -9,6 +9,7 @@
#import "mozView.h"
#include "Accessible-inl.h"
#include "nsAccUtils.h"
#include "nsIAccessibleRelation.h"
#include "nsIAccessibleText.h"
#include "nsIAccessibleEditableText.h"
@ -21,6 +22,7 @@
#include "nsCocoaUtils.h"
#include "nsCoord.h"
#include "nsObjCExceptions.h"
#include "nsWhitespaceTokenizer.h"
using namespace mozilla;
using namespace mozilla::a11y;
@ -63,18 +65,6 @@ GetClosestInterestingAccessible(id anObject)
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
static inline mozAccessible*
GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL;
mozAccessible *native = nil;
anAccessible->GetNativeInterface ((void**)&native);
return native;
NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL;
}
#pragma mark -
@implementation mozAccessible
@ -85,7 +75,6 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
if ((self = [super init])) {
mGeckoAccessible = geckoAccessible;
mIsExpired = NO;
mRole = geckoAccessible->Role();
}
@ -112,7 +101,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
// unknown (either unimplemented, or irrelevant) elements are marked as ignored
// as well as expired elements.
return mIsExpired || [[self role] isEqualToString:NSAccessibilityUnknownRole];
return !mGeckoAccessible || [[self role] isEqualToString:NSAccessibilityUnknownRole];
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
}
@ -122,7 +111,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
// if we're expired, we don't support any attributes.
if (mIsExpired)
if (!mGeckoAccessible)
return [NSArray array];
static NSArray *generalAttributes = nil;
@ -160,7 +149,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
if (mIsExpired)
if (!mGeckoAccessible)
return nil;
#if DEBUG
@ -246,7 +235,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
- (id)accessibilityHitTest:(NSPoint)point
{
if (mIsExpired)
if (!mGeckoAccessible)
return nil;
// Convert from cocoa's coordinate system to gecko's. According to the docs
@ -288,7 +277,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
- (id)accessibilityFocusedUIElement
{
if (mIsExpired)
if (!mGeckoAccessible)
return nil;
Accessible* focusedGeckoChild = mGeckoAccessible->FocusedChild();
@ -420,7 +409,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
- (NSString*)role
{
if (mIsExpired)
if (!mGeckoAccessible)
return nil;
#ifdef DEBUG
@ -444,6 +433,42 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
- (NSString*)subrole
{
if (!mGeckoAccessible)
return nil;
// XXX maybe we should cache the subrole.
nsAutoString xmlRoles;
nsCOMPtr<nsIPersistentProperties> attributes;
// XXX we don't need all the attributes (see bug 771113)
nsresult rv = mGeckoAccessible->GetAttributes(getter_AddRefs(attributes));
if (NS_SUCCEEDED(rv) && attributes)
nsAccUtils::GetAccAttr(attributes, nsGkAtoms::xmlroles, xmlRoles);
nsWhitespaceTokenizer tokenizer(xmlRoles);
while (tokenizer.hasMoreTokens()) {
const nsDependentSubstring token(tokenizer.nextToken());
if (token.EqualsLiteral("banner"))
return @"AXLandmarkBanner";
if (token.EqualsLiteral("complementary"))
return @"AXLandmarkComplementary";
if (token.EqualsLiteral("contentinfo"))
return @"AXLandmarkContentInfo";
if (token.EqualsLiteral("main"))
return @"AXLandmarkMain";
if (token.EqualsLiteral("navigation"))
return @"AXLandmarkNavigation";
if (token.EqualsLiteral("search"))
return @"AXLandmarkSearch";
}
switch (mRole) {
case roles::LIST:
return @"AXContentList"; // 10.6+ NSAccessibilityContentListSubrole;
@ -468,15 +493,33 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
{
if (mRole == roles::DOCUMENT)
return utils::LocalizedString(NS_LITERAL_STRING("htmlContent"));
NSString* subrole = [self subrole];
if ((mRole == roles::LISTITEM) && [subrole isEqualToString:@"AXTerm"])
return utils::LocalizedString(NS_LITERAL_STRING("term"));
if ((mRole == roles::PARAGRAPH) && [subrole isEqualToString:@"AXDefinition"])
return utils::LocalizedString(NS_LITERAL_STRING("definition"));
return NSAccessibilityRoleDescription([self role], subrole);
NSString* role = [self role];
// the WAI-ARIA Landmarks
if ([role isEqualToString:NSAccessibilityGroupRole]) {
if ([subrole isEqualToString:@"AXLandmarkBanner"])
return utils::LocalizedString(NS_LITERAL_STRING("banner"));
if ([subrole isEqualToString:@"AXLandmarkComplementary"])
return utils::LocalizedString(NS_LITERAL_STRING("complementary"));
if ([subrole isEqualToString:@"AXLandmarkContentInfo"])
return utils::LocalizedString(NS_LITERAL_STRING("content"));
if ([subrole isEqualToString:@"AXLandmarkMain"])
return utils::LocalizedString(NS_LITERAL_STRING("main"));
if ([subrole isEqualToString:@"AXLandmarkNavigation"])
return utils::LocalizedString(NS_LITERAL_STRING("navigation"));
if ([subrole isEqualToString:@"AXLandmarkSearch"])
return utils::LocalizedString(NS_LITERAL_STRING("search"));
}
return NSAccessibilityRoleDescription(role, subrole);
}
- (NSString*)title
@ -485,7 +528,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
nsAutoString title;
mGeckoAccessible->Name(title);
return title.IsEmpty() ? nil : [NSString stringWithCharacters:title.BeginReading() length:title.Length()];
return nsCocoaUtils::ToNSString(title);
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
@ -528,7 +571,8 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
nsAutoString desc;
mGeckoAccessible->Description(desc);
return desc.IsEmpty() ? nil : [NSString stringWithCharacters:desc.BeginReading() length:desc.Length()];
return nsCocoaUtils::ToNSString(desc);
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
@ -561,18 +605,21 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
- (BOOL)canBeFocused
{
return mGeckoAccessible->InteractiveState() & states::FOCUSABLE;
return mGeckoAccessible && (mGeckoAccessible->InteractiveState() & states::FOCUSABLE);
}
- (BOOL)focus
{
if (!mGeckoAccessible)
return NO;
nsresult rv = mGeckoAccessible->TakeFocus();
return NS_SUCCEEDED(rv);
}
- (BOOL)isEnabled
{
return (mGeckoAccessible->InteractiveState() & states::UNAVAILABLE) == 0;
return mGeckoAccessible && ((mGeckoAccessible->InteractiveState() & states::UNAVAILABLE) == 0);
}
// The root accessible calls this when the focused node was
@ -637,7 +684,6 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
[self invalidateChildren];
mIsExpired = YES;
mGeckoAccessible = nsnull;
NS_OBJC_END_TRY_ABORT_BLOCK;
@ -645,7 +691,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible)
- (BOOL)isExpired
{
return mIsExpired;
return !mGeckoAccessible;
}
#pragma mark -

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

@ -29,3 +29,10 @@
}
-(id)tabs;
@end
/**
* Accessible for a PANE
*/
@interface mozPaneAccessible : mozAccessible
@end

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

@ -7,8 +7,10 @@
#import "MacUtils.h"
#include "Accessible-inl.h"
#include "DocAccessible.h"
#include "XULTabAccessible.h"
#include "nsDeckFrame.h"
#include "nsObjCExceptions.h"
using namespace mozilla::a11y;
@ -71,7 +73,7 @@ enum CheckboxValue {
- (BOOL)accessibilityIsIgnored
{
return mIsExpired;
return !mGeckoAccessible;
}
- (NSArray*)accessibilityActionNames
@ -333,3 +335,30 @@ enum CheckboxValue {
}
@end
@implementation mozPaneAccessible
- (NSArray*)children
{
if (!mGeckoAccessible)
return nil;
nsDeckFrame* deckFrame = do_QueryFrame(mGeckoAccessible->GetFrame());
nsIFrame* selectedFrame = deckFrame ? deckFrame->GetSelectedBox() : nsnull;
Accessible* selectedAcc = nsnull;
if (selectedFrame) {
nsINode* node = selectedFrame->GetContent();
selectedAcc = mGeckoAccessible->Document()->GetAccessible(node);
}
if (selectedAcc) {
mozAccessible *curNative = GetNativeFromGeckoAccessible(selectedAcc);
if (curNative)
return [NSArray arrayWithObjects:GetObjectOrRepresentedView(curNative), nil];
}
return nil;
}
@end

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

@ -31,7 +31,7 @@ getNativeViewFromRootAccessible(Accessible* aAccessible)
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
// if we're expired, we don't support any attributes.
if (mIsExpired)
if (!mGeckoAccessible)
return [NSArray array];
// standard attributes that are shared and supported by root accessible (AXMain) elements.

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

@ -13,6 +13,17 @@
@implementation mozHeadingAccessible
- (NSString*)title
{
nsAutoString title;
// XXX use the flattening API when there are available
// see bug 768298
nsresult rv = mGeckoAccessible->GetContent()->GetTextContent(title);
NS_ENSURE_SUCCESS(rv, nil);
return nsCocoaUtils::ToNSString(title);
}
- (id)value
{
if (!mGeckoAccessible || !mGeckoAccessible->IsHyperText())
@ -33,7 +44,7 @@
- (NSArray*)accessibilityAttributeNames
{
// if we're expired, we don't support any attributes.
if (mIsExpired)
if (!mGeckoAccessible)
return [NSArray array];
static NSMutableArray* attributes = nil;
@ -57,7 +68,7 @@
- (NSArray*)accessibilityActionNames
{
// if we're expired, we don't support any attributes.
if (mIsExpired)
if (!mGeckoAccessible)
return [NSArray array];
static NSArray* actionNames = nil;

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

@ -14,3 +14,8 @@
nsIAccessibleEditableText *mGeckoEditableTextAccessible; // strong
}
@end
@interface mozTextLeafAccessible : mozAccessible
{
}
@end

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

@ -5,6 +5,7 @@
#include "AccessibleWrap.h"
#include "TextLeafAccessible.h"
#include "nsCocoaUtils.h"
#include "nsObjCExceptions.h"
@ -67,7 +68,7 @@ ToNSString(id aValue)
- (BOOL)accessibilityIsIgnored
{
return mIsExpired;
return !mGeckoAccessible;
}
- (NSArray*)accessibilityAttributeNames
@ -110,13 +111,18 @@ ToNSString(id aValue)
if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute])
return [self selectedText];
if ([attribute isEqualToString:NSAccessibilityTitleAttribute])
return @"";
if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
// Apple's SpeechSynthesisServer expects AXValue to return an AXStaticText
// object's AXSelectedText attribute. See bug 674612 for details.
// Also if there is no selected text, we return the full text.
// See bug 369710 for details.
if ([[self role] isEqualToString:NSAccessibilityStaticTextRole])
return [self selectedText] ? : [self text];
if ([[self role] isEqualToString:NSAccessibilityStaticTextRole]) {
NSString* selectedText = [self selectedText];
return (selectedText && [selectedText length]) ? selectedText : [self text];
}
return [self text];
}
@ -226,7 +232,7 @@ ToNSString(id aValue)
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
if ([attribute isEqualToString:NSAccessibilityValueAttribute])
return [self isReadOnly];
return ![self isReadOnly];
if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute] ||
[attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute] ||
@ -359,7 +365,7 @@ ToNSString(id aValue)
- (NSString*)text
{
if (!mGeckoTextAccessible)
if (!mGeckoAccessible || !mGeckoTextAccessible)
return nil;
// A password text field returns an empty value
@ -378,6 +384,9 @@ ToNSString(id aValue)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
if (!mGeckoAccessible || !mGeckoTextAccessible)
return 0;
return mGeckoTextAccessible ? mGeckoTextAccessible->CharacterCount() : 0;
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
@ -484,3 +493,45 @@ ToNSString(id aValue)
}
@end
@implementation mozTextLeafAccessible
- (NSArray*)accessibilityAttributeNames
{
static NSMutableArray* supportedAttributes = nil;
if (!supportedAttributes) {
supportedAttributes = [[super accessibilityAttributeNames] mutableCopy];
[supportedAttributes removeObject:NSAccessibilityChildrenAttribute];
}
return supportedAttributes;
}
- (id)accessibilityAttributeValue:(NSString*)attribute
{
if ([attribute isEqualToString:NSAccessibilityTitleAttribute])
return @"";
if ([attribute isEqualToString:NSAccessibilityValueAttribute])
return [self text];
return [super accessibilityAttributeValue:attribute];
}
- (NSString*)text
{
if (!mGeckoAccessible)
return nil;
return nsCocoaUtils::ToNSString(mGeckoAccessible->AsTextLeaf()->Text());
}
- (long)textLength
{
if (!mGeckoAccessible)
return 0;
return mGeckoAccessible->AsTextLeaf()->Text().Length();
}
@end

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

@ -8,22 +8,17 @@
#include "Compatibility.h"
#include "DocAccessible-inl.h"
#include "EnumVariant.h"
#include "ia2AccessibleRelation.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "nsIAccessibleEvent.h"
#include "nsIAccessibleRelation.h"
#include "nsWinUtils.h"
#include "Relation.h"
#include "Role.h"
#include "States.h"
#include "ia2AccessibleRelation.h"
#include "nsIAccessibleEvent.h"
#include "nsIAccessibleRelation.h"
#include "Accessible2_i.c"
#include "AccessibleRole.h"
#include "AccessibleStates.h"
#include "RootAccessible.h"
#include "States.h"
#include "uiaRawElmProvider.h"
#ifdef DEBUG
#include "Logging.h"
@ -40,7 +35,11 @@
#include "nsIViewManager.h"
#include "nsEventMap.h"
#include "nsArrayUtils.h"
#include "mozilla/Preferences.h"
#include "Accessible2_i.c"
#include "AccessibleRole.h"
#include "AccessibleStates.h"
#include "OLEACC.H"
using namespace mozilla;
@ -122,6 +121,32 @@ __try {
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
// IServiceProvider
STDMETHODIMP
AccessibleWrap::QueryService(REFGUID aGuidService, REFIID aIID,
void** aInstancePtr)
{
if (!aInstancePtr)
return E_INVALIDARG;
*aInstancePtr = NULL;
// UIA IAccessibleEx
if (aGuidService == IID_IAccessibleEx &&
Preferences::GetBool("accessibility.uia.enable")) {
IAccessibleEx* accEx = new uiaRawElmProvider(this);
HRESULT hr = accEx->QueryInterface(aIID, aInstancePtr);
if (FAILED(hr))
delete accEx;
return hr;
}
return nsAccessNodeWrap::QueryService(aGuidService, aIID, aInstancePtr);
}
//-----------------------------------------------------
// IAccessible methods
//-----------------------------------------------------

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

@ -17,51 +17,104 @@
#include "ia2AccessibleHyperlink.h"
#include "CAccessibleValue.h"
#define DECL_IUNKNOWN_INHERITED \
public: \
STDMETHODIMP QueryInterface(REFIID, void**); \
#define DECL_IUNKNOWN \
public: \
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**); \
virtual ULONG STDMETHODCALLTYPE AddRef() MOZ_FINAL \
{ return ++mRefCnt; } \
virtual ULONG STDMETHODCALLTYPE Release() MOZ_FINAL \
{ \
mRefCnt--; \
if (mRefCnt) \
return mRefCnt; \
\
delete this; \
return 0; \
} \
private: \
ULONG mRefCnt; \
public:
#define IMPL_IUNKNOWN_QUERY_HEAD(Class) \
STDMETHODIMP \
Class::QueryInterface(REFIID iid, void** ppv) \
{ \
HRESULT hr = E_NOINTERFACE; \
*ppv = NULL; \
#define DECL_IUNKNOWN_INHERITED \
public: \
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**); \
#define IMPL_IUNKNOWN_QUERY_TAIL \
return hr; \
} \
#define IMPL_IUNKNOWN_QUERY_HEAD(Class) \
STDMETHODIMP \
Class::QueryInterface(REFIID aIID, void** aInstancePtr) \
{ \
__try { \
if (!aInstancePtr) \
return E_INVALIDARG; \
*aInstancePtr = NULL; \
\
HRESULT hr = E_NOINTERFACE;
#define IMPL_IUNKNOWN_QUERY_ENTRY(Class) \
hr = Class::QueryInterface(iid, ppv); \
if (SUCCEEDED(hr)) \
return hr; \
#define IMPL_IUNKNOWN_QUERY_TAIL \
return hr; \
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), \
GetExceptionInformation())) { } \
return E_NOINTERFACE; \
}
#define IMPL_IUNKNOWN_QUERY_ENTRY_COND(Class, Cond) \
if (Cond) { \
hr = Class::QueryInterface(iid, ppv); \
if (SUCCEEDED(hr)) \
return hr; \
} \
#define IMPL_IUNKNOWN_QUERY_IFACE(Iface) \
if (aIID == IID_##Iface) { \
*aInstancePtr = static_cast<Iface*>(this); \
AddRef(); \
return S_OK; \
}
#define IMPL_IUNKNOWN_INHERITED0(Class, Super) \
IMPL_IUNKNOWN_QUERY_HEAD(Class) \
IMPL_IUNKNOWN_QUERY_ENTRY(Super) \
IMPL_IUNKNOWN_QUERY_TAIL \
#define IMPL_IUNKNOWN_QUERY_IFACE_AMBIGIOUS(Iface, aResolveIface) \
if (aIID == IID_##Iface) { \
*aInstancePtr = static_cast<Iface*>(static_cast<aResolveIface*>(this)); \
AddRef(); \
return S_OK; \
}
#define IMPL_IUNKNOWN_INHERITED1(Class, Super, I1) \
IMPL_IUNKNOWN_QUERY_HEAD(Class) \
IMPL_IUNKNOWN_QUERY_ENTRY(I1); \
IMPL_IUNKNOWN_QUERY_ENTRY(Super) \
IMPL_IUNKNOWN_QUERY_TAIL \
#define IMPL_IUNKNOWN_QUERY_CLASS(Class) \
hr = Class::QueryInterface(aIID, aInstancePtr); \
if (SUCCEEDED(hr)) \
return hr;
#define IMPL_IUNKNOWN_INHERITED2(Class, Super, I1, I2) \
IMPL_IUNKNOWN_QUERY_HEAD(Class) \
IMPL_IUNKNOWN_QUERY_ENTRY(I1); \
IMPL_IUNKNOWN_QUERY_ENTRY(I2); \
IMPL_IUNKNOWN_QUERY_ENTRY(Super) \
IMPL_IUNKNOWN_QUERY_TAIL \
#define IMPL_IUNKNOWN_QUERY_CLASS_COND(Class, Cond) \
if (Cond) { \
hr = Class::QueryInterface(aIID, aInstancePtr); \
if (SUCCEEDED(hr)) \
return hr; \
}
#define IMPL_IUNKNOWN_QUERY_AGGR_COND(Member, Cond) \
if (Cond) { \
hr = Member->QueryInterface(aIID, aInstancePtr); \
if (SUCCEEDED(hr)) \
return hr; \
}
#define IMPL_IUNKNOWN1(Class, I1) \
IMPL_IUNKNOWN_QUERY_HEAD(Class) \
IMPL_IUNKNOWN_QUERY_IFACE(I1); \
IMPL_IUNKNOWN_QUERY_IFACE(IUnknown); \
IMPL_IUNKNOWN_QUERY_TAIL \
#define IMPL_IUNKNOWN2(Class, I1, I2) \
IMPL_IUNKNOWN_QUERY_HEAD(Class) \
IMPL_IUNKNOWN_QUERY_IFACE(I1); \
IMPL_IUNKNOWN_QUERY_IFACE(I2); \
IMPL_IUNKNOWN_QUERY_IFACE_AMBIGIOUS(IUnknown, I1); \
IMPL_IUNKNOWN_QUERY_TAIL \
#define IMPL_IUNKNOWN_INHERITED1(Class, Super0, Super1) \
IMPL_IUNKNOWN_QUERY_HEAD(Class) \
IMPL_IUNKNOWN_QUERY_CLASS(Super1); \
IMPL_IUNKNOWN_QUERY_CLASS(Super0) \
IMPL_IUNKNOWN_QUERY_TAIL \
#define IMPL_IUNKNOWN_INHERITED2(Class, Super0, Super1, Super2) \
IMPL_IUNKNOWN_QUERY_HEAD(Class) \
IMPL_IUNKNOWN_QUERY_CLASS(Super1); \
IMPL_IUNKNOWN_QUERY_CLASS(Super2); \
IMPL_IUNKNOWN_QUERY_CLASS(Super0) \
IMPL_IUNKNOWN_QUERY_TAIL
class AccessibleWrap : public Accessible,
public ia2AccessibleComponent,
@ -83,6 +136,11 @@ public: // construction, destruction
// Return the registered OLE class ID of this object's CfDataObj.
CLSID GetClassID() const;
// IServiceProvider
virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID aGuidService,
REFIID aIID,
void** aInstancePtr);
public: // COM interface IAccessible
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent(
/* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent);

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

@ -13,51 +13,11 @@ using namespace mozilla::a11y;
// ChildrenEnumVariant
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
ChildrenEnumVariant::QueryInterface(REFIID aIID, void** aObject)
{
__try {
if (!aObject)
return E_INVALIDARG;
if (aIID == IID_IEnumVARIANT) {
*aObject = static_cast<IEnumVARIANT*>(this);
AddRef();
return S_OK;
}
if (aIID == IID_IUnknown) {
*aObject = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
// Redirect QI to IAccessible this enum was retrieved for.
if (!mAnchorAcc->IsDefunct())
return mAnchorAcc->QueryInterface(aIID, aObject);
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(),
GetExceptionInformation())) { }
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE
ChildrenEnumVariant::AddRef()
{
return ++mRefCnt;
}
ULONG STDMETHODCALLTYPE
ChildrenEnumVariant::Release()
{
mRefCnt--;
ULONG r = mRefCnt;
if (r == 0)
delete this;
return r;
}
IMPL_IUNKNOWN_QUERY_HEAD(ChildrenEnumVariant)
IMPL_IUNKNOWN_QUERY_IFACE(IEnumVARIANT);
IMPL_IUNKNOWN_QUERY_IFACE(IUnknown);
IMPL_IUNKNOWN_QUERY_AGGR_COND(mAnchorAcc, !mAnchorAcc->IsDefunct());
IMPL_IUNKNOWN_QUERY_TAIL
STDMETHODIMP
ChildrenEnumVariant::Next(ULONG aCount, VARIANT FAR* aItems,

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

@ -22,12 +22,7 @@ public:
mCurAcc(mAnchorAcc->GetChildAt(0)), mCurIndex(0), mRefCnt(0) { }
// IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID aRefIID,
/* [annotation][iid_is][out] */ void** aObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
DECL_IUNKNOWN
// IEnumVariant
virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next(
@ -56,9 +51,6 @@ protected:
nsRefPtr<AccessibleWrap> mAnchorAcc;
Accessible* mCurAcc;
PRUint32 mCurIndex;
private:
ULONG mRefCnt;
};
} // a11y namespace

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

@ -69,6 +69,7 @@ LOCAL_INCLUDES += \
-I$(srcdir)/../html \
-I$(srcdir)/../xpcom \
-I$(srcdir)/../xul \
-I$(srcdir)/../windows/uia \
-I$(srcdir)/../../../content/base/src \
-I$(srcdir)/../../../content/events/src \
$(NULL)

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

@ -21,8 +21,8 @@ NS_IMPL_ISUPPORTS_INHERITED0(XULListboxAccessibleWrap,
XULListboxAccessible)
IMPL_IUNKNOWN_QUERY_HEAD(XULListboxAccessibleWrap)
IMPL_IUNKNOWN_QUERY_ENTRY_COND(CAccessibleTable, IsMulticolumn());
IMPL_IUNKNOWN_QUERY_ENTRY(AccessibleWrap)
IMPL_IUNKNOWN_QUERY_CLASS_COND(CAccessibleTable, IsMulticolumn());
IMPL_IUNKNOWN_QUERY_CLASS(AccessibleWrap)
IMPL_IUNKNOWN_QUERY_TAIL

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

@ -24,8 +24,6 @@
#include "nsPIDOMWindow.h"
#include "nsIServiceManager.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
using namespace mozilla::a11y;
@ -87,22 +85,13 @@ nsAccessNodeWrap::QueryService(REFGUID guidService, REFIID iid, void** ppv)
{
*ppv = nsnull;
static const GUID IID_SimpleDOMDeprecated = {0x0c539790,0x12e4,0x11cf,0xb6,0x61,0x00,0xaa,0x00,0x4c,0xd6,0xd8};
// Provide a special service ID for getting the accessible for the browser tab
// document that contains this accessible object. If this accessible object
// is not inside a browser tab then the service fails with E_NOINTERFACE.
// A use case for this is for screen readers that need to switch context or
// 'virtual buffer' when focus moves from one browser tab area to another.
static const GUID SID_IAccessibleContentDocument = {0xa5d8e1f3,0x3571,0x4d8f,0x95,0x21,0x07,0xed,0x28,0xfb,0x07,0x2e};
if (guidService != IID_ISimpleDOMNode &&
guidService != IID_SimpleDOMDeprecated &&
guidService != IID_IAccessible && guidService != IID_IAccessible2 &&
guidService != IID_IAccessibleApplication &&
guidService != SID_IAccessibleContentDocument)
return E_INVALIDARG;
static const GUID SID_IAccessibleContentDocument =
{ 0xa5d8e1f3,0x3571,0x4d8f,0x95,0x21,0x07,0xed,0x28,0xfb,0x07,0x2e };
if (guidService == SID_IAccessibleContentDocument) {
if (iid != IID_IAccessible)
return E_NOINTERFACE;
@ -139,7 +128,7 @@ nsAccessNodeWrap::QueryService(REFGUID guidService, REFIID iid, void** ppv)
}
// Can get to IAccessibleApplication from any node via QS
if (iid == IID_IAccessibleApplication) {
if (guidService == IID_IAccessibleApplication) {
ApplicationAccessible* applicationAcc = GetApplicationAccessible();
if (!applicationAcc)
return E_NOINTERFACE;
@ -162,7 +151,14 @@ nsAccessNodeWrap::QueryService(REFGUID guidService, REFIID iid, void** ppv)
* }
*/
return QueryInterface(iid, ppv);
static const GUID IID_SimpleDOMDeprecated =
{ 0x0c539790,0x12e4,0x11cf,0xb6,0x61,0x00,0xaa,0x00,0x4c,0xd6,0xd8 };
if (guidService == IID_ISimpleDOMNode ||
guidService == IID_SimpleDOMDeprecated ||
guidService == IID_IAccessible || guidService == IID_IAccessible2)
return QueryInterface(iid, ppv);
return E_INVALIDARG;
}
//-----------------------------------------------------

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

@ -34,6 +34,14 @@
#include "nsRefPtrHashtable.h"
#define A11Y_TRYBLOCK_BEGIN \
__try {
#define A11Y_TRYBLOCK_END \
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), \
GetExceptionInformation()))\
{ } \
return E_FAIL;
class AccTextChangeEvent;
@ -46,18 +54,20 @@ class nsAccessNodeWrap : public nsAccessNode,
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIWINACCESSNODE
public: // IServiceProvider
STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void** ppv);
public: // construction, destruction
nsAccessNodeWrap(nsIContent* aContent, DocAccessible* aDoc);
virtual ~nsAccessNodeWrap();
// IUnknown
STDMETHODIMP QueryInterface(REFIID, void**);
// IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID aIID,
void** aInstancePtr);
public:
// IServiceProvider
virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID aGuidService,
REFIID aIID,
void** aInstancePtr);
// ISimpleDOMNode
virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_nodeInfo(
/* [out] */ BSTR __RPC_FAR *tagName,
/* [out] */ short __RPC_FAR *nameSpaceID,

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

@ -0,0 +1,16 @@
#
# 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/.
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS += uia \
$(null)
include $(topsrcdir)/config/rules.mk

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

@ -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/.
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = accessibility
LIBRARY_NAME = accessibility_toolkit_uia_s
EXPORT_LIBRARY = ..
LIBXUL_LIBRARY = 1
CPPSRCS += \
uiaRawElmProvider.cpp \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a static lib.
FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES += \
-I$(srcdir) \
-I$(srcdir)/../../base \
-I$(srcdir)/../../generic \
-I$(srcdir)/../../html \
-I$(srcdir)/../../msaa \
-I$(srcdir)/../../xpcom \
-I$(srcdir)/../../xul \
$(NULL)

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

@ -0,0 +1,170 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "uiaRawElmProvider.h"
#include "AccessibleWrap.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// uiaRawElmProvider
////////////////////////////////////////////////////////////////////////////////
IMPL_IUNKNOWN2(uiaRawElmProvider,
IAccessibleEx,
IRawElementProviderSimple)
////////////////////////////////////////////////////////////////////////////////
// IAccessibleEx
STDMETHODIMP
uiaRawElmProvider::GetObjectForChild(long aIdChild,
__RPC__deref_out_opt IAccessibleEx** aAccEx)
{
A11Y_TRYBLOCK_BEGIN
if (!aAccEx)
return E_INVALIDARG;
*aAccEx = NULL;
return mAcc->IsDefunct() ? CO_E_OBJNOTCONNECTED : S_OK;
A11Y_TRYBLOCK_END
}
STDMETHODIMP
uiaRawElmProvider::GetIAccessiblePair(__RPC__deref_out_opt IAccessible** aAcc,
__RPC__out long* aIdChild)
{
A11Y_TRYBLOCK_BEGIN
if (!aAcc || !aIdChild)
return E_INVALIDARG;
*aAcc = NULL;
*aIdChild = 0;
if (mAcc->IsDefunct())
return CO_E_OBJNOTCONNECTED;
*aIdChild = CHILDID_SELF;
*aAcc = mAcc;
mAcc->AddRef();
return S_OK;
A11Y_TRYBLOCK_END
}
STDMETHODIMP
uiaRawElmProvider::GetRuntimeId(__RPC__deref_out_opt SAFEARRAY** aRuntimeIds)
{
A11Y_TRYBLOCK_BEGIN
if (!aRuntimeIds)
return E_INVALIDARG;
int ids[] = { UiaAppendRuntimeId, reinterpret_cast<int>(mAcc->UniqueID()) };
*aRuntimeIds = SafeArrayCreateVector(VT_I4, 0, 2);
if (!*aRuntimeIds)
return E_OUTOFMEMORY;
for (LONG i = 0; i < ArrayLength(ids); i++)
SafeArrayPutElement(*aRuntimeIds, &i, (void*)&(ids[i]));
return S_OK;
A11Y_TRYBLOCK_END
}
STDMETHODIMP
uiaRawElmProvider::ConvertReturnedElement(__RPC__in_opt IRawElementProviderSimple* aRawElmProvider,
__RPC__deref_out_opt IAccessibleEx** aAccEx)
{
A11Y_TRYBLOCK_BEGIN
if (!aRawElmProvider || !aAccEx)
return E_INVALIDARG;
*aAccEx = NULL;
void* instancePtr = NULL;
HRESULT hr = aRawElmProvider->QueryInterface(IID_IAccessibleEx, &instancePtr);
if (SUCCEEDED(hr))
*aAccEx = static_cast<IAccessibleEx*>(instancePtr);
return hr;
A11Y_TRYBLOCK_END
}
////////////////////////////////////////////////////////////////////////////////
// IRawElementProviderSimple
STDMETHODIMP
uiaRawElmProvider::get_ProviderOptions(__RPC__out enum ProviderOptions* aOptions)
{
A11Y_TRYBLOCK_BEGIN
if (!aOptions)
return E_INVALIDARG;
// This method is not used with IAccessibleEx implementations.
*aOptions = ProviderOptions_ServerSideProvider;
return S_OK;
A11Y_TRYBLOCK_END
}
STDMETHODIMP
uiaRawElmProvider::GetPatternProvider(PATTERNID aPatternId,
__RPC__deref_out_opt IUnknown** aPatternProvider)
{
A11Y_TRYBLOCK_BEGIN
if (!aPatternProvider)
return E_INVALIDARG;
*aPatternProvider = NULL;
return S_OK;
A11Y_TRYBLOCK_END
}
STDMETHODIMP
uiaRawElmProvider::GetPropertyValue(PROPERTYID aPropertyId,
__RPC__out VARIANT* aPropertyValue)
{
A11Y_TRYBLOCK_BEGIN
if (!aPropertyValue)
return E_INVALIDARG;
// UI Automation will attempt to get the property from the host
//window provider.
aPropertyValue->vt = VT_EMPTY;
return S_OK;
A11Y_TRYBLOCK_END
}
STDMETHODIMP
uiaRawElmProvider::get_HostRawElementProvider(__RPC__deref_out_opt IRawElementProviderSimple** aRawElmProvider)
{
A11Y_TRYBLOCK_BEGIN
if (!aRawElmProvider)
return E_INVALIDARG;
// This method is not used with IAccessibleEx implementations.
*aRawElmProvider = NULL;
return S_OK;
A11Y_TRYBLOCK_END
}

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

@ -0,0 +1,74 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_uiaRawElmProvider_h__
#define mozilla_a11y_uiaRawElmProvider_h__
#include "objbase.h"
#include "AccessibleWrap.h"
#include "UIAutomation.h"
class AccessibleWrap;
namespace mozilla {
namespace a11y {
/**
* IRawElementProviderSimple implementation (maintains IAccessibleEx approach).
*/
class uiaRawElmProvider MOZ_FINAL : public IAccessibleEx,
public IRawElementProviderSimple
{
public:
uiaRawElmProvider(AccessibleWrap* aAcc) : mAcc(aAcc), mRefCnt(0) { }
// IUnknown
DECL_IUNKNOWN
// IAccessibleEx
virtual HRESULT STDMETHODCALLTYPE GetObjectForChild(
/* [in] */ long aIdChild,
/* [retval][out] */ __RPC__deref_out_opt IAccessibleEx** aAccEx);
virtual HRESULT STDMETHODCALLTYPE GetIAccessiblePair(
/* [out] */ __RPC__deref_out_opt IAccessible** aAcc,
/* [out] */ __RPC__out long* aIdChild);
virtual HRESULT STDMETHODCALLTYPE GetRuntimeId(
/* [retval][out] */ __RPC__deref_out_opt SAFEARRAY** aRuntimeIds);
virtual HRESULT STDMETHODCALLTYPE ConvertReturnedElement(
/* [in] */ __RPC__in_opt IRawElementProviderSimple* aRawElmProvider,
/* [out] */ __RPC__deref_out_opt IAccessibleEx** aAccEx);
// IRawElementProviderSimple
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_ProviderOptions(
/* [retval][out] */ __RPC__out enum ProviderOptions* aProviderOptions);
virtual HRESULT STDMETHODCALLTYPE GetPatternProvider(
/* [in] */ PATTERNID aPatternId,
/* [retval][out] */ __RPC__deref_out_opt IUnknown** aPatternProvider);
virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
/* [in] */ PROPERTYID aPropertyId,
/* [retval][out] */ __RPC__out VARIANT* aPropertyValue);
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_HostRawElementProvider(
/* [retval][out] */ __RPC__deref_out_opt IRawElementProviderSimple** aRawElmProvider);
private:
uiaRawElmProvider() MOZ_DELETE;
uiaRawElmProvider& operator =(const uiaRawElmProvider&) MOZ_DELETE;
uiaRawElmProvider(const uiaRawElmProvider&) MOZ_DELETE;
protected:
nsRefPtr<AccessibleWrap> mAcc;
};
} // a11y namespace
} // mozilla namespace
#endif

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

@ -164,22 +164,15 @@ XULTabsAccessible::GetNameInternal(nsAString& aName)
////////////////////////////////////////////////////////////////////////////////
// XULTabpanelsAccessible
// XULDeckAccessible
////////////////////////////////////////////////////////////////////////////////
XULTabpanelsAccessible::
XULTabpanelsAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc)
{
}
role
XULTabpanelsAccessible::NativeRole()
XULDeckAccessible::NativeRole()
{
return roles::PANE;
}
////////////////////////////////////////////////////////////////////////////////
// XULTabpanelAccessible
////////////////////////////////////////////////////////////////////////////////

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

@ -56,13 +56,15 @@ public:
};
/**
/**
* A container of tab panels, xul:tabpanels element.
*/
class XULTabpanelsAccessible : public AccessibleWrap
class XULDeckAccessible : public AccessibleWrap
{
public:
XULTabpanelsAccessible(nsIContent* aContent, DocAccessible* aDoc);
XULDeckAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc)
{ mFlags |= eXULDeckAccessible; }
// Accessible
virtual a11y::role NativeRole();

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

@ -542,6 +542,23 @@
testTextAttrs(ID, 2, { }, defAttrs, 2, 6);
testTextAttrs(ID, 6, attrs, defAttrs, 6, 7);
//////////////////////////////////////////////////////////////////////////
// area19, "HTML5 mark tag" test
// text enclosed in mark tag will have a different background color
ID = "area19";
defAttrs = buildDefaultTextAttrs(ID, "12pt");
attrs = {};
testTextAttrs(ID, 0, attrs, defAttrs, 0, 10);
tempElem = getNode(ID).firstChild.nextSibling;
gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
attrs = { "background-color": gComputedStyle.backgroundColor };
testTextAttrs(ID, 11, attrs, defAttrs, 10, 17);
attrs = {};
testTextAttrs(ID, 18, attrs, defAttrs, 17, 28);
SimpleTest.finish();
}
@ -692,5 +709,9 @@
<li id="area18" class="gencontent">item</li>
</ul>
<p id="area19">uncolored
<mark>colored</mark> uncolored
</p>
</body>
</html>

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

@ -378,6 +378,9 @@ pref("dom.sms.enabled", true);
// Temporary permission hack for WebContacts
pref("dom.mozContacts.enabled", true);
// WebAlarms
pref("dom.mozAlarms.enabled", true);
// WebSettings
pref("dom.mozSettings.enabled", true);

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

@ -161,7 +161,7 @@ DeviceTabActor.prototype = {
'tab should have an actorID.');
return {
'actor': this.actorID,
'title': this.browser.contentTitle,
'title': this.browser.title,
'url': this.browser.document.documentURI
}
},
@ -222,7 +222,7 @@ DeviceTabActor.prototype = {
this.conn.addActorPool(this._contextPool);
this.threadActor = new ThreadActor(this);
this._addDebuggees(this.browser.content.wrappedJSObject);
this._addDebuggees(this.browser.wrappedJSObject);
this._contextPool.addActor(this.threadActor);
},
@ -293,7 +293,7 @@ DeviceTabActor.prototype = {
* Prepare to enter a nested event loop by disabling debuggee events.
*/
preNest: function DTA_preNest() {
let windowUtils = this.browser.content
let windowUtils = this.browser
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.suppressEventHandling(true);
@ -304,7 +304,7 @@ DeviceTabActor.prototype = {
* Prepare to exit a nested event loop by enabling debuggee events.
*/
postNest: function DTA_postNest(aNestData) {
let windowUtils = this.browser.content
let windowUtils = this.browser
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.resumeTimeouts();

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

@ -79,15 +79,18 @@ SettingsListener.observe('language.current', 'en-US', function(value) {
// =================== Debugger ====================
SettingsListener.observe('devtools.debugger.enabled', false, function(enabled) {
Services.prefs.setBoolPref('devtools.debugger.enabled', value);
SettingsListener.observe('devtools.debugger.remote-enabled', false, function(enabled) {
Services.prefs.setBoolPref('devtools.debugger.remote-enabled', value);
});
SettingsListener.observe('devtools.debugger.log', false, function(value) {
Services.prefs.setBoolPref('devtools.debugger.log', value);
});
SettingsListener.observe('devtools.debugger.port', 6000, function(value) {
Services.prefs.setIntPref('devtools.debugger.port', value);
SettingsListener.observe('devtools.debugger.remote-port', 6000, function(value) {
Services.prefs.setIntPref('devtools.debugger.remote-port', value);
});
SettingsListener.observe('devtools.debugger.force-local', true, function(value) {
Services.prefs.setBoolPref('devtools.debugger.force-local', value);
});

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

@ -14,6 +14,7 @@ Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/ContactService.jsm');
Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
Cu.import('resource://gre/modules/Webapps.jsm');
Cu.import('resource://gre/modules/AlarmService.jsm');
XPCOMUtils.defineLazyServiceGetter(Services, 'env',
'@mozilla.org/process/environment;1',
@ -48,10 +49,10 @@ XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() {
// XXX never grant 'content-camera' to non-gaia apps
function addPermissions(urls) {
let permissions = [
'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'pin-app',
'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'pin-app',
'websettings-read', 'websettings-readwrite',
'content-camera', 'webcontacts-manage', 'wifi-manage', 'desktop-notification',
'geolocation', 'device-storage'
'geolocation', 'device-storage', 'alarms'
];
urls.forEach(function(url) {
url = url.trim();

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

@ -7,7 +7,6 @@ ac_add_options --enable-application=b2g
ac_add_options --target=arm-android-eabi
ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-eabi-4.4.3/bin/arm-eabi-"
ac_add_options --with-endian=little
ac_add_options --disable-elf-hack
ac_add_options --enable-debug-symbols
ac_add_options --enable-debug

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

@ -7,7 +7,6 @@ ac_add_options --enable-application=b2g
ac_add_options --target=arm-android-eabi
ac_add_options --with-gonk="$topsrcdir/gonk-toolchain"
ac_add_options --with-gonk-toolchain-prefix="$topsrcdir/gonk-toolchain/prebuilt/$TOOLCHAIN_HOST/toolchain/arm-eabi-4.4.3/bin/arm-eabi-"
ac_add_options --with-endian=little
ac_add_options --disable-elf-hack
ac_add_options --enable-debug-symbols
ac_add_options --enable-profiling

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

@ -55,6 +55,10 @@ BINPATH = bin
endif
DEFINES += -DBINPATH=$(BINPATH)
ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
DEFINES += -DMOZ_SHARED_MOZGLUE=1
endif
ifdef MOZ_PKG_MANIFEST_P
$(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) FORCE
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@

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

@ -82,11 +82,13 @@
@BINPATH@/mozcpp19.dll
#endif
#endif
#ifdef MOZ_SHARED_MOZGLUE
@BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
#endif
#ifdef ANDROID
@BINPATH@/AndroidManifest.xml
@BINPATH@/resources.arsc
@BINPATH@/classes.dex
@BINPATH@/@DLL_PREFIX@mozglue@DLL_SUFFIX@
@BINPATH@/res/drawable
@BINPATH@/res/drawable-hdpi
@BINPATH@/res/layout
@ -161,6 +163,7 @@
#endif
@BINPATH@/components/dom_canvas.xpt
@BINPATH@/components/dom_contacts.xpt
@BINPATH@/components/dom_alarm.xpt
@BINPATH@/components/dom_core.xpt
@BINPATH@/components/dom_css.xpt
@BINPATH@/components/dom_devicestorage.xpt
@ -317,6 +320,8 @@
@BINPATH@/components/BrowserElementParent.js
@BINPATH@/components/ContactManager.js
@BINPATH@/components/ContactManager.manifest
@BINPATH@/components/AlarmsManager.js
@BINPATH@/components/AlarmsManager.manifest
@BINPATH@/components/FeedProcessor.manifest
@BINPATH@/components/FeedProcessor.js
@BINPATH@/components/BrowserFeeds.manifest

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

@ -1023,7 +1023,7 @@ pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
pref("devtools.errorconsole.enabled", false);
// Developer toolbar and GCLI preferences
pref("devtools.toolbar.enabled", false);
pref("devtools.toolbar.enabled", true);
pref("devtools.toolbar.visible", false);
pref("devtools.gcli.allowSet", false);
pref("devtools.commands.dir", "");
@ -1073,6 +1073,11 @@ pref("devtools.ruleview.enabled", true);
// Enable the Scratchpad tool.
pref("devtools.scratchpad.enabled", true);
// The maximum number of recently-opened files stored.
// Setting this preference to 0 will not clear any recent files, but rather hide
// the 'Open Recent'-menu.
pref("devtools.scratchpad.recentFilesMax", 10);
// Enable the Style Editor.
pref("devtools.styleeditor.enabled", true);
pref("devtools.styleeditor.transitions", true);
@ -1177,3 +1182,6 @@ pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
// might keep around more than this, but we'll try to get down to this value).
// (This is intentionally on the high side; see bug 746055.)
pref("image.mem.max_decoded_image_kb", 256000);
// Example social provider
pref("social.manifest.motown", "{\"origin\":\"https://motown-dev.mozillalabs.com\",\"name\":\"MoTown\",\"workerURL\":\"https://motown-dev.mozillalabs.com/social/worker.js\"}");

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

@ -118,7 +118,7 @@
command="Browser:SavePage"
key="key_savePage"/>
<menuitem id="appmenu_sendLink"
label="&sendPageCmd.label;"
label="&emailPageCmd.label;"
command="Browser:SendLink"/>
<splitmenu id="appmenu_print"
iconic="true"

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

@ -37,10 +37,6 @@
label="&saveLinkCmd.label;"
accesskey="&saveLinkCmd.accesskey;"
oncommand="gContextMenu.saveLink();"/>
<menuitem id="context-sendlink"
label="&sendLinkCmd.label;"
accesskey="&sendLinkCmd.accesskey;"
oncommand="gContextMenu.sendLink();"/>
<menuitem id="context-copyemail"
label="&copyEmailCmd.label;"
accesskey="&copyEmailCmd.accesskey;"
@ -129,8 +125,8 @@
accesskey="&saveImageCmd.accesskey;"
oncommand="gContextMenu.saveMedia();"/>
<menuitem id="context-sendimage"
label="&sendImageCmd.label;"
accesskey="&sendImageCmd.accesskey;"
label="&emailImageCmd.label;"
accesskey="&emailImageCmd.accesskey;"
oncommand="gContextMenu.sendMedia();"/>
<menuitem id="context-setDesktopBackground"
label="&setDesktopBackgroundCmd.label;"
@ -153,12 +149,12 @@
label="&videoSaveImage.label;"
oncommand="gContextMenu.saveVideoFrameAsImage();"/>
<menuitem id="context-sendvideo"
label="&sendVideoCmd.label;"
accesskey="&sendVideoCmd.accesskey;"
label="&emailVideoCmd.label;"
accesskey="&emailVideoCmd.accesskey;"
oncommand="gContextMenu.sendMedia();"/>
<menuitem id="context-sendaudio"
label="&sendAudioCmd.label;"
accesskey="&sendAudioCmd.accesskey;"
label="&emailAudioCmd.label;"
accesskey="&emailAudioCmd.accesskey;"
oncommand="gContextMenu.sendMedia();"/>
<menuitem id="context-back"
label="&backCmd.label;"
@ -188,10 +184,6 @@
label="&savePageCmd.label;"
accesskey="&savePageCmd.accesskey2;"
oncommand="gContextMenu.savePageAs();"/>
<menuitem id="context-sendpage"
label="&sendPageCmd.label;"
accesskey="&sendPageCmd.accesskey;"
oncommand="gContextMenu.sendPage();"/>
<menuseparator id="context-sep-viewbgimage"/>
<menuitem id="context-viewbgimage"
label="&viewBGImageCmd.label;"

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

@ -53,8 +53,8 @@
key="key_savePage"
command="Browser:SavePage"/>
<menuitem id="menu_sendLink"
label="&sendPageCmd.label;"
accesskey="&sendPageCmd.accesskey;"
label="&emailPageCmd.label;"
accesskey="&emailPageCmd.accesskey;"
command="Browser:SendLink"/>
<menuseparator/>
<menuitem id="menu_printSetup"
@ -519,7 +519,6 @@
autocheck="false"
hidden="true"
label="&devToolbarMenu.label;"
accesskey="&devToolbarMenu.accesskey;"
key="key_devToolbar"
command="Tools:DevToolbar"/>
<menuitem id="webConsole"

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

@ -225,13 +225,6 @@
#endif
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
<key id="key_devToolbar" key="&devToolbar.commandkey;" command="Tools:DevToolbar"
#ifdef XP_MACOSX
modifiers="accel,alt"
#else
modifiers="accel,shift"
#endif
/>
<key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
#ifdef XP_MACOSX
modifiers="accel,alt"

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

@ -568,6 +568,16 @@ html|*#gcli-output-frame,
direction: ltr;
}
#developer-toolbar-webconsole[error-count] > .toolbarbutton-icon {
display: none;
}
#developer-toolbar-webconsole[error-count]:before {
content: attr(error-count);
display: -moz-box;
-moz-box-pack: center;
}
/* Responsive Mode */
vbox[anonid=browserContainer][responsivemode] {

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

@ -1400,7 +1400,7 @@ var gBrowserInit = {
// Show the toolbar if it was previously visible
if (gPrefService.getBoolPref("devtools.toolbar.visible")) {
DeveloperToolbar.show();
DeveloperToolbar.show(false);
}
}
@ -2610,13 +2610,16 @@ function BrowserOnClick(event) {
if (previousNotification)
notificationBox.removeNotification(previousNotification);
notificationBox.appendNotification(
let notification = notificationBox.appendNotification(
title,
value,
"chrome://global/skin/icons/blacklist_favicon.png",
notificationBox.PRIORITY_CRITICAL_HIGH,
buttons
);
// Persist the notification until the user removes so it
// doesn't get removed on redirects.
notification.persistence = -1;
}
}
else if (/^about:home$/i.test(ownerDoc.documentURI)) {
@ -5261,10 +5264,9 @@ function middleMousePaste(event) {
Cu.reportError(ex);
}
// FIXME: Bug 631500, use openUILink directly
let where = whereToOpenLink(event, true);
openUILinkIn(url, where,
{ disallowInheritPrincipal: !mayInheritPrincipal.value });
openUILink(url, event,
{ ignoreButton: true,
disallowInheritPrincipal: !mayInheritPrincipal.value });
event.stopPropagation();
}
@ -6914,6 +6916,7 @@ let gPrivateBrowsingUI = {
_searchBarValue: null,
_findBarValue: null,
_inited: false,
_initCallbacks: [],
init: function PBUI_init() {
Services.obs.addObserver(this, "private-browsing", false);
@ -6926,6 +6929,9 @@ let gPrivateBrowsingUI = {
this.onEnterPrivateBrowsing(true);
this._inited = true;
this._initCallbacks.forEach(function (callback) callback.apply());
this._initCallbacks = [];
},
uninit: function PBUI_unint() {
@ -6936,6 +6942,17 @@ let gPrivateBrowsingUI = {
Services.obs.removeObserver(this, "private-browsing-transition-complete");
},
get initialized() {
return this._inited;
},
addInitializationCallback: function PBUI_addInitializationCallback(aCallback) {
if (this._inited)
return;
this._initCallbacks.push(aCallback);
},
get _disableUIOnToggle() {
if (this._privateBrowsingService.autoStarted)
return false;
@ -7138,14 +7155,16 @@ let gPrivateBrowsingUI = {
!this.privateBrowsingEnabled;
},
get autoStarted() {
return this._privateBrowsingService.autoStarted;
},
get privateBrowsingEnabled() {
return this._privateBrowsingService.privateBrowsingEnabled;
},
/**
* These accessors are used to support per-window Private Browsing mode.
* For now the getter returns nsIPrivateBrowsingService.privateBrowsingEnabled,
* and the setter should only be used in tests.
* This accessor is used to support per-window Private Browsing mode.
*/
get privateWindow() {
if (!gBrowser)

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

@ -1037,21 +1037,21 @@
</stack>
<toolbarbutton id="developer-toolbar-webconsole"
label="&webConsoleButton.label;"
class="devtools-toolbarbutton"
class="developer-toolbar-button"
command="Tools:WebConsole"/>
<toolbarbutton id="developer-toolbar-inspector"
label="&inspectorButton.label;"
class="devtools-toolbarbutton"
class="developer-toolbar-button"
hidden="true"
command="Tools:Inspect"/>
<toolbarbutton id="developer-toolbar-styleeditor"
label="&styleeditor.label;"
class="devtools-toolbarbutton"
class="developer-toolbar-button"
hidden="true"
command="Tools:StyleEditor"/>
<toolbarbutton id="developer-toolbar-debugger"
label="&debuggerMenu.label2;"
class="devtools-toolbarbutton"
class="developer-toolbar-button"
hidden="true"
command="Tools:Debugger"/>
#ifndef XP_MACOSX

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

@ -38,10 +38,13 @@ let gDrag = {
// Mark nodes as being dragged.
let selector = ".newtab-site, .newtab-control, .newtab-thumbnail";
let nodes = aSite.node.parentNode.querySelectorAll(selector);
let parentCell = aSite.node.parentNode;
let nodes = parentCell.querySelectorAll(selector);
for (let i = 0; i < nodes.length; i++)
nodes[i].setAttribute("dragged", "true");
parentCell.setAttribute("dragged", "true");
this._setDragData(aSite, aEvent);
// Store the cursor offset.
@ -88,7 +91,7 @@ let gDrag = {
* @param aEvent The 'dragend' event.
*/
end: function Drag_end(aSite, aEvent) {
let nodes = aSite.node.parentNode.querySelectorAll("[dragged]");
let nodes = gGrid.node.querySelectorAll("[dragged]")
for (let i = 0; i < nodes.length; i++)
nodes[i].removeAttribute("dragged");

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

@ -148,8 +148,9 @@ nsContextMenu.prototype = {
this.onTextInput);
this.showItem("context-back", shouldShow);
this.showItem("context-forward", shouldShow);
this.showItem("context-reload", shouldShow);
this.showItem("context-stop", shouldShow);
var shouldShowReload = XULBrowserWindow.stopCommand.getAttribute("disabled") == "true";
this.showItem("context-reload", shouldShow && shouldShowReload);
this.showItem("context-stop", shouldShow && !shouldShowReload);
this.showItem("context-sep-stop", shouldShow);
// XXX: Stop is determined in browser.js; the canStop broadcaster is broken
@ -171,11 +172,9 @@ nsContextMenu.prototype = {
this.isContentSelected || this.onImage ||
this.onCanvas || this.onVideo || this.onAudio);
this.showItem("context-savepage", shouldShow);
this.showItem("context-sendpage", shouldShow);
// Save+Send link depends on whether we're in a link, or selected text matches valid URL pattern.
// Save link depends on whether we're in a link, or selected text matches valid URL pattern.
this.showItem("context-savelink", this.onSaveableLink || this.onPlainTextLink);
this.showItem("context-sendlink", this.onSaveableLink || this.onPlainTextLink);
// Save image depends on having loaded its content, video and audio don't.
this.showItem("context-saveimage", this.onLoadedImage || this.onCanvas);
@ -1050,11 +1049,6 @@ nsContextMenu.prototype = {
this.saveHelper(this.linkURL, linkText, null, true, doc);
},
sendLink: function() {
// we don't know the title of the link so pass in an empty string
MailIntegration.sendMessage( this.linkURL, "" );
},
// Backwards-compatibility wrapper
saveImage : function() {
if (this.onCanvas || this.onImage)
@ -1403,10 +1397,6 @@ nsContextMenu.prototype = {
saveDocument(this.browser.contentDocument);
},
sendPage: function CM_sendPage() {
MailIntegration.sendLinkForWindow(this.browser.contentWindow);
},
printFrame: function CM_printFrame() {
PrintUtils.print(this.target.ownerDocument.defaultView);
},

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

@ -354,18 +354,23 @@
<label class="permissionLabel" id="permIndexedDBLabel"
value="&permIndexedDB;" control="indexedDBRadioGroup"/>
<hbox role="group" aria-labelledby="permIndexedDBLabel">
<checkbox id="indexedDBDef" command="cmd_indexedDBDef" label="&permAskAlways;"/>
<checkbox id="indexedDBDef" command="cmd_indexedDBDef" label="&permUseDefault;"/>
<spacer flex="1"/>
<vbox pack="center">
<label id="indexedDBStatus" control="indexedDBClear"/>
</vbox>
<button id="indexedDBClear" label="&permClearStorage;"
accesskey="&permClearStorage.accesskey;" onclick="onIndexedDBClear();"/>
<radiogroup id="indexedDBRadioGroup" orient="horizontal">
<radio id="indexedDB#1" command="cmd_indexedDBToggle" label="&permAllow;"/>
<!-- Ask and Allow are purposefully reversed here! -->
<radio id="indexedDB#1" command="cmd_indexedDBToggle" label="&permAskAlways;"/>
<radio id="indexedDB#0" command="cmd_indexedDBToggle" label="&permAllow;"/>
<radio id="indexedDB#2" command="cmd_indexedDBToggle" label="&permBlock;"/>
</radiogroup>
</hbox>
<hbox>
<spacer flex="1"/>
<vbox pack="center">
<label id="indexedDBStatus" control="indexedDBClear" hidden="true"/>
</vbox>
<button id="indexedDBClear" label="&permClearStorage;" hidden="true"
accesskey="&permClearStorage.accesskey;" onclick="onIndexedDBClear();"/>
</hbox>
</vbox>
<vbox class="permission" id="permPluginsRow">
<label class="permissionLabel" id="permPluginsLabel"

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

@ -51,7 +51,7 @@ var gPermObj = {
},
indexedDB: function getIndexedDBDefaultPermissions()
{
return BLOCK;
return UNKNOWN;
},
plugins: function getPluginsDefaultPermissions()
{
@ -149,9 +149,6 @@ function onCheckboxClick(aPartId)
var checkbox = document.getElementById(aPartId + "Def");
if (checkbox.checked) {
permissionManager.remove(gPermURI.host, aPartId);
if (aPartId == "indexedDB") {
permissionManager.remove(gPermURI.host, "indexedDB-unlimited");
}
command.setAttribute("disabled", "true");
var perm = gPermObj[aPartId]();
setRadioState(aPartId, perm);
@ -171,7 +168,8 @@ function onRadioClick(aPartId)
var id = radioGroup.selectedItem.id;
var permission = id.split('#')[1];
permissionManager.add(gPermURI, aPartId, permission);
if (aPartId == "indexedDB" && permission == BLOCK) {
if (aPartId == "indexedDB" &&
(permission == ALLOW || permission == BLOCK)) {
permissionManager.remove(gPermURI.host, "indexedDB-unlimited");
}
if (aPartId == "fullscreen" && permission == UNKNOWN) {
@ -207,7 +205,6 @@ function onIndexedDBClear()
var permissionManager = Components.classes[PERMISSION_CONTRACTID]
.getService(nsIPermissionManager);
permissionManager.remove(gPermURI.host, "indexedDB");
permissionManager.remove(gPermURI.host, "indexedDB-unlimited");
initIndexedDBRow();
}

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

@ -1413,10 +1413,9 @@
if (tabsToClose <= 1)
return true;
var canDisablePrompt = !!aAll;
const pref = "browser.tabs.warnOnClose";
var shouldPrompt = Services.prefs.getBoolPref(pref);
if (!shouldPrompt)
if (canDisablePrompt && !Services.prefs.getBoolPref(pref))
return true;
var ps = Services.prompt;
@ -1440,11 +1439,13 @@
+ (ps.BUTTON_TITLE_CANCEL * ps.BUTTON_POS_1),
bundle.getString("tabs.closeButtonMultiple"),
null, null,
bundle.getString('tabs.closeWarningPromptMe'),
canDisablePrompt ?
bundle.getString("tabs.closeWarningPromptMe") : null,
warnOnClose);
var reallyClose = (buttonPressed == 0);
// don't set the pref unless they press OK and it's false
if (reallyClose && !warnOnClose.value)
if (canDisablePrompt && reallyClose && !warnOnClose.value)
Services.prefs.setBoolPref(pref, false);
return reallyClose;

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

@ -153,6 +153,7 @@ _BROWSER_FILES = \
browser_bug743421.js \
browser_bug749738.js \
browser_bug763468.js \
browser_bug767836.js \
browser_canonizeURL.js \
browser_customize.js \
browser_findbarClose.js \

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

@ -11,12 +11,12 @@ function test() {
var newWindow;
var tabToDetach;
var documentToDetach;
function onPageShow(event) {
// we get here if the test is executed before the pageshow
// event for the window's first tab
if (!tabToDetach ||
tabToDetach.linkedBrowser.contentDocument != event.target)
if (!tabToDetach || documentToDetach != event.target)
return;
event.currentTarget.removeEventListener("pageshow", onPageShow, false);
@ -46,6 +46,10 @@ function test() {
finish();
}
gBrowser.addEventListener("pageshow", onPageShow, false);
tabToDetach = gBrowser.addTab(testPage);
tabToDetach.linkedBrowser.addEventListener("load", function onLoad() {
tabToDetach.linkedBrowser.removeEventListener("load", onLoad, true);
documentToDetach = tabToDetach.linkedBrowser.contentDocument;
gBrowser.addEventListener("pageshow", onPageShow, false);
}, true);
}

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

@ -0,0 +1,93 @@
/* 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/. */
// initialization
const pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
const PREF = "browser.newtab.url";
const NEWTABURL = Services.prefs.getCharPref(PREF) || "about:blank";
const TESTURL = "http://example.com/";
function test() {
waitForExplicitFinish();
// check whether the mode that we start off with is normal or not
ok(!pb.privateBrowsingEnabled, "private browsing is disabled");
// check whether any custom new tab url has been configured
ok(!Services.prefs.prefHasUserValue(PREF), "No custom newtab url is set");
openNewTab(function () {
// Check the new tab opened while in normal mode
is(gBrowser.selectedBrowser.currentURI.spec, NEWTABURL,
"URL of NewTab should be browser.newtab.url in Normal mode");
// Set the custom newtab url
Services.prefs.setCharPref(PREF, TESTURL);
ok(Services.prefs.prefHasUserValue(PREF), "Custom newtab url is set");
// Open a newtab after setting the custom newtab url
openNewTab(function () {
is(gBrowser.selectedBrowser.currentURI.spec, TESTURL,
"URL of NewTab should be the custom url");
// clear the custom url preference
Services.prefs.clearUserPref(PREF);
ok(!Services.prefs.prefHasUserValue(PREF), "No custom newtab url is set");
// enter private browsing mode
togglePrivateBrowsing(function () {
ok(pb.privateBrowsingEnabled, "private browsing is enabled");
// Open a new tab page in private browsing mode
openNewTab(function () {
// Check the new tab opened while in private browsing mode
is(gBrowser.selectedBrowser.currentURI.spec, "about:privatebrowsing",
"URL of NewTab should be about:privatebrowsing in PB mode");
Services.prefs.setCharPref(PREF, TESTURL);
ok(Services.prefs.prefHasUserValue(PREF), "Custom newtab url is set");
// Open a newtab after setting the custom newtab url
openNewTab(function () {
is(gBrowser.selectedBrowser.currentURI.spec, TESTURL,
"URL of NewTab should be the custom url");
Services.prefs.clearUserPref(PREF);
ok(!Services.prefs.prefHasUserValue(PREF), "No custom newtab url is set");
// exit private browsing mode
togglePrivateBrowsing(function () {
ok(!pb.privateBrowsingEnabled, "private browsing is disabled");
gBrowser.removeTab(gBrowser.selectedTab);
gBrowser.removeTab(gBrowser.selectedTab);
finish();
});
});
});
});
});
});
}
function togglePrivateBrowsing(aCallback) {
let topic = "private-browsing-transition-complete";
Services.obs.addObserver(function observe() {
Services.obs.removeObserver(observe, topic);
executeSoon(aCallback);
}, topic, false);
pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
}
function openNewTab(aCallback) {
// Open a new tab
BrowserOpenTab();
let browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
executeSoon(aCallback);
}, true);
}

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

@ -16,6 +16,7 @@ _BROWSER_FILES = \
browser_newtab_disable.js \
browser_newtab_drag_drop.js \
browser_newtab_drop_preview.js \
browser_newtab_focus.js \
browser_newtab_private_browsing.js \
browser_newtab_reset.js \
browser_newtab_tabsync.js \

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

@ -9,7 +9,7 @@
function runTests() {
// we remove sites and expect the gaps to be filled as long as there still
// are some sites available
setLinks("0,1,2,3,4,5,6,7,8,9");
yield setLinks("0,1,2,3,4,5,6,7,8,9");
setPinnedLinks("");
yield addNewTabPageTab();
@ -26,7 +26,7 @@ function runTests() {
// we removed a pinned site
yield restore();
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",1");
yield addNewTabPageTab();
@ -38,7 +38,7 @@ function runTests() {
// we remove the last site on the grid (which is pinned) and expect the gap
// to be re-filled and the new site to be unpinned
yield restore();
setLinks("0,1,2,3,4,5,6,7,8,9");
yield setLinks("0,1,2,3,4,5,6,7,8,9");
setPinnedLinks(",,,,,,,,8");
yield addNewTabPageTab();
@ -50,7 +50,7 @@ function runTests() {
// we remove the first site on the grid with the last one pinned. all cells
// but the last one should shift to the left and a new site fades in
yield restore();
setLinks("0,1,2,3,4,5,6,7,8,9");
yield setLinks("0,1,2,3,4,5,6,7,8,9");
setPinnedLinks(",,,,,,,,8");
yield addNewTabPageTab();

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

@ -2,19 +2,19 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
setLinks("0,1,2,3,4,5,6,7,8");
NewTabUtils.pinnedLinks._links = [
{url: "about:blank#7", title: ""},
{url: "about:blank#8", title: "title"},
{url: "about:blank#9", title: "about:blank#9"}
];
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks([
{url: "http://example.com/#7", title: ""},
{url: "http://example.com/#8", title: "title"},
{url: "http://example.com/#9", title: "http://example.com/#9"}
]);
yield addNewTabPageTab();
checkGrid("7p,8p,9p,0,1,2,3,4,5");
checkTooltip(0, "about:blank#7", "1st tooltip is correct");
checkTooltip(1, "title\nabout:blank#8", "2nd tooltip is correct");
checkTooltip(2, "about:blank#9", "3rd tooltip is correct");
checkTooltip(0, "http://example.com/#7", "1st tooltip is correct");
checkTooltip(1, "title\nhttp://example.com/#8", "2nd tooltip is correct");
checkTooltip(2, "http://example.com/#9", "3rd tooltip is correct");
}
function checkTooltip(aIndex, aExpected, aMessage) {

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

@ -5,30 +5,26 @@ const NOW = Date.now() * 1000;
const URL = "http://fake-site.com/";
let tmp = {};
Cu.import("resource:///modules/NewTabUtils.jsm", tmp);
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://browser/content/sanitize.js", tmp);
let {NewTabUtils, Sanitizer} = tmp;
let bhist = Cc["@mozilla.org/browser/global-history;2"]
.getService(Ci.nsIBrowserHistory);
let {Sanitizer} = tmp;
function runTests() {
clearHistory();
yield fillHistory();
sanitizeHistory();
yield addFakeVisits();
yield addNewTabPageTab();
is(getCell(0).site.url, URL, "first site is our fake site");
whenPagesUpdated();
yield clearHistory();
yield sanitizeHistory();
ok(!getCell(0).site, "the fake site is gone");
}
function fillHistory() {
function addFakeVisits() {
let visits = [];
for (let i = 59; i > 0; i--) {
visits.push({
@ -42,13 +38,18 @@ function fillHistory() {
visits: visits
};
PlacesUtils.asyncHistory.updatePlaces(place, {
handleError: function () do_throw("Unexpected error in adding visit."),
handleResult: function () { },
handleCompletion: function () TestRunner.next()
handleError: function () ok(false, "couldn't add visit"),
handleResult: function () {},
handleCompletion: function () {
NewTabUtils.links.populateCache(function () {
NewTabUtils.allPages.update();
TestRunner.next();
}, true);
}
});
}
function clearHistory() {
function sanitizeHistory() {
let s = new Sanitizer();
s.prefDomain = "privacy.cpd.";

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

@ -3,7 +3,7 @@
function runTests() {
// create a new tab page and hide it.
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();
@ -12,7 +12,7 @@ function runTests() {
yield addNewTabPageTab();
gBrowser.removeTab(firstTab);
ok(NewTabUtils.allPages.enabled, true, "page is enabled");
ok(NewTabUtils.allPages.enabled, "page is enabled");
NewTabUtils.allPages.enabled = false;
ok(getGrid().node.hasAttribute("page-disabled"), "page is disabled");
}

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

@ -2,7 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();

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

@ -2,7 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();
@ -10,14 +10,14 @@ function runTests() {
let cell = getCell(0).node;
sendDragEvent("drop", cell, "about:blank#99\nblank");
is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
sendDragEvent("drop", cell, "http://example.com/#99\nblank");
is(NewTabUtils.pinnedLinks.links[0].url, "http://example.com/#99",
"first cell is pinned and contains the dropped site");
yield whenPagesUpdated();
checkGrid("99p,0,1,2,3,4,5,6,7");
sendDragEvent("drop", cell, "");
is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
is(NewTabUtils.pinnedLinks.links[0].url, "http://example.com/#99",
"first cell is still pinned with the site we dropped before");
}

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

@ -2,7 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();

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

@ -2,7 +2,7 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
function runTests() {
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();

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

@ -7,7 +7,7 @@
*/
function runTests() {
// create a new tab page and hide it.
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();

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

@ -9,7 +9,7 @@
*/
function runTests() {
// test a simple drag-and-drop scenario
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();
@ -19,7 +19,7 @@ function runTests() {
checkGrid("1,0p,2,3,4,5,6,7,8");
// drag a cell to its current cell and make sure it's not pinned afterwards
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();
@ -29,7 +29,7 @@ function runTests() {
checkGrid("0,1,2,3,4,5,6,7,8");
// ensure that pinned pages aren't moved if that's not necessary
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",1,2");
yield addNewTabPageTab();
@ -40,7 +40,7 @@ function runTests() {
// pinned sites should always be moved around as blocks. if a pinned site is
// moved around, neighboring pinned are affected as well
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("0,1");
yield addNewTabPageTab();
@ -51,7 +51,7 @@ function runTests() {
// pinned sites should not be pushed out of the grid (unless there are only
// pinned ones left on the grid)
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",,,,,,,7,8");
yield addNewTabPageTab();
@ -61,7 +61,7 @@ function runTests() {
checkGrid("0,1,3,4,5,6,7p,8p,2p");
// make sure that pinned sites are re-positioned correctly
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("0,1,2,,,5");
yield addNewTabPageTab();
@ -71,7 +71,7 @@ function runTests() {
checkGrid("3,1p,2p,4,0p,5p,6,7,8");
// drag a new site onto the very first cell
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",,,,,,,7,8");
yield addNewTabPageTab();
@ -82,7 +82,7 @@ function runTests() {
// drag a new site onto the grid and make sure that pinned cells don't get
// pushed out
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",,,,,,,7,8");
yield addNewTabPageTab();
@ -93,7 +93,7 @@ function runTests() {
// drag a new site beneath a pinned cell and make sure the pinned cell is
// not moved
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",,,,,,,,8");
yield addNewTabPageTab();
@ -104,7 +104,7 @@ function runTests() {
// drag a new site onto a block of pinned sites and make sure they're shifted
// around accordingly
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("0,1,2,,,,,,");
yield addNewTabPageTab();

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

@ -7,7 +7,7 @@
*/
function runTests() {
// the first three sites are pinned - make sure they're re-arranged correctly
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("0,1,2,,,5");
yield addNewTabPageTab();

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

@ -0,0 +1,55 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*
* These tests make sure that focusing the 'New Tage Page' works as expected.
*/
function runTests() {
// Focus count in new tab page.
// 28 = 9 * 3 + 1 = 9 sites and 1 toggle button, each site has a link, a pin
// and a remove button.
let FOCUS_COUNT = 28;
if ("nsILocalFileMac" in Ci) {
// 19 = Mac doesn't focus links, so 9 focus targets less than Windows/Linux.
FOCUS_COUNT = 19;
}
// Create a new tab page.
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();
gURLBar.focus();
// Count the focus with the enabled page.
yield countFocus(FOCUS_COUNT);
// Disable page and count the focus with the disabled page.
NewTabUtils.allPages.enabled = false;
yield countFocus(1);
}
/**
* Focus the urlbar and count how many focus stops to return again to the urlbar.
*/
function countFocus(aExpectedCount) {
let focusCount = 0;
let contentDoc = getContentDocument();
window.addEventListener("focus", function onFocus() {
let focusedElement = document.commandDispatcher.focusedElement;
if (focusedElement && focusedElement.classList.contains("urlbar-input")) {
window.removeEventListener("focus", onFocus, true);
is(focusCount, aExpectedCount, "Validate focus count in the new tab page.");
executeSoon(TestRunner.next);
} else {
if (focusedElement && focusedElement.ownerDocument == contentDoc &&
focusedElement instanceof HTMLElement) {
focusCount++;
}
document.commandDispatcher.advanceFocus();
}
}, true);
document.commandDispatcher.advanceFocus();
}

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

@ -12,7 +12,7 @@ let pb = Cc["@mozilla.org/privatebrowsing;1"]
function runTests() {
// prepare the grid
setLinks("0,1,2,3,4,5,6,7,8,9");
yield setLinks("0,1,2,3,4,5,6,7,8,9");
ok(!pb.privateBrowsingEnabled, "private browsing is disabled");
yield addNewTabPageTab();

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

@ -9,7 +9,7 @@ function runTests() {
return;
// create a new tab page and check its modified state after blocking a site
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
yield addNewTabPageTab();

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

@ -11,7 +11,7 @@ function runTests() {
// Disabled until bug 716543 is fixed.
return;
setLinks("0,1,2,3,4,5,6,7,8,9");
yield setLinks("0,1,2,3,4,5,6,7,8,9");
setPinnedLinks(",1");
yield addNewTabPageTab();

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

@ -8,7 +8,7 @@
function runTests() {
// we have a pinned link that didn't change its position since it was pinned.
// nothing should happend when we unpin it.
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",1");
yield addNewTabPageTab();
@ -20,7 +20,7 @@ function runTests() {
// we have a pinned link that is not anymore in the list of the most-visited
// links. this should disappear, the remaining links adjust their positions
// and a new link will appear at the end of the grid.
setLinks("0,1,2,3,4,5,6,7,8");
yield setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks(",99");
yield addNewTabPageTab();
@ -31,7 +31,7 @@ function runTests() {
// we have a pinned link that changed its position since it was pinned. it
// should be moved to its new position after being unpinned.
setLinks("0,1,2,3,4,5,6,7");
yield setLinks("0,1,2,3,4,5,6,7");
setPinnedLinks(",1,,,,,,,0");
yield addNewTabPageTab();
@ -45,7 +45,7 @@ function runTests() {
// we have pinned link that changed its position since it was pinned. the
// link will disappear from the grid because it's now a much lower priority
setLinks("0,1,2,3,4,5,6,7,8,9");
yield setLinks("0,1,2,3,4,5,6,7,8,9");
setPinnedLinks("9");
yield addNewTabPageTab();

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

@ -7,7 +7,17 @@ Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, true);
let tmp = {};
Cu.import("resource:///modules/NewTabUtils.jsm", tmp);
let NewTabUtils = tmp.NewTabUtils;
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://browser/content/sanitize.js", tmp);
let {NewTabUtils, Sanitizer} = tmp;
let uri = Services.io.newURI("about:newtab", null, null);
let principal = Services.scriptSecurityManager.getCodebasePrincipal(uri);
let sm = Services.domStorageManager;
let storage = sm.getLocalStorageForPrincipal(principal, "");
registerCleanupFunction(function () {
while (gBrowser.tabs.length > 1)
@ -16,11 +26,6 @@ registerCleanupFunction(function () {
Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED);
});
/**
* We'll want to restore the original links provider later.
*/
let originalProvider = NewTabUtils.links._provider;
/**
* Provide the default test function to start our test runner.
*/
@ -58,9 +63,7 @@ let TestRunner = {
*/
finish: function () {
function cleanupAndFinish() {
// Restore the old provider.
NewTabUtils.links._provider = originalProvider;
clearHistory();
whenPagesUpdated(finish);
NewTabUtils.restore();
}
@ -113,17 +116,52 @@ function getCell(aIndex) {
* @param aLinksPattern the pattern (see below)
*
* Example: setLinks("1,2,3")
* Result: [{url: "about:blank#1", title: "site#1"},
* {url: "about:blank#2", title: "site#2"}
* {url: "about:blank#3", title: "site#3"}]
* Result: [{url: "http://example.com/#1", title: "site#1"},
* {url: "http://example.com/#2", title: "site#2"}
* {url: "http://example.com/#3", title: "site#3"}]
*/
function setLinks(aLinksPattern) {
let links = aLinksPattern.split(/\s*,\s*/).map(function (id) {
return {url: "about:blank#" + id, title: "site#" + id};
});
function setLinks(aLinks) {
let links = aLinks;
NewTabUtils.links._provider = {getLinks: function (c) c(links)};
NewTabUtils.links._links = links;
if (typeof links == "string") {
links = aLinks.split(/\s*,\s*/).map(function (id) {
return {url: "http://example.com/#" + id, title: "site#" + id};
});
}
clearHistory();
fillHistory(links, function () {
NewTabUtils.links.populateCache(function () {
NewTabUtils.allPages.update();
TestRunner.next();
}, true);
});
}
function clearHistory() {
PlacesUtils.history.removeAllPages();
}
function fillHistory(aLinks, aCallback) {
let numLinks = aLinks.length;
let transitionLink = Ci.nsINavHistoryService.TRANSITION_LINK;
for (let link of aLinks.reverse()) {
let place = {
uri: makeURI(link.url),
title: link.title,
visits: [{visitDate: Date.now() * 1000, transitionType: transitionLink}]
};
PlacesUtils.asyncHistory.updatePlaces(place, {
handleError: function () ok(false, "couldn't add visit to history"),
handleResult: function () {},
handleCompletion: function () {
if (--numLinks == 0)
aCallback();
}
});
}
}
/**
@ -132,23 +170,22 @@ function setLinks(aLinksPattern) {
* @param aLinksPattern the pattern (see below)
*
* Example: setPinnedLinks("3,,1")
* Result: 'about:blank#3' is pinned in the first cell. 'about:blank#1' is
* Result: 'http://example.com/#3' is pinned in the first cell. 'http://example.com/#1' is
* pinned in the third cell.
*/
function setPinnedLinks(aLinksPattern) {
let pinnedLinks = [];
function setPinnedLinks(aLinks) {
let links = aLinks;
aLinksPattern.split(/\s*,\s*/).forEach(function (id, index) {
let link;
if (typeof links == "string") {
links = aLinks.split(/\s*,\s*/).map(function (id) {
if (id)
return {url: "http://example.com/#" + id, title: "site#" + id};
});
}
if (id)
link = {url: "about:blank#" + id, title: "site#" + id};
pinnedLinks[index] = link;
});
// Inject the list of pinned links to work with.
NewTabUtils.pinnedLinks._links = pinnedLinks;
storage.setItem("pinnedLinks", JSON.stringify(links));
NewTabUtils.pinnedLinks.resetCache();
NewTabUtils.allPages.update();
}
/**
@ -187,9 +224,9 @@ function addNewTabPageTab() {
* @param the array of sites to compare with (optional)
*
* Example: checkGrid("3p,2,,1p")
* Result: We expect the first cell to contain the pinned site 'about:blank#3'.
* The second cell contains 'about:blank#2'. The third cell is empty.
* The fourth cell contains the pinned site 'about:blank#4'.
* Result: We expect the first cell to contain the pinned site 'http://example.com/#3'.
* The second cell contains 'http://example.com/#2'. The third cell is empty.
* The fourth cell contains the pinned site 'http://example.com/#4'.
*/
function checkGrid(aSitesPattern, aSites) {
let length = aSitesPattern.split(",").length;
@ -205,7 +242,7 @@ function checkGrid(aSitesPattern, aSites) {
if (pinned != hasPinnedAttr)
ok(false, "invalid state (site.isPinned() != site[pinned])");
return aSite.url.replace(/^about:blank#(\d+)$/, "$1") + (pinned ? "p" : "");
return aSite.url.replace(/^http:\/\/example\.com\/#(\d+)$/, "$1") + (pinned ? "p" : "");
});
is(current, aSitesPattern, "grid status = " + aSitesPattern);
@ -246,7 +283,7 @@ function unpinCell(aIndex) {
function simulateDrop(aDropIndex, aDragIndex) {
let draggedSite;
let {gDrag: drag, gDrop: drop} = getContentWindow();
let event = createDragEvent("drop", "about:blank#99\nblank");
let event = createDragEvent("drop", "http://example.com/#99\nblank");
if (typeof aDragIndex != "undefined")
draggedSite = getCell(aDragIndex).site;

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

@ -272,11 +272,9 @@ function runTest(testNum) {
plainTextItems = ["context-back", false,
"context-forward", false,
"context-reload", true,
"context-stop", false,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"context-sendpage", true,
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@ -296,7 +294,6 @@ function runTest(testNum) {
"---", null,
"context-bookmarklink", true,
"context-savelink", true,
"context-sendlink", true,
"context-copylink", true
].concat(inspectItems));
closeContextMenu();
@ -430,11 +427,9 @@ function runTest(testNum) {
checkContextMenu(["context-back", false,
"context-forward", false,
"context-reload", true,
"context-stop", false,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"context-sendpage", true,
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@ -656,11 +651,9 @@ function runTest(testNum) {
"context-back", false,
"context-forward", false,
"context-reload", true,
"context-stop", false,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"context-sendpage", true,
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@ -691,11 +684,9 @@ function runTest(testNum) {
"context-back", false,
"context-forward", false,
"context-reload", true,
"context-stop", false,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"context-sendpage", true,
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@ -721,11 +712,9 @@ function runTest(testNum) {
checkContextMenu(["context-back", false,
"context-forward", false,
"context-reload", true,
"context-stop", false,
"---", null,
"context-bookmarkpage", true,
"context-savepage", true,
"context-sendpage", true,
"---", null,
"context-viewbgimage", false,
"context-selectall", true,
@ -764,7 +753,6 @@ function runTest(testNum) {
"---", null,
"context-bookmarklink", true,
"context-savelink", true,
"context-sendlink", true,
"context-copy", true,
"context-selectall", true,
"---", null,

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

@ -1,4 +1,4 @@
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# -*- Mode: javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# 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/.
@ -12,10 +12,17 @@ XPCOMUtils.defineLazyGetter(this, "BROWSER_NEW_TAB_URL", function () {
const TOPIC = "private-browsing-transition-complete";
function getNewTabPageURL() {
if (("gPrivateBrowsingUI" in window) && gPrivateBrowsingUI.privateWindow)
return "about:privatebrowsing";
else
return Services.prefs.getCharPref(PREF) || "about:blank";
if (("gPrivateBrowsingUI" in window) &&
!Services.prefs.prefHasUserValue(PREF)) {
// gPrivateBrowsingUI may not be initialized yet, in that case we'll
// update BROWSER_NEW_TAB_URL when it gets initialized.
if (!gPrivateBrowsingUI.initialized)
gPrivateBrowsingUI.addInitializationCallback(update);
else if (gPrivateBrowsingUI.privateWindow &&
!gPrivateBrowsingUI.autoStarted)
return "about:privatebrowsing";
}
return Services.prefs.getCharPref(PREF) || "about:blank";
}
function update() {

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

@ -9,6 +9,7 @@
#include "nsComponentManagerUtils.h"
#include "nsISimpleEnumerator.h"
#include "nsIFile.h"
#include "mozilla/Attributes.h"
#define NS_BROWSERDIRECTORYPROVIDER_CONTRACTID \
"@mozilla.org/browser/directory-provider;1"
@ -16,7 +17,7 @@
namespace mozilla {
namespace browser {
class DirectoryProvider : public nsIDirectoryServiceProvider2
class DirectoryProvider MOZ_FINAL : public nsIDirectoryServiceProvider2
{
public:
NS_DECL_ISUPPORTS
@ -24,7 +25,7 @@ public:
NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
private:
class AppendingEnumerator : public nsISimpleEnumerator
class AppendingEnumerator MOZ_FINAL : public nsISimpleEnumerator
{
public:
NS_DECL_ISUPPORTS

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

@ -51,7 +51,7 @@ const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
const URI_BUNDLE = "chrome://browser/locale/feeds/subscribe.properties";
const SUBSCRIBE_PAGE_URI = "chrome://browser/content/feeds/subscribe.xhtml";
const FEEDHANDLER_URI = "about:feeds";
const PREF_SELECTED_APP = "browser.feeds.handlers.application";
const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
@ -673,7 +673,7 @@ FeedWriter.prototype = {
*/
_getFileIconURL: function FW__getFileIconURL(file) {
var ios = Cc["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService);
getService(Ci.nsIIOService);
var fph = ios.getProtocolHandler("file")
.QueryInterface(Ci.nsIFileProtocolHandler);
var urlSpec = fph.getURLSpecFromFile(file);
@ -1089,10 +1089,9 @@ FeedWriter.prototype = {
getInterface(Ci.nsIWebNavigation).
QueryInterface(Ci.nsIDocShell).currentDocumentChannel;
var uri = makeURI(SUBSCRIBE_PAGE_URI);
var resolvedURI = Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIChromeRegistry).
convertChromeURL(uri);
var resolvedURI = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService).
newChannel(FEEDHANDLER_URI, null, null).URI;
if (resolvedURI.equals(chan.URI))
return chan.originalURI;

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

@ -7,8 +7,10 @@
#include "nsIContentSniffer.h"
#include "nsIStreamListener.h"
#include "nsStringAPI.h"
#include "mozilla/Attributes.h"
class nsFeedSniffer : public nsIContentSniffer, nsIStreamListener
class nsFeedSniffer MOZ_FINAL : public nsIContentSniffer,
nsIStreamListener
{
public:
NS_DECL_ISUPPORTS

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

@ -5,11 +5,12 @@
#include "nsCOMPtr.h"
#include "nsIPrivateBrowsingService.h"
#include "nsIObserver.h"
#include "mozilla/Attributes.h"
class nsIJSContextStack;
class nsPrivateBrowsingServiceWrapper : public nsIPrivateBrowsingService,
public nsIObserver
class nsPrivateBrowsingServiceWrapper MOZ_FINAL : public nsIPrivateBrowsingService,
public nsIObserver
{
public:
NS_DECL_ISUPPORTS

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

@ -12,8 +12,6 @@ function test() {
waitForExplicitFinish();
let tabBlank = gBrowser.selectedTab;
gBrowser.removeAllTabsBut(tabBlank);
let blankBrowser = gBrowser.getBrowserForTab(tabBlank);
blankBrowser.addEventListener("load", function() {
blankBrowser.removeEventListener("load", arguments.callee, true);

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

@ -2823,6 +2823,108 @@ let SessionStoreInternal = {
this._sendRestoreCompletedNotifications();
},
/**
* Sets the tabs restoring order with the following priority:
* Selected tab, pinned tabs, visible tabs, unhidden tabs and hidden tabs.
* @param aTabBrowser
* Tab browser object
* @param aTabs
* Array of tab references
* @param aTabData
* Array of tab data
* @param aSelectedTab
* Index of selected tab
*/
_setTabsRestoringOrder : function ssi__setTabsRestoringOrder(
aTabBrowser, aTabs, aTabData, aSelectedTab) {
// Temporally store the pinned tabs before moving the hidden tabs and
// optimizing the visible tabs. In case the selected tab is a pinned tab,
// the index is also stored.
let pinnedTabs = aTabData.filter(function (aData) aData.pinned).length;
let pinnedTabsArray = [];
let pinnedTabsDataArray = [];
let pinnedSelectedTab = null;
if (pinnedTabs && aTabs.length > 1) {
for (let t = aTabs.length - 1; t >= 0; t--) {
if (aTabData[t].pinned) {
pinnedTabsArray.unshift(aTabs.splice(t, 1)[0]);
pinnedTabsDataArray.unshift(aTabData.splice(t, 1)[0]);
if (aSelectedTab) {
if (aSelectedTab > (t + 1))
--aSelectedTab;
else if (aSelectedTab == (t + 1)) {
aSelectedTab = null;
pinnedSelectedTab = 1;
}
} else if (pinnedSelectedTab)
++pinnedSelectedTab;
}
}
}
// Without the pinned tabs, we move the hidden tabs to the end of the list
// and optimize the visible tabs.
let unhiddenTabs = aTabData.filter(function (aData) !aData.hidden).length;
if (unhiddenTabs && aTabs.length > 1) {
// Load hidden tabs last, by pushing them to the end of the list.
for (let t = 0, tabsToReorder = aTabs.length - unhiddenTabs; tabsToReorder > 0; ) {
if (aTabData[t].hidden) {
aTabs = aTabs.concat(aTabs.splice(t, 1));
aTabData = aTabData.concat(aTabData.splice(t, 1));
if (aSelectedTab && aSelectedTab > t)
--aSelectedTab;
--tabsToReorder;
continue;
}
++t;
}
// Determine if we can optimize & load visible tabs first
let maxVisibleTabs = Math.ceil(aTabBrowser.tabContainer.mTabstrip.scrollClientSize /
aTabs[unhiddenTabs - 1].getBoundingClientRect().width);
// Make sure we restore visible tabs first, if there are enough
if (aSelectedTab && maxVisibleTabs < unhiddenTabs && aSelectedTab > 1) {
let firstVisibleTab = 0;
if (unhiddenTabs - maxVisibleTabs > aSelectedTab) {
// aSelectedTab is leftmost since we scroll to it when possible
firstVisibleTab = aSelectedTab - 1;
} else {
// aSelectedTab is rightmost or no more room to scroll right
firstVisibleTab = unhiddenTabs - maxVisibleTabs;
}
aTabs = aTabs.splice(firstVisibleTab, maxVisibleTabs).concat(aTabs);
aTabData = aTabData.splice(firstVisibleTab, maxVisibleTabs).concat(aTabData);
aSelectedTab -= firstVisibleTab;
}
}
// Load the pinned tabs at the beginning of the list and restore the
// selected tab index.
if (pinnedTabsArray) {
// Restore the selected tab index.
if (pinnedSelectedTab) {
aSelectedTab = pinnedSelectedTab;
} else {
aSelectedTab += pinnedTabsArray.length;
}
// Load the pinned tabs at the beginning of the list.
for (let t = pinnedTabsArray.length - 1; t >= 0; t--) {
aTabs.unshift(pinnedTabsArray.splice(t, 1)[0]);
aTabData.unshift(pinnedTabsDataArray.splice(t, 1)[0]);
}
}
// Load the selected tab to the first position.
if (aSelectedTab-- && aTabs[aSelectedTab]) {
aTabs.unshift(aTabs.splice(aSelectedTab, 1)[0]);
aTabData.unshift(aTabData.splice(aSelectedTab, 1)[0]);
aTabBrowser.selectedTab = aTabs[0];
}
return [aTabs, aTabData];
},
/**
* Manage history restoration for a window
* @param aWindow
@ -2875,48 +2977,9 @@ let SessionStoreInternal = {
return;
}
let unhiddenTabs = aTabData.filter(function (aData) !aData.hidden).length;
if (unhiddenTabs && aTabs.length > 1) {
// Load hidden tabs last, by pushing them to the end of the list
for (let t = 0, tabsToReorder = aTabs.length - unhiddenTabs; tabsToReorder > 0; ) {
if (aTabData[t].hidden) {
aTabs = aTabs.concat(aTabs.splice(t, 1));
aTabData = aTabData.concat(aTabData.splice(t, 1));
if (aSelectTab > t)
--aSelectTab;
--tabsToReorder;
continue;
}
++t;
}
// Determine if we can optimize & load visible tabs first
let maxVisibleTabs = Math.ceil(tabbrowser.tabContainer.mTabstrip.scrollClientSize /
aTabs[unhiddenTabs - 1].getBoundingClientRect().width);
// make sure we restore visible tabs first, if there are enough
if (maxVisibleTabs < unhiddenTabs && aSelectTab > 1) {
let firstVisibleTab = 0;
if (unhiddenTabs - maxVisibleTabs > aSelectTab) {
// aSelectTab is leftmost since we scroll to it when possible
firstVisibleTab = aSelectTab - 1;
} else {
// aSelectTab is rightmost or no more room to scroll right
firstVisibleTab = unhiddenTabs - maxVisibleTabs;
}
aTabs = aTabs.splice(firstVisibleTab, maxVisibleTabs).concat(aTabs);
aTabData = aTabData.splice(firstVisibleTab, maxVisibleTabs).concat(aTabData);
aSelectTab -= firstVisibleTab;
}
}
// make sure to restore the selected tab first (if any)
if (aSelectTab-- && aTabs[aSelectTab]) {
aTabs.unshift(aTabs.splice(aSelectTab, 1)[0]);
aTabData.unshift(aTabData.splice(aSelectTab, 1)[0]);
tabbrowser.selectedTab = aTabs[0];
}
// Sets the tabs restoring order.
[aTabs, aTabData] =
this._setTabsRestoringOrder(tabbrowser, aTabs, aTabData, aSelectTab);
// Prepare the tabs so that they can be properly restored. We'll pin/unpin
// and show/hide tabs as necessary. We'll also set the labels, user typed

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

@ -8,15 +8,23 @@ function test() {
requestLongerTimeout(3);
// builds the tests state based on a few parameters
function buildTestState(num, selected, hidden) {
let state = { windows: [ { "tabs": [], "selected": selected } ] };
function buildTestState(num, selected, hidden, pinned) {
let state = { windows: [ { "tabs": [], "selected": selected + 1 } ] };
while (num--) {
state.windows[0].tabs.push({entries: [{url: "http://example.com/"}]});
state.windows[0].tabs.push({
entries: [
{ url: "http://example.com/?t=" + state.windows[0].tabs.length }
]
});
let i = state.windows[0].tabs.length - 1;
if (hidden.length > 0 && i == hidden[0]) {
state.windows[0].tabs[i].hidden = true;
hidden.splice(0, 1);
}
if (pinned.length > 0 && i == pinned[0]) {
state.windows[0].tabs[i].pinned = true;
pinned.splice(0, 1);
}
}
return state;
}
@ -24,56 +32,128 @@ function test() {
let tests = [
{ testNum: 1,
totalTabs: 13,
selectedTab: 1,
selectedTab: 0,
shownTabs: 6,
hiddenTabs: [],
pinnedTabs: [],
order: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
},
{ testNum: 2,
totalTabs: 13,
selectedTab: 13,
selectedTab: 12,
shownTabs: 6,
hiddenTabs: [],
pinnedTabs: [],
order: [12, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6]
},
{ testNum: 3,
totalTabs: 13,
selectedTab: 4,
selectedTab: 3,
shownTabs: 6,
hiddenTabs: [],
pinnedTabs: [],
order: [3, 4, 5, 6, 7, 8, 0, 1, 2, 9, 10, 11, 12]
},
{ testNum: 4,
totalTabs: 13,
selectedTab: 11,
selectedTab: 10,
shownTabs: 6,
hiddenTabs: [],
pinnedTabs: [],
order: [10, 7, 8, 9, 11, 12, 0, 1, 2, 3, 4, 5, 6]
},
{ testNum: 5,
totalTabs: 13,
selectedTab: 13,
selectedTab: 12,
shownTabs: 6,
hiddenTabs: [0, 4, 9],
pinnedTabs: [],
order: [12, 6, 7, 8, 10, 11, 1, 2, 3, 5, 0, 4, 9]
},
{ testNum: 6,
totalTabs: 13,
selectedTab: 4,
selectedTab: 3,
shownTabs: 6,
hiddenTabs: [1, 7, 12],
pinnedTabs: [],
order: [3, 4, 5, 6, 8, 9, 0, 2, 10, 11, 1, 7, 12]
},
{ testNum: 7,
totalTabs: 13,
selectedTab: 4,
selectedTab: 3,
shownTabs: 6,
hiddenTabs: [0, 1, 2],
pinnedTabs: [],
order: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2]
},
{ testNum: 8,
totalTabs: 13,
selectedTab: 0,
shownTabs: 6,
hiddenTabs: [],
pinnedTabs: [0],
order: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
},
{ testNum: 9,
totalTabs: 13,
selectedTab: 1,
shownTabs: 6,
hiddenTabs: [],
pinnedTabs: [0],
order: [1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
},
{ testNum: 10,
totalTabs: 13,
selectedTab: 3,
shownTabs: 6,
hiddenTabs: [2],
pinnedTabs: [0,1],
order: [3, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 2]
},
{ testNum: 11,
totalTabs: 13,
selectedTab: 12,
shownTabs: 6,
hiddenTabs: [],
pinnedTabs: [0,1,2],
order: [12, 0, 1, 2, 7, 8, 9, 10, 11, 3, 4, 5, 6]
},
{ testNum: 12,
totalTabs: 13,
selectedTab: 6,
shownTabs: 6,
hiddenTabs: [3,4,5],
pinnedTabs: [0,1,2],
order: [6, 0, 1, 2, 7, 8, 9, 10, 11, 12, 3, 4, 5]
},
{ testNum: 13,
totalTabs: 13,
selectedTab: 1,
shownTabs: 6,
hiddenTabs: [3,4,5],
pinnedTabs: [0,1,2],
order: [1, 0, 2, 6, 7, 8, 9, 10, 11, 12, 3, 4, 5]
},
{ testNum: 14,
totalTabs: 13,
selectedTab: 2,
shownTabs: 6,
hiddenTabs: [],
pinnedTabs: [0,1,2],
order: [2, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
},
{ testNum: 15,
totalTabs: 13,
selectedTab: 3,
shownTabs: 6,
hiddenTabs: [1,4],
pinnedTabs: [0,1,2],
order: [3, 0, 1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 4]
}
];
let tabMinWidth = parseInt(getComputedStyle(gBrowser.selectedTab, null).minWidth);
let tabMinWidth =
parseInt(getComputedStyle(gBrowser.selectedTab, null).minWidth);
let testIndex = 0;
function runNextTest() {
@ -84,41 +164,46 @@ function test() {
info ("Starting test " + (++testIndex));
let test = tests.shift();
let state = buildTestState(test.totalTabs, test.selectedTab, test.hiddenTabs);
let state = buildTestState(test.totalTabs, test.selectedTab,
test.hiddenTabs, test.pinnedTabs);
let tabbarWidth = Math.floor((test.shownTabs - 0.5) * tabMinWidth);
let win = openDialog(location, "_blank", "chrome,all,dialog=no");
let actualOrder = [];
let tabsRestored = [];
win.addEventListener("SSTabRestoring", function onSSTabRestoring(aEvent) {
let tab = aEvent.originalTarget;
let currentIndex = Array.indexOf(win.gBrowser.tabs, tab);
actualOrder.push(currentIndex);
let tabLink = tab.linkedBrowser.currentURI.spec;
let tabIndex =
tabLink.substring(tabLink.indexOf("?t=") + 3, tabLink.length);
if (actualOrder.length < state.windows[0].tabs.length)
// we need to compare with the tab's restoring index, no with the
// position index, since the pinned tabs change the positions in the
// tabbar.
tabsRestored.push(tabIndex);
if (tabsRestored.length < state.windows[0].tabs.length)
return;
// all of the tabs should be restoring or restored by now
is(actualOrder.length, state.windows[0].tabs.length,
is(tabsRestored.length, state.windows[0].tabs.length,
"Test #" + testIndex + ": Number of restored tabs is as expected");
is(actualOrder.join(" "), test.order.join(" "),
is(tabsRestored.join(" "), test.order.join(" "),
"Test #" + testIndex + ": 'visible' tabs restored first");
// Cleanup.
// cleanup
win.removeEventListener("SSTabRestoring", onSSTabRestoring, false);
win.close();
executeSoon(runNextTest);
}, false);
win.addEventListener("load", function onLoad(aEvent) {
win.removeEventListener("load", onLoad, false);
executeSoon(function () {
let extent = win.outerWidth - win.gBrowser.tabContainer.mTabstrip.scrollClientSize;
let windowWidth = tabbarWidth + extent;
win.resizeTo(windowWidth, win.outerHeight);
ss.setWindowState(win, JSON.stringify(state), true);
});
}, false);
whenWindowLoaded(win, function(aEvent) {
let extent =
win.outerWidth - win.gBrowser.tabContainer.mTabstrip.scrollClientSize;
let windowWidth = tabbarWidth + extent;
win.resizeTo(windowWidth, win.outerHeight);
ss.setWindowState(win, JSON.stringify(state), true);
});
};
runNextTest();

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

@ -41,9 +41,7 @@ let WindowEventHandler = {
// Sends an asynchronous message when the "onMozAfterPaint" event
// is fired.
onMozAfterPaint: function WEH_onMozAfterPaint(event) {
if (event.clientRects.length > 0) {
sendAsyncMessage("Panorama:MozAfterPaint");
}
sendAsyncMessage("Panorama:MozAfterPaint");
}
};

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

@ -2,7 +2,7 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --enable-codesighs
ac_add_options --enable-signmar
ac_add_options --enable-profiling
#ac_add_options --enable-profiling
# Nightlies only since this has a cost in performance
ac_add_options --enable-js-diagnostics

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

@ -1,5 +1,5 @@
[
{"clang_version": "r159409"},
{"clang_version": "r159509"},
{
"size": 47,
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
@ -7,8 +7,8 @@
"filename": "setup.sh"
},
{
"size": 74004324,
"digest": "c5bb558a5958458b11da385d57897a1f7e57a7be2f452438f6813cf1e9f2a4ce93769c36e304126f97dbd753732b70446c7fa3c779267e80152d7ac0175057fc",
"size": 74071397,
"digest": "390e499161e8b5e91c179f3352ecbb07431e3d5a190298de7f338b48fe3807f3ddbeca72d8df39d11f89864fb1135f14500471faa741d3886b875b8e2b1d4416",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}

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

@ -1,5 +1,5 @@
[
{"clang_version": "r159409"},
{"clang_version": "r159509"},
{
"size": 47,
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
@ -7,8 +7,8 @@
"filename": "setup.sh"
},
{
"size": 72533541,
"digest": "f092080caed28db1ed7d9f0612aef1d885d2587b4e069d3662af5c241950ee772b6bc249d766a47b4fe2c170a46cfe05010269a3cbc1123d1f4126bc182b7b40",
"size": 72518043,
"digest": "447dac319a8d7fa902cc065b758440bf6d4a7a98104362162fbdb0479a44d9b84c5878506f09be4398053a6ddc07935c7fb4f71e59b178073876fb5f90a45219",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}

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

@ -1,5 +1,5 @@
[
{"clang_version": "r159409"},
{"clang_version": "r159509"},
{
"size": 47,
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
@ -7,8 +7,8 @@
"filename": "setup.sh"
},
{
"size": 63604770,
"digest": "c664beadb01a4e8ba7f32698b3ef694ade9044a9117d90d57f1475f2cefea82d74d1b0f3da89dcb9932ba90e048ae3d908bff05ab09d0ce2c82731e949e62a47",
"size": 63679229,
"digest": "5257503e537b8d440b17e40aa06f0f70f1b124129c02f10e45b46ac642fc4170bfa77ae737a8bcac3ed7602ccd934a88cbe349986eb971d66a6fb553ae31f13c",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -46,270 +46,358 @@ registerCleanupFunction(function tearDown() {
* - browser/devtools/commandline/test/head.js
* - browser/devtools/shared/test/head.js
*/
let DeveloperToolbarTest = {
/**
* Paranoid DeveloperToolbar.show();
*/
show: function DTT_show(aCallback) {
if (DeveloperToolbar.visible) {
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
}
else {
DeveloperToolbar.show(aCallback);
}
},
let DeveloperToolbarTest = { };
/**
* Paranoid DeveloperToolbar.hide();
*/
hide: function DTT_hide() {
if (!DeveloperToolbar.visible) {
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
}
else {
DeveloperToolbar.display.inputter.setInput("");
DeveloperToolbar.hide();
}
},
/**
* Paranoid DeveloperToolbar.show();
*/
DeveloperToolbarTest.show = function DTT_show(aCallback) {
if (DeveloperToolbar.visible) {
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
}
else {
DeveloperToolbar.show(true, aCallback);
}
};
/**
* Check that we can parse command input.
* Doesn't execute the command, just checks that we grok the input properly:
*
* DeveloperToolbarTest.checkInputStatus({
* // Test inputs
* typed: "ech", // Required
* cursor: 3, // Optional cursor position
*
* // Thing to check
* status: "INCOMPLETE", // One of "VALID", "ERROR", "INCOMPLETE"
* emptyParameters: [ "<message>" ], // Still to type
* directTabText: "o", // Simple completion text
* arrowTabText: "", // When the completion is not an extension
* markup: "VVVIIIEEE", // What state should the error markup be in
* });
*/
checkInputStatus: function DTT_checkInputStatus(tests) {
let display = DeveloperToolbar.display;
/**
* Paranoid DeveloperToolbar.hide();
*/
DeveloperToolbarTest.hide = function DTT_hide() {
if (!DeveloperToolbar.visible) {
ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar");
}
else {
DeveloperToolbar.display.inputter.setInput("");
DeveloperToolbar.hide();
}
};
if (tests.typed) {
display.inputter.setInput(tests.typed);
}
else {
ok(false, "Missing typed for " + JSON.stringify(tests));
return;
}
/**
* check() is the new status. Similar API except that it doesn't attempt to
* alter the display/requisition at all, and it makes extra checks.
* Test inputs
* typed: The text to type at the input
* Available checks:
* input: The text displayed in the input field
* cursor: The position of the start of the cursor
* status: One of "VALID", "ERROR", "INCOMPLETE"
* emptyParameters: Array of parameters still to type. e.g. [ "<message>" ]
* directTabText: Simple completion text
* arrowTabText: When the completion is not an extension (without arrow)
* markup: What state should the error markup be in. e.g. "VVVIIIEEE"
* args: Maps of checks to make against the arguments:
* value: i.e. assignment.value (which ignores defaultValue)
* type: Argument/BlankArgument/MergedArgument/etc i.e. what's assigned
* Care should be taken with this since it's something of an
* implementation detail
* arg: The toString value of the argument
* status: i.e. assignment.getStatus
* message: i.e. assignment.getMessage
* name: For commands - checks assignment.value.name
*/
DeveloperToolbarTest.checkInputStatus = function DTT_checkInputStatus(checks) {
if (!checks.emptyParameters) {
checks.emptyParameters = [];
}
if (!checks.directTabText) {
checks.directTabText = '';
}
if (!checks.arrowTabText) {
checks.arrowTabText = '';
}
if (tests.cursor) {
display.inputter.setCursor(tests.cursor)
}
var display = DeveloperToolbar.display;
if (tests.status) {
is(display.requisition.getStatus().toString(),
tests.status, "status for " + tests.typed);
}
if (checks.typed) {
display.inputter.setInput(checks.typed);
}
else {
ok(false, "Missing typed for " + JSON.stringify(checks));
return;
}
if (tests.emptyParameters == null) {
tests.emptyParameters = [];
}
if (checks.cursor) {
display.inputter.setCursor(checks.cursor)
}
let realParams = display.completer.emptyParameters;
is(realParams.length, tests.emptyParameters.length,
'emptyParameters.length for \'' + tests.typed + '\'');
var cursor = checks.cursor ? checks.cursor.start : checks.typed.length;
if (realParams.length === tests.emptyParameters.length) {
for (let i = 0; i < realParams.length; i++) {
is(realParams[i].replace(/\u00a0/g, ' '), tests.emptyParameters[i],
'emptyParameters[' + i + '] for \'' + tests.typed + '\'');
var requisition = display.requisition;
var completer = display.completer;
var actual = completer._getCompleterTemplateData();
/*
if (checks.input) {
is(display.inputter.element.value,
checks.input,
'input');
}
if (checks.cursor) {
is(display.inputter.element.selectionStart,
checks.cursor,
'cursor');
}
*/
if (checks.status) {
is(requisition.getStatus().toString(),
checks.status,
'status');
}
if (checks.markup) {
var statusMarkup = requisition.getInputStatusMarkup(cursor);
var actualMarkup = statusMarkup.map(function(s) {
return Array(s.string.length + 1).join(s.status.toString()[0]);
}).join('');
is(checks.markup,
actualMarkup,
'markup');
}
if (checks.emptyParameters) {
var actualParams = actual.emptyParameters;
is(actualParams.length,
checks.emptyParameters.length,
'emptyParameters.length');
if (actualParams.length === checks.emptyParameters.length) {
for (var i = 0; i < actualParams.length; i++) {
is(actualParams[i].replace(/\u00a0/g, ' '),
checks.emptyParameters[i],
'emptyParameters[' + i + ']');
}
}
}
if (tests.directTabText) {
is(display.completer.directTabText, tests.directTabText,
'directTabText for \'' + tests.typed + '\'');
}
else {
is(display.completer.directTabText, '',
'directTabText for \'' + tests.typed + '\'');
}
if (checks.directTabText) {
is(actual.directTabText,
checks.directTabText,
'directTabText');
}
if (tests.arrowTabText) {
is(display.completer.arrowTabText, ' \u00a0\u21E5 ' + tests.arrowTabText,
'arrowTabText for \'' + tests.typed + '\'');
}
else {
is(display.completer.arrowTabText, '',
'arrowTabText for \'' + tests.typed + '\'');
}
if (checks.arrowTabText) {
is(actual.arrowTabText,
' \u00a0\u21E5 ' + checks.arrowTabText,
'arrowTabText');
}
if (tests.markup) {
let cursor = tests.cursor ? tests.cursor.start : tests.typed.length;
let statusMarkup = display.requisition.getInputStatusMarkup(cursor);
let actualMarkup = statusMarkup.map(function(s) {
return Array(s.string.length + 1).join(s.status.toString()[0]);
}).join('');
is(tests.markup, actualMarkup, 'markup for ' + tests.typed);
}
},
if (checks.args) {
Object.keys(checks.args).forEach(function(paramName) {
var check = checks.args[paramName];
/**
* Execute a command:
*
* DeveloperToolbarTest.exec({
* // Test inputs
* typed: "echo hi", // Optional, uses existing if undefined
*
* // Thing to check
* args: { message: "hi" }, // Check that the args were understood properly
* outputMatch: /^hi$/, // RegExp to test against textContent of output
* // (can also be array of RegExps)
* blankOutput: true, // Special checks when there is no output
* });
*/
exec: function DTT_exec(tests) {
tests = tests || {};
if (tests.typed) {
DeveloperToolbar.display.inputter.setInput(tests.typed);
}
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
let output = DeveloperToolbar.display.requisition.exec();
is(typed, output.typed, 'output.command for: ' + typed);
if (tests.completed !== false) {
ok(output.completed, 'output.completed false for: ' + typed);
}
else {
// It is actually an error if we say something is async and it turns
// out not to be? For now we're saying 'no'
// ok(!output.completed, 'output.completed true for: ' + typed);
}
if (tests.args != null) {
is(Object.keys(tests.args).length, Object.keys(output.args).length,
'arg count for ' + typed);
Object.keys(output.args).forEach(function(arg) {
let expectedArg = tests.args[arg];
let actualArg = output.args[arg];
if (typeof expectedArg === 'function') {
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
}
else {
if (Array.isArray(expectedArg)) {
if (!Array.isArray(actualArg)) {
ok(false, 'actual is not an array. ' + typed + '/' + arg);
return;
}
is(expectedArg.length, actualArg.length,
'array length: ' + typed + '/' + arg);
for (let i = 0; i < expectedArg.length; i++) {
is(expectedArg[i], actualArg[i],
'member: "' + typed + '/' + arg + '/' + i);
}
}
else {
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
}
}
});
}
let displayed = DeveloperToolbar.outputPanel._div.textContent;
if (tests.outputMatch) {
function doTest(match, against) {
if (!match.test(against)) {
ok(false, "html output for " + typed + " against " + match.source +
" (textContent sent to info)");
info("Actual textContent");
info(against);
}
}
if (Array.isArray(tests.outputMatch)) {
tests.outputMatch.forEach(function(match) {
doTest(match, displayed);
});
var assignment;
if (paramName === 'command') {
assignment = requisition.commandAssignment;
}
else {
doTest(tests.outputMatch, displayed);
}
}
if (tests.blankOutput != null) {
if (!/^$/.test(displayed)) {
ok(false, "html output for " + typed + " (textContent sent to info)");
info("Actual textContent");
info(displayed);
}
}
},
/**
* Quick wrapper around the things you need to do to run DeveloperToolbar
* command tests:
* - Set the pref 'devtools.toolbar.enabled' to true
* - Add a tab pointing at |uri|
* - Open the DeveloperToolbar
* - Register a cleanup function to undo the above
* - Run the tests
*
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
* @param testFunc A function containing the tests to run. This should
* arrange for 'finish()' to be called on completion.
*/
test: function DTT_test(uri, testFunc) {
let menuItem = document.getElementById("menu_devToolbar");
let command = document.getElementById("Tools:DevToolbar");
let appMenuItem = document.getElementById("appmenu_devToolbar");
registerCleanupFunction(function() {
DeveloperToolbarTest.hide();
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
if (menuItem) {
menuItem.hidden = true;
}
if (command) {
command.setAttribute("disabled", "true");
}
if (appMenuItem) {
appMenuItem.hidden = true;
assignment = requisition.getAssignment(paramName);
}
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
if (assignment == null) {
ok(false, 'Unknown parameter: ' + paramName);
return;
}
if (check.value) {
is(assignment.value,
check.value,
'checkStatus value for ' + paramName);
}
if (check.name) {
is(assignment.value.name,
check.name,
'checkStatus name for ' + paramName);
}
if (check.type) {
is(assignment.arg.type,
check.type,
'checkStatus type for ' + paramName);
}
if (check.arg) {
is(assignment.arg.toString(),
check.arg,
'checkStatus arg for ' + paramName);
}
if (check.status) {
is(assignment.getStatus().toString(),
check.status,
'checkStatus status for ' + paramName);
}
if (check.message) {
is(assignment.getMessage(),
check.message,
'checkStatus message for ' + paramName);
}
});
}
};
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
/**
* Execute a command:
*
* DeveloperToolbarTest.exec({
* // Test inputs
* typed: "echo hi", // Optional, uses existing if undefined
*
* // Thing to check
* args: { message: "hi" }, // Check that the args were understood properly
* outputMatch: /^hi$/, // RegExp to test against textContent of output
* // (can also be array of RegExps)
* blankOutput: true, // Special checks when there is no output
* });
*/
DeveloperToolbarTest.exec = function DTT_exec(tests) {
tests = tests || {};
if (tests.typed) {
DeveloperToolbar.display.inputter.setInput(tests.typed);
}
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
let output = DeveloperToolbar.display.requisition.exec();
is(typed, output.typed, 'output.command for: ' + typed);
if (tests.completed !== false) {
ok(output.completed, 'output.completed false for: ' + typed);
}
else {
// It is actually an error if we say something is async and it turns
// out not to be? For now we're saying 'no'
// ok(!output.completed, 'output.completed true for: ' + typed);
}
if (tests.args != null) {
is(Object.keys(tests.args).length, Object.keys(output.args).length,
'arg count for ' + typed);
Object.keys(output.args).forEach(function(arg) {
let expectedArg = tests.args[arg];
let actualArg = output.args[arg];
if (typeof expectedArg === 'function') {
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
}
else {
if (Array.isArray(expectedArg)) {
if (!Array.isArray(actualArg)) {
ok(false, 'actual is not an array. ' + typed + '/' + arg);
return;
}
is(expectedArg.length, actualArg.length,
'array length: ' + typed + '/' + arg);
for (let i = 0; i < expectedArg.length; i++) {
is(expectedArg[i], actualArg[i],
'member: "' + typed + '/' + arg + '/' + i);
}
}
else {
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
}
}
});
}
let displayed = DeveloperToolbar.outputPanel._div.textContent;
if (tests.outputMatch) {
function doTest(match, against) {
if (!match.test(against)) {
ok(false, "html output for " + typed + " against " + match.source +
" (textContent sent to info)");
info("Actual textContent");
info(against);
}
}
if (Array.isArray(tests.outputMatch)) {
tests.outputMatch.forEach(function(match) {
doTest(match, displayed);
});
}
else {
doTest(tests.outputMatch, displayed);
}
}
if (tests.blankOutput != null) {
if (!/^$/.test(displayed)) {
ok(false, "html output for " + typed + " (textContent sent to info)");
info("Actual textContent");
info(displayed);
}
}
};
/**
* Quick wrapper around the things you need to do to run DeveloperToolbar
* command tests:
* - Set the pref 'devtools.toolbar.enabled' to true
* - Add a tab pointing at |uri|
* - Open the DeveloperToolbar
* - Register a cleanup function to undo the above
* - Run the tests
*
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
* @param testFunc A function containing the tests to run. This should
* arrange for 'finish()' to be called on completion.
*/
DeveloperToolbarTest.test = function DTT_test(uri, testFunc) {
let menuItem = document.getElementById("menu_devToolbar");
let command = document.getElementById("Tools:DevToolbar");
let appMenuItem = document.getElementById("appmenu_devToolbar");
registerCleanupFunction(function() {
DeveloperToolbarTest.hide();
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
if (menuItem) {
menuItem.hidden = false;
menuItem.hidden = true;
}
if (command) {
command.removeAttribute("disabled");
command.setAttribute("disabled", "true");
}
if (appMenuItem) {
appMenuItem.hidden = false;
appMenuItem.hidden = true;
}
addTab(uri, function(browser, tab) {
DeveloperToolbarTest.show(function() {
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
});
try {
testFunc(browser, tab);
}
catch (ex) {
ok(false, "" + ex);
console.error(ex);
finish();
throw ex;
}
});
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
if (menuItem) {
menuItem.hidden = false;
}
if (command) {
command.removeAttribute("disabled");
}
if (appMenuItem) {
appMenuItem.hidden = false;
}
addTab(uri, function(browser, tab) {
DeveloperToolbarTest.show(function() {
try {
testFunc(browser, tab);
}
catch (ex) {
ok(false, "" + ex);
console.error(ex);
finish();
throw ex;
}
});
},
});
};

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

@ -552,8 +552,6 @@ StackFramesView.prototype = {
resume.setAttribute("tooltiptext", L10N.getStr("pauseTooltip"));
resume.removeAttribute("checked");
}
DebuggerView.Scripts.clearSearch();
},
/**

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

@ -101,7 +101,7 @@ var ScratchpadManager = {
}
let win = Services.ww.openWindow(null, SCRATCHPAD_WINDOW_URL, "_blank",
SCRATCHPAD_WINDOW_FEATURES, params);
// Only add shutdown observer if we've opened a scratchpad window
// Only add the shutdown observer if we've opened a scratchpad window.
ShutdownObserver.init();
return win;

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

@ -31,6 +31,7 @@ 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 PREF_RECENT_FILES_MAX = "devtools.scratchpad.recentFilesMax";
const BUTTON_POSITION_SAVE = 0;
const BUTTON_POSITION_CANCEL = 1;
const BUTTON_POSITION_DONT_SAVE = 2;
@ -160,7 +161,7 @@ var Scratchpad = {
* @param object aState
* An object with filename and executionContext properties.
*/
setState: function SP_getState(aState)
setState: function SP_setState(aState)
{
if (aState.filename) {
this.setFilename(aState.filename);
@ -615,19 +616,203 @@ var Scratchpad = {
/**
* Open a file to edit in the Scratchpad.
*
* @param integer aIndex
* Optional integer: clicked menuitem in the 'Open Recent'-menu.
*/
openFile: function SP_openFile()
openFile: function SP_openFile(aIndex)
{
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, this.strings.GetStringFromName("openFile.title"),
Ci.nsIFilePicker.modeOpen);
fp.defaultString = "";
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
this.setFilename(fp.file.path);
this.importFromFile(fp.file, false);
let fp;
if (!aIndex && aIndex !== 0) {
fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, this.strings.GetStringFromName("openFile.title"),
Ci.nsIFilePicker.modeOpen);
fp.defaultString = "";
}
if (aIndex > -1 || fp.show() != Ci.nsIFilePicker.returnCancel) {
this.promptSave(function(aCloseFile, aSaved, aStatus) {
let shouldOpen = aCloseFile;
if (aSaved && !Components.isSuccessCode(aStatus)) {
shouldOpen = false;
}
if (shouldOpen) {
this._skipClosePrompt = true;
let file;
if (fp) {
file = fp.file;
} else {
file = Components.classes["@mozilla.org/file/local;1"].
createInstance(Components.interfaces.nsILocalFile);
let filePath = this.getRecentFiles()[aIndex];
file.initWithPath(filePath);
}
this.setFilename(file.path);
this.importFromFile(file, false);
this.setRecentFile(file);
}
}.bind(this));
}
},
/**
* Get recent files.
*
* @return Array
* File paths.
*/
getRecentFiles: function SP_getRecentFiles()
{
let maxRecent = Services.prefs.getIntPref(PREF_RECENT_FILES_MAX);
let branch = Services.prefs.
getBranch("devtools.scratchpad.");
let filePaths = [];
if (branch.prefHasUserValue("recentFilePaths")) {
filePaths = JSON.parse(branch.getCharPref("recentFilePaths"));
}
return filePaths;
},
/**
* Save a recent file in a JSON parsable string.
*
* @param nsILocalFile aFile
* The nsILocalFile we want to save as a recent file.
*/
setRecentFile: function SP_setRecentFile(aFile)
{
let maxRecent = Services.prefs.getIntPref(PREF_RECENT_FILES_MAX);
if (maxRecent < 1) {
return;
}
let filePaths = this.getRecentFiles();
let filesCount = filePaths.length;
let pathIndex = filePaths.indexOf(aFile.path);
// We are already storing this file in the list of recent files.
if (pathIndex > -1) {
// If it's already the most recent file, we don't have to do anything.
if (pathIndex === (filesCount - 1)) {
// Updating the menu to clear the disabled state from the wrong menuitem
// in rare cases when two or more Scratchpad windows are open and the
// same file has been opened in two or more windows.
this.populateRecentFilesMenu();
return;
}
// It is not the most recent file. Remove it from the list, we add it as
// the most recent farther down.
filePaths.splice(pathIndex, 1);
}
// If we are not storing the file and the 'recent files'-list is full,
// remove the oldest file from the list.
else if (filesCount === maxRecent) {
filePaths.shift();
}
filePaths.push(aFile.path);
let branch = Services.prefs.
getBranch("devtools.scratchpad.");
branch.setCharPref("recentFilePaths", JSON.stringify(filePaths));
return;
},
/**
* Populates the 'Open Recent'-menu.
*/
populateRecentFilesMenu: function SP_populateRecentFilesMenu()
{
let maxRecent = Services.prefs.getIntPref(PREF_RECENT_FILES_MAX);
let recentFilesMenu = document.getElementById("sp-open_recent-menu");
if (maxRecent < 1) {
recentFilesMenu.setAttribute("hidden", true);
return;
}
let recentFilesPopup = recentFilesMenu.firstChild;
let filePaths = this.getRecentFiles();
let filename = this.getState().filename;
recentFilesMenu.setAttribute("disabled", true);
while (recentFilesPopup.hasChildNodes()) {
recentFilesPopup.removeChild(recentFilesPopup.firstChild);
}
if (filePaths.length > 0) {
recentFilesMenu.removeAttribute("disabled");
// Print out menuitems with the most recent file first.
for (let i = filePaths.length - 1; i >= 0; --i) {
let menuitem = document.createElement("menuitem");
menuitem.setAttribute("type", "radio");
menuitem.setAttribute("label", filePaths[i]);
if (filePaths[i] === filename) {
menuitem.setAttribute("checked", true);
menuitem.setAttribute("disabled", true);
}
menuitem.setAttribute("oncommand", "Scratchpad.openFile(" + i + ");");
recentFilesPopup.appendChild(menuitem);
}
recentFilesPopup.appendChild(document.createElement("menuseparator"));
let clearItems = document.createElement("menuitem");
clearItems.setAttribute("id", "sp-menu-clear_recent");
clearItems.setAttribute("label",
this.strings.
GetStringFromName("clearRecentMenuItems.label"));
clearItems.setAttribute("command", "sp-cmd-clearRecentFiles");
recentFilesPopup.appendChild(clearItems);
}
},
/**
* Clear all recent files.
*/
clearRecentFiles: function SP_clearRecentFiles()
{
Services.prefs.clearUserPref("devtools.scratchpad.recentFilePaths");
},
/**
* Handle changes to the 'PREF_RECENT_FILES_MAX'-preference.
*/
handleRecentFileMaxChange: function SP_handleRecentFileMaxChange()
{
let maxRecent = Services.prefs.getIntPref(PREF_RECENT_FILES_MAX);
let menu = document.getElementById("sp-open_recent-menu");
// Hide the menu if the 'PREF_RECENT_FILES_MAX'-pref is set to zero or less.
if (maxRecent < 1) {
menu.setAttribute("hidden", true);
} else {
if (menu.hasAttribute("hidden")) {
if (!menu.firstChild.hasChildNodes()) {
this.populateRecentFilesMenu();
}
menu.removeAttribute("hidden");
}
let filePaths = this.getRecentFiles();
if (maxRecent < filePaths.length) {
let branch = Services.prefs.
getBranch("devtools.scratchpad.");
let diff = filePaths.length - maxRecent;
filePaths.splice(0, diff);
branch.setCharPref("recentFilePaths", JSON.stringify(filePaths));
}
}
},
/**
* Save the textbox content to the currently open file.
*
@ -646,6 +831,7 @@ var Scratchpad = {
this.exportToFile(file, true, false, function(aStatus) {
if (Components.isSuccessCode(aStatus)) {
this.editor.dirty = false;
this.setRecentFile(file);
}
if (aCallback) {
aCallback(aStatus);
@ -671,6 +857,7 @@ var Scratchpad = {
this.exportToFile(fp.file, true, false, function(aStatus) {
if (Components.isSuccessCode(aStatus)) {
this.editor.dirty = false;
this.setRecentFile(fp.file);
}
if (aCallback) {
aCallback(aStatus);
@ -827,6 +1014,9 @@ var Scratchpad = {
this.initialized = true;
this._triggerObservers("Ready");
this.populateRecentFilesMenu();
PreferenceObserver.init();
},
/**
@ -887,6 +1077,8 @@ var Scratchpad = {
this.resetContext();
this.editor.removeEventListener(SourceEditor.EVENTS.DIRTY_CHANGED,
this._onDirtyChanged);
PreferenceObserver.uninit();
this.editor.destroy();
this.editor = null;
this.initialized = false;
@ -1063,6 +1255,48 @@ var Scratchpad = {
},
};
/**
* The PreferenceObserver listens for preference changes while Scratchpad is
* running.
*/
var PreferenceObserver = {
_initialized: false,
init: function PO_init()
{
if (this._initialized) {
return;
}
this.branch = Services.prefs.getBranch("devtools.scratchpad.");
this.branch.addObserver("", this, false);
this._initialized = true;
},
observe: function PO_observe(aMessage, aTopic, aData)
{
if (aTopic != "nsPref:changed") {
return;
}
if (aData == "recentFilesMax") {
Scratchpad.handleRecentFileMaxChange();
}
else if (aData == "recentFilePaths") {
Scratchpad.populateRecentFilesMenu();
}
},
uninit: function PO_uninit () {
if (!this.branch) {
return;
}
this.branch.removeObserver("", this);
this.branch = null;
}
};
XPCOMUtils.defineLazyGetter(Scratchpad, "strings", function () {
return Services.strings.createBundle(SCRATCHPAD_L10N);
});

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

@ -30,6 +30,7 @@
<commandset id="sp-commandset">
<command id="sp-cmd-newWindow" oncommand="Scratchpad.openScratchpad();"/>
<command id="sp-cmd-openFile" oncommand="Scratchpad.openFile();"/>
<command id="sp-cmd-clearRecentFiles" oncommand="Scratchpad.clearRecentFiles();"/>
<command id="sp-cmd-save" oncommand="Scratchpad.saveFile();"/>
<command id="sp-cmd-saveas" oncommand="Scratchpad.saveFileAs();"/>
@ -117,6 +118,11 @@
command="sp-cmd-openFile"
key="sp-key-open"
accesskey="&openFileCmd.accesskey;"/>
<menu id="sp-open_recent-menu" label="&openRecentMenu.label;"
accesskey="&openRecentMenu.accesskey;"
disabled="true">
<menupopup id="sp-menu-open_recentPopup"/>
</menu>
<menuitem id="sp-menu-save"
label="&saveFileCmd.label;"
accesskey="&saveFileCmd.accesskey;"

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

@ -32,6 +32,7 @@ _BROWSER_TEST_FILES = \
browser_scratchpad_bug650345_find_ui.js \
browser_scratchpad_bug714942_goto_line_ui.js \
browser_scratchpad_bug_650760_help_key.js \
browser_scratchpad_bug_651942_recent_files.js \
head.js \
libs:: $(_BROWSER_TEST_FILES)

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

@ -0,0 +1,314 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let tempScope = {};
Cu.import("resource://gre/modules/NetUtil.jsm", tempScope);
Cu.import("resource://gre/modules/FileUtils.jsm", tempScope);
let NetUtil = tempScope.NetUtil;
let FileUtils = tempScope.FileUtils;
// Reference to the Scratchpad object.
let gScratchpad;
// References to the temporary nsIFiles.
let gFile01;
let gFile02;
let gFile03;
let gFile04;
// lists of recent files.
var lists = {
recentFiles01: null,
recentFiles02: null,
recentFiles03: null,
recentFiles04: null,
};
// Temporary file names.
let gFileName01 = "file01_ForBug651942.tmp"
let gFileName02 = "file02_ForBug651942.tmp"
let gFileName03 = "file03_ForBug651942.tmp"
let gFileName04 = "file04_ForBug651942.tmp"
// Content for the temporary files.
let gFileContent;
let gFileContent01 = "hello.world.01('bug651942');";
let gFileContent02 = "hello.world.02('bug651942');";
let gFileContent03 = "hello.world.03('bug651942');";
let gFileContent04 = "hello.world.04('bug651942');";
function startTest()
{
gScratchpad = gScratchpadWindow.Scratchpad;
gFile01 = createAndLoadTemporaryFile(gFile01, gFileName01, gFileContent01);
gFile02 = createAndLoadTemporaryFile(gFile02, gFileName02, gFileContent02);
gFile03 = createAndLoadTemporaryFile(gFile03, gFileName03, gFileContent03);
}
// Test to see if the three files we created in the 'startTest()'-method have
// been added to the list of recent files.
function testAddedToRecent()
{
lists.recentFiles01 = gScratchpad.getRecentFiles();
is(lists.recentFiles01.length, 3,
"Temporary files created successfully and added to list of recent files.");
// Create a 4th file, this should clear the oldest file.
gFile04 = createAndLoadTemporaryFile(gFile04, gFileName04, gFileContent04);
}
// We have opened a 4th file. Test to see if the oldest recent file was removed,
// and that the other files were reordered successfully.
function testOverwriteRecent()
{
lists.recentFiles02 = gScratchpad.getRecentFiles();
is(lists.recentFiles02[0], lists.recentFiles01[1],
"File02 was reordered successfully in the 'recent files'-list.");
is(lists.recentFiles02[1], lists.recentFiles01[2],
"File03 was reordered successfully in the 'recent files'-list.");
isnot(lists.recentFiles02[2], lists.recentFiles01[2],
"File04: was added successfully.");
// Open the oldest recent file.
gScratchpad.openFile(0);
}
// We have opened the "oldest"-recent file. Test to see if it is now the most
// recent file, and that the other files were reordered successfully.
function testOpenOldestRecent()
{
lists.recentFiles03 = gScratchpad.getRecentFiles();
is(lists.recentFiles02[0], lists.recentFiles03[2],
"File04 was reordered successfully in the 'recent files'-list.");
is(lists.recentFiles02[1], lists.recentFiles03[0],
"File03 was reordered successfully in the 'recent files'-list.");
is(lists.recentFiles02[2], lists.recentFiles03[1],
"File02 was reordered successfully in the 'recent files'-list.");
Services.prefs.setIntPref("devtools.scratchpad.recentFilesMax", 0);
}
// The "devtools.scratchpad.recentFilesMax"-preference was set to zero (0).
// This should disable the "Open Recent"-menu by hiding it (this should not
// remove any files from the list). Test to see if it's been hidden.
function testHideMenu()
{
let menu = gScratchpadWindow.document.getElementById("sp-open_recent-menu");
ok(menu.hasAttribute("hidden"), "The menu was hidden successfully.");
Services.prefs.setIntPref("devtools.scratchpad.recentFilesMax", 1);
}
// We have set the recentFilesMax-pref to one (1), this enables the feature,
// removes the two oldest files, rebuilds the menu and removes the
// "hidden"-attribute from it. Test to see if this works.
function testChangedMaxRecent()
{
let menu = gScratchpadWindow.document.getElementById("sp-open_recent-menu");
ok(!menu.hasAttribute("hidden"), "The menu is visible. \\o/");
lists.recentFiles04 = gScratchpad.getRecentFiles();
is(lists.recentFiles04.length, 1,
"Two recent files were successfully removed from the 'recent files'-list");
let doc = gScratchpadWindow.document;
let popup = doc.getElementById("sp-menu-open_recentPopup");
let menuitemLabel = popup.children[0].getAttribute("label");
let correctMenuItem = false;
if (menuitemLabel === lists.recentFiles03[2] &&
menuitemLabel === lists.recentFiles04[0]) {
correctMenuItem = true;
}
is(correctMenuItem, true,
"Two recent files were successfully removed from the 'Open Recent'-menu");
gScratchpad.clearRecentFiles();
}
// We have cleared the last file. Test to see if the last file was removed,
// the menu is empty and was disabled successfully.
function testClearedAll()
{
let doc = gScratchpadWindow.document;
let menu = doc.getElementById("sp-open_recent-menu");
let popup = doc.getElementById("sp-menu-open_recentPopup");
is(gScratchpad.getRecentFiles().length, 0,
"All recent files removed successfully.");
is(popup.children.length, 0, "All menuitems removed successfully.");
ok(menu.hasAttribute("disabled"),
"No files in the menu, it was disabled successfully.");
finishTest();
}
function createAndLoadTemporaryFile(aFile, aFileName, aFileContent)
{
// Create a temporary file.
aFile = FileUtils.getFile("TmpD", [aFileName]);
aFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
// Write the temporary file.
let fout = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
fout.init(aFile.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20,
0644, fout.DEFER_OPEN);
gScratchpad.setFilename(aFile.path);
gScratchpad.importFromFile(aFile.QueryInterface(Ci.nsILocalFile), true,
fileImported);
gScratchpad.saveFile(fileSaved);
return aFile;
}
function fileImported(aStatus)
{
ok(Components.isSuccessCode(aStatus),
"the temporary file was imported successfully with Scratchpad");
}
function fileSaved(aStatus)
{
ok(Components.isSuccessCode(aStatus),
"the temporary file was saved successfully with Scratchpad");
checkIfMenuIsPopulated();
}
function checkIfMenuIsPopulated()
{
let doc = gScratchpadWindow.document;
let expectedMenuitemCount = doc.getElementById("sp-menu-open_recentPopup").
children.length;
// The number of recent files stored, plus the separator and the
// clearRecentMenuItems-item.
let recentFilesPlusExtra = gScratchpad.getRecentFiles().length + 2;
if (expectedMenuitemCount > 2) {
is(expectedMenuitemCount, recentFilesPlusExtra,
"the recent files menu was populated successfully.");
}
}
/**
* The PreferenceObserver listens for preference changes while Scratchpad is
* running.
*/
var PreferenceObserver = {
_initialized: false,
_timesFired: 0,
set timesFired(aNewValue) {
this._timesFired = aNewValue;
},
get timesFired() {
return this._timesFired;
},
init: function PO_init()
{
if (this._initialized) {
return;
}
this.branch = Services.prefs.getBranch("devtools.scratchpad.");
this.branch.addObserver("", this, false);
this._initialized = true;
},
observe: function PO_observe(aMessage, aTopic, aData)
{
if (aTopic != "nsPref:changed") {
return;
}
switch (this.timesFired) {
case 0:
this.timesFired = 1;
break;
case 1:
this.timesFired = 2;
break;
case 2:
this.timesFired = 3;
testAddedToRecent();
break;
case 3:
this.timesFired = 4;
testOverwriteRecent();
break;
case 4:
this.timesFired = 5;
testOpenOldestRecent();
break;
case 5:
this.timesFired = 6;
testHideMenu();
break;
case 6:
this.timesFired = 7;
testChangedMaxRecent();
break;
case 7:
this.timesFired = 8;
testClearedAll();
break;
}
},
uninit: function PO_uninit () {
this.branch.removeObserver("", this);
}
};
function test()
{
waitForExplicitFinish();
registerCleanupFunction(function () {
gFile01.remove(false);
gFile01 = null;
gFile02.remove(false);
gFile02 = null;
gFile03.remove(false);
gFile03 = null;
gFile04.remove(false);
gFile04 = null;
lists.recentFiles01 = null;
lists.recentFiles02 = null;
lists.recentFiles03 = null;
lists.recentFiles04 = null;
gScratchpad = null;
PreferenceObserver.uninit();
Services.prefs.clearUserPref("devtools.scratchpad.recentFilesMax");
});
Services.prefs.setIntPref("devtools.scratchpad.recentFilesMax", 3);
// Initiate the preference observer after we have set the temporary recent
// files max for this test.
PreferenceObserver.init();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
openScratchpad(startTest);
}, true);
content.location = "data:text/html,<p>test recent files in Scratchpad";
}
function finishTest()
{
finish();
}

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

@ -43,7 +43,6 @@ function DeveloperToolbar(aChromeWindow, aToolbarElement)
this._errorsCount = {};
this._webConsoleButton = this._doc
.getElementById("developer-toolbar-webconsole");
this._webConsoleButtonLabel = this._webConsoleButton.label;
try {
GcliCommands.refreshAutoCommands(aChromeWindow);
@ -107,7 +106,7 @@ DeveloperToolbar.prototype.toggle = function DT_toggle()
if (this.visible) {
this.hide();
} else {
this.show();
this.show(true);
}
};
@ -124,7 +123,7 @@ DeveloperToolbar.introShownThisSession = false;
* @param aCallback show events can be asynchronous. If supplied aCallback will
* be called when the DeveloperToolbar is visible
*/
DeveloperToolbar.prototype.show = function DT_show(aCallback)
DeveloperToolbar.prototype.show = function DT_show(aFocus, aCallback)
{
if (this._lastState != NOTIFICATIONS.HIDE) {
return;
@ -139,7 +138,7 @@ DeveloperToolbar.prototype.show = function DT_show(aCallback)
let checkLoad = function() {
if (this.tooltipPanel && this.tooltipPanel.loaded &&
this.outputPanel && this.outputPanel.loaded) {
this._onload();
this._onload(aFocus);
}
}.bind(this);
@ -152,7 +151,7 @@ DeveloperToolbar.prototype.show = function DT_show(aCallback)
* Initializing GCLI can only be done when we've got content windows to write
* to, so this needs to be done asynchronously.
*/
DeveloperToolbar.prototype._onload = function DT_onload()
DeveloperToolbar.prototype._onload = function DT_onload(aFocus)
{
this._doc.getElementById("Tools:DevToolbar").setAttribute("checked", "true");
@ -179,6 +178,9 @@ DeveloperToolbar.prototype._onload = function DT_onload()
scratchpad: null
});
this.display.focusManager.addMonitoredElement(this.outputPanel._frame);
this.display.focusManager.addMonitoredElement(this._element);
this.display.onVisibilityChange.add(this.outputPanel._visibilityChanged, this.outputPanel);
this.display.onVisibilityChange.add(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
this.display.onOutput.add(this.outputPanel._outputChanged, this.outputPanel);
@ -187,12 +189,14 @@ DeveloperToolbar.prototype._onload = function DT_onload()
this._chromeWindow.getBrowser().tabContainer.addEventListener("TabClose", this, false);
this._chromeWindow.getBrowser().addEventListener("load", this, true);
this._chromeWindow.getBrowser().addEventListener("beforeunload", this, true);
this._chromeWindow.addEventListener("resize", this, false);
this._initErrorsCount(this._chromeWindow.getBrowser().selectedTab);
this._element.hidden = false;
this._input.focus();
if (aFocus) {
this._input.focus();
}
this._notify(NOTIFICATIONS.SHOW);
if (this._pendingShowCallback) {
@ -307,11 +311,13 @@ DeveloperToolbar.prototype.destroy = function DT_destroy()
this._chromeWindow.getBrowser().tabContainer.removeEventListener("TabSelect", this, false);
this._chromeWindow.getBrowser().removeEventListener("load", this, true);
this._chromeWindow.getBrowser().removeEventListener("beforeunload", this, true);
this._chromeWindow.removeEventListener("resize", this, false);
let tabs = this._chromeWindow.getBrowser().tabs;
Array.prototype.forEach.call(tabs, this._stopErrorsCount, this);
this.display.focusManager.removeMonitoredElement(this.outputPanel._frame);
this.display.focusManager.removeMonitoredElement(this._element);
this.display.onVisibilityChange.remove(this.outputPanel._visibilityChanged, this.outputPanel);
this.display.onVisibilityChange.remove(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
this.display.onOutput.remove(this.outputPanel._outputChanged, this.outputPanel);
@ -368,9 +374,6 @@ DeveloperToolbar.prototype.handleEvent = function DT_handleEvent(aEvent)
}
}
}
else if (aEvent.type == "resize") {
this.outputPanel._resize();
}
else if (aEvent.type == "TabClose") {
this._stopErrorsCount(aEvent.target);
}
@ -498,11 +501,9 @@ function DT__updateErrorsCount(aChangedTabId)
let errors = this._errorsCount[tabId];
if (errors) {
this._webConsoleButton.label =
this._webConsoleButtonLabel + " (" + errors + ")";
}
else {
this._webConsoleButton.label = this._webConsoleButtonLabel;
this._webConsoleButton.setAttribute("error-count", errors);
} else {
this._webConsoleButton.removeAttribute("error-count");
}
};
@ -812,7 +813,7 @@ TooltipPanel.prototype._resize = function TP_resize()
}
let offset = 10 + Math.floor(this._dimensions.start * AVE_CHAR_WIDTH);
this._frame.style.marginLeft = offset + "px";
this._panel.style.marginLeft = offset + "px";
/*
// Bug 744906: UX review - Not sure if we want this code to fatten connector

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

@ -40,6 +40,6 @@ function runTest() {
}
function getLeftMargin() {
let style = DeveloperToolbar.tooltipPanel._frame.style.marginLeft;
let style = DeveloperToolbar.tooltipPanel._panel.style.marginLeft;
return parseInt(style.slice(0, -2), 10);
}

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

@ -29,8 +29,8 @@ function test() {
addTab(TEST_URI, openToolbar);
function getErrorsCount() {
let match = webconsole.label.match(/\((\d+)\)$/);
return match ? match[1] : 0;
let count = webconsole.getAttribute("error-count");
return count ? count : "0";
}
function onOpenToolbar() {

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

@ -52,7 +52,7 @@ let DeveloperToolbarTest = {
ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar");
}
else {
DeveloperToolbar.show(aCallback);
DeveloperToolbar.show(true, aCallback);
}
},

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

@ -161,6 +161,7 @@
@BINPATH@/components/dom.xpt
@BINPATH@/components/dom_apps.xpt
@BINPATH@/components/dom_base.xpt
@BINPATH@/components/dom_system.xpt
#ifdef MOZ_B2G_RIL
@BINPATH@/components/dom_telephony.xpt
@BINPATH@/components/dom_wifi.xpt
@ -172,6 +173,7 @@
#endif
@BINPATH@/components/dom_canvas.xpt
@BINPATH@/components/dom_contacts.xpt
@BINPATH@/components/dom_alarm.xpt
@BINPATH@/components/dom_core.xpt
@BINPATH@/components/dom_css.xpt
@BINPATH@/components/dom_devicestorage.xpt
@ -217,6 +219,7 @@
@BINPATH@/components/gfx.xpt
@BINPATH@/components/html5.xpt
@BINPATH@/components/htmlparser.xpt
@BINPATH@/components/identity.xpt
@BINPATH@/components/imglib2.xpt
@BINPATH@/components/imgicon.xpt
@BINPATH@/components/inspector.xpt
@ -471,6 +474,8 @@
@BINPATH@/components/ContactManager.js
@BINPATH@/components/ContactManager.manifest
@BINPATH@/components/AlarmsManager.js
@BINPATH@/components/AlarmsManager.manifest
#ifdef ENABLE_MARIONETTE
@BINPATH@/chrome/marionette@JAREXT@
@BINPATH@/chrome/marionette.manifest

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