diff --git a/.hgtags b/.hgtags index 0b8e3d04940f..614c3e6a4db5 100644 --- a/.hgtags +++ b/.hgtags @@ -62,3 +62,4 @@ b70744835d94e54eec97b8fd186c96da5708a506 PRE_MOBILE_MERGE_20110406 a71bd564ebf5bf4f93d13e84114f759c263130b0 MOBILE_MERGE_DONE a71bd564ebf5bf4f93d13e84114f759c263130b0 MOBILE_MERGE_DONE_20110406 a95d426422816513477e5863add1b00ac7041dcb AURORA_BASE_20110412 +138f593553b66c9f815e8f57870c19d6347f7702 UPDATE_PACKAGING_R14 diff --git a/Makefile.in b/Makefile.in index f5fe8ec2bde6..11375517c040 100644 --- a/Makefile.in +++ b/Makefile.in @@ -162,7 +162,7 @@ ifdef MOZ_SYMBOLS_EXTRA_BUILDID EXTRA_BUILDID := -$(MOZ_SYMBOLS_EXTRA_BUILDID) endif -export SYMBOL_INDEX_NAME = \ +SYMBOL_INDEX_NAME = \ $(MOZ_APP_NAME)-$(MOZ_APP_VERSION)-$(OS_TARGET)-$(BUILDID)$(EXTRA_BUILDID)-symbols.txt buildsymbols: @@ -194,7 +194,7 @@ endif # MOZ_CRASHREPORTER uploadsymbols: ifdef MOZ_CRASHREPORTER - $(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh "$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip" + $(SHELL) $(topsrcdir)/toolkit/crashreporter/tools/upload_symbols.sh $(SYMBOL_INDEX_NAME) "$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip" endif # defined in package-name.mk diff --git a/accessible/src/atk/nsAccessibleWrap.cpp b/accessible/src/atk/nsAccessibleWrap.cpp index 19b6bc3f5212..2bd95a470f83 100644 --- a/accessible/src/atk/nsAccessibleWrap.cpp +++ b/accessible/src/atk/nsAccessibleWrap.cpp @@ -341,9 +341,7 @@ void nsAccessibleWrap::SetMaiHyperlink(MaiHyperlink* aMaiHyperlink) if (!maiHyperlink && !aMaiHyperlink) { return; // Never set and we're shutting down } - if (maiHyperlink) { - delete maiHyperlink; - } + delete maiHyperlink; g_object_set_qdata(G_OBJECT(mAtkObject), quark_mai_hyperlink, aMaiHyperlink); } diff --git a/accessible/src/base/nsAccDocManager.h b/accessible/src/base/nsAccDocManager.h index 4fd523653921..1bd5256c5540 100644 --- a/accessible/src/base/nsAccDocManager.h +++ b/accessible/src/base/nsAccDocManager.h @@ -199,23 +199,32 @@ private: printf("uri: %s", spec); #define NS_LOG_ACCDOC_TYPE(aDocument) \ - PRBool isContent = nsCoreUtils::IsContentDocument(aDocument); \ - printf("%s document", (isContent ? "content" : "chrome")); + if (aDocument->IsActive()) { \ + PRBool isContent = nsCoreUtils::IsContentDocument(aDocument); \ + printf("%s document", (isContent ? "content" : "chrome")); \ + } else { \ + printf("document type: [failed]"); \ + } #define NS_LOG_ACCDOC_SHELLSTATE(aDocument) \ - nsCOMPtr container = aDocument->GetContainer(); \ - nsCOMPtr docShell = do_QueryInterface(container); \ - PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE; \ - docShell->GetBusyFlags(&busyFlags); \ nsCAutoString docShellBusy; \ - if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) \ - docShellBusy.AppendLiteral("'none'"); \ - if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY) \ - docShellBusy.AppendLiteral("'busy'"); \ - if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD) \ - docShellBusy.AppendLiteral(", 'before page load'"); \ - if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) \ - docShellBusy.AppendLiteral(", 'page loading'"); \ + nsCOMPtr container = aDocument->GetContainer(); \ + if (container) { \ + nsCOMPtr docShell = do_QueryInterface(container); \ + PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE; \ + docShell->GetBusyFlags(&busyFlags); \ + if (busyFlags == nsIDocShell::BUSY_FLAGS_NONE) \ + docShellBusy.AppendLiteral("'none'"); \ + if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY) \ + docShellBusy.AppendLiteral("'busy'"); \ + if (busyFlags & nsIDocShell::BUSY_FLAGS_BEFORE_PAGE_LOAD) \ + docShellBusy.AppendLiteral(", 'before page load'"); \ + if (busyFlags & nsIDocShell::BUSY_FLAGS_PAGE_LOADING) \ + docShellBusy.AppendLiteral(", 'page loading'"); \ + } \ + else { \ + docShellBusy.AppendLiteral("[failed]"); \ + } \ printf("docshell busy: %s", docShellBusy.get()); #define NS_LOG_ACCDOC_DOCSTATES(aDocument) \ @@ -336,20 +345,22 @@ private: printf(" "); \ NS_LOG_ACCDOC_ADDRESS(aDocument, aDocAcc) \ printf("\n "); \ - NS_LOG_ACCDOC_URI(aDocument) \ - printf("\n "); \ - NS_LOG_ACCDOC_SHELLSTATE(aDocument) \ - printf("; "); \ - NS_LOG_ACCDOC_TYPE(aDocument) \ - printf("\n "); \ - NS_LOG_ACCDOC_DOCSTATES(aDocument) \ - printf("\n "); \ - NS_LOG_ACCDOC_DOCPRESSHELL(aDocument) \ - printf("\n "); \ - NS_LOG_ACCDOC_DOCLOADGROUP(aDocument) \ - printf(", "); \ - NS_LOG_ACCDOC_DOCPARENT(aDocument) \ - printf("\n"); \ + if (aDocument) { \ + NS_LOG_ACCDOC_URI(aDocument) \ + printf("\n "); \ + NS_LOG_ACCDOC_SHELLSTATE(aDocument) \ + printf("; "); \ + NS_LOG_ACCDOC_TYPE(aDocument) \ + printf("\n "); \ + NS_LOG_ACCDOC_DOCSTATES(aDocument) \ + printf("\n "); \ + NS_LOG_ACCDOC_DOCPRESSHELL(aDocument) \ + printf("\n "); \ + NS_LOG_ACCDOC_DOCLOADGROUP(aDocument) \ + printf(", "); \ + NS_LOG_ACCDOC_DOCPARENT(aDocument) \ + printf("\n"); \ + } \ } #define NS_LOG_ACCDOC_DOCINFO_END \ printf(" }\n"); diff --git a/accessible/src/base/nsAccTreeWalker.cpp b/accessible/src/base/nsAccTreeWalker.cpp index ba2f6297b7fe..da2b0d696320 100644 --- a/accessible/src/base/nsAccTreeWalker.cpp +++ b/accessible/src/base/nsAccTreeWalker.cpp @@ -67,7 +67,7 @@ struct WalkState nsAccTreeWalker:: nsAccTreeWalker(nsIWeakReference* aShell, nsIContent* aContent, PRBool aWalkAnonContent, bool aWalkCache) : - mWeakShell(aShell), mState(nsnull), mWalkCache(aWalkCache) + mWeakShell(aShell), mWalkCache(aWalkCache), mState(nsnull) { NS_ASSERTION(aContent, "No node for the accessible tree walker!"); diff --git a/accessible/src/base/nsAccUtils.cpp b/accessible/src/base/nsAccUtils.cpp index fbb4e1d491c6..e588945b0cdf 100644 --- a/accessible/src/base/nsAccUtils.cpp +++ b/accessible/src/base/nsAccUtils.cpp @@ -160,7 +160,8 @@ nsAccUtils::GetPositionAndSizeForXULSelectControlItem(nsIContent *aContent, control->GetItemAtIndex(index, getter_AddRefs(currItem)); nsCOMPtr currNode(do_QueryInterface(currItem)); - nsAccessible* itemAcc = GetAccService()->GetAccessible(currNode); + nsAccessible* itemAcc = currNode ? + GetAccService()->GetAccessible(currNode) : nsnull; if (!itemAcc || itemAcc->State() & states::INVISIBLE) { (*aSetSize)--; @@ -201,7 +202,8 @@ nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIContent *aContent, container->GetItemAtIndex(index, getter_AddRefs(item)); nsCOMPtr itemNode(do_QueryInterface(item)); - nsAccessible* itemAcc = GetAccService()->GetAccessible(itemNode); + nsAccessible* itemAcc = itemNode ? + GetAccService()->GetAccessible(itemNode) : nsnull; if (itemAcc) { PRUint32 itemRole = Role(itemAcc); @@ -220,8 +222,9 @@ nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIContent *aContent, nsCOMPtr item; container->GetItemAtIndex(index, getter_AddRefs(item)); nsCOMPtr itemNode(do_QueryInterface(item)); - - nsAccessible* itemAcc = GetAccService()->GetAccessible(itemNode); + + nsAccessible* itemAcc = + itemNode ? GetAccService()->GetAccessible(itemNode) : nsnull; if (itemAcc) { PRUint32 itemRole = Role(itemAcc); diff --git a/accessible/src/base/nsAccessNode.h b/accessible/src/base/nsAccessNode.h index f7ba055282d3..0f902f3db47f 100644 --- a/accessible/src/base/nsAccessNode.h +++ b/accessible/src/base/nsAccessNode.h @@ -171,7 +171,7 @@ public: nsINode* node = GetNode(); return node && node->IsElement(); } - PRBool IsDocument() const + bool IsDocumentNode() const { return GetNode() && GetNode()->IsNodeOfType(nsINode::eDOCUMENT); } diff --git a/accessible/src/base/nsAccessibilityService.cpp b/accessible/src/base/nsAccessibilityService.cpp index 23688b6936a5..92d9083a6388 100644 --- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -68,7 +68,7 @@ #include "nsImageFrame.h" #include "nsILink.h" #include "nsIObserverService.h" -#include "nsIPluginInstance.h" +#include "nsNPAPIPluginInstance.h" #include "nsISupportsUtils.h" #include "nsObjectFrame.h" #include "nsOuterDocAccessible.h" @@ -346,8 +346,8 @@ nsAccessibilityService::CreateHTMLObjectFrameAccessible(nsObjectFrame* aFrame, #if defined(XP_WIN) || defined(MOZ_ACCESSIBILITY_ATK) // 2) for plugins - nsCOMPtr pluginInstance; - if (NS_SUCCEEDED(aFrame->GetPluginInstance(*getter_AddRefs(pluginInstance))) && + nsRefPtr pluginInstance; + if (NS_SUCCEEDED(aFrame->GetPluginInstance(getter_AddRefs(pluginInstance))) && pluginInstance) { #ifdef XP_WIN // Note: pluginPort will be null if windowless. @@ -842,6 +842,8 @@ nsAccessibilityService::GetAccessibleInShell(nsINode* aNode, nsAccessible* nsAccessibilityService::GetAccessible(nsINode* aNode) { + NS_PRECONDITION(aNode, "Getting an accessible for null node! Crash."); + nsDocAccessible* document = GetDocAccessible(aNode->GetOwnerDoc()); return document ? document->GetAccessible(aNode) : nsnull; } diff --git a/accessible/src/base/nsAccessible.h b/accessible/src/base/nsAccessible.h index 53bf532be660..31af76d7ed90 100644 --- a/accessible/src/base/nsAccessible.h +++ b/accessible/src/base/nsAccessible.h @@ -376,6 +376,9 @@ public: inline bool IsApplication() const { return mFlags & eApplicationAccessible; } + inline bool IsDoc() const { return mFlags & eDocAccessible; } + nsDocAccessible* AsDoc(); + inline bool IsHyperText() const { return mFlags & eHyperTextAccessible; } nsHyperTextAccessible* AsHyperText(); @@ -529,10 +532,11 @@ protected: */ enum AccessibleTypes { eApplicationAccessible = 1 << 2, - eHyperTextAccessible = 1 << 3, - eHTMLListItemAccessible = 1 << 4, - eRootAccessible = 1 << 5, - eTextLeafAccessible = 1 << 6 + eDocAccessible = 1 << 3, + eHyperTextAccessible = 1 << 4, + eHTMLListItemAccessible = 1 << 5, + eRootAccessible = 1 << 6, + eTextLeafAccessible = 1 << 7 }; ////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/src/base/nsBaseWidgetAccessible.cpp b/accessible/src/base/nsBaseWidgetAccessible.cpp index ab66e903d52b..b4b9ba8867de 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.cpp +++ b/accessible/src/base/nsBaseWidgetAccessible.cpp @@ -93,7 +93,7 @@ nsLeafAccessible::CacheChildren() nsLinkableAccessible:: nsLinkableAccessible(nsIContent *aContent, nsIWeakReference *aShell) : nsAccessibleWrap(aContent, aShell), - mActionContent(nsnull), + mActionAcc(nsnull), mIsLink(PR_FALSE), mIsOnclick(PR_FALSE) { @@ -107,11 +107,7 @@ NS_IMPL_ISUPPORTS_INHERITED0(nsLinkableAccessible, nsAccessibleWrap) NS_IMETHODIMP nsLinkableAccessible::TakeFocus() { - nsAccessible *actionAcc = GetActionAccessible(); - if (actionAcc) - return actionAcc->TakeFocus(); - - return nsAccessibleWrap::TakeFocus(); + return mActionAcc ? mActionAcc->TakeFocus() : nsAccessibleWrap::TakeFocus(); } PRUint64 @@ -120,8 +116,7 @@ nsLinkableAccessible::NativeState() PRUint64 states = nsAccessibleWrap::NativeState(); if (mIsLink) { states |= states::LINKED; - nsAccessible* actionAcc = GetActionAccessible(); - if (actionAcc->State() & states::TRAVERSED) + if (mActionAcc->State() & states::TRAVERSED) states |= states::TRAVERSED; } @@ -137,13 +132,7 @@ nsLinkableAccessible::GetValue(nsAString& aValue) if (!aValue.IsEmpty()) return NS_OK; - if (mIsLink) { - nsAccessible *actionAcc = GetActionAccessible(); - if (actionAcc) - return actionAcc->GetValue(aValue); - } - - return NS_ERROR_NOT_IMPLEMENTED; + return mIsLink ? mActionAcc->GetValue(aValue) : NS_ERROR_NOT_IMPLEMENTED; } @@ -152,7 +141,7 @@ nsLinkableAccessible::GetNumActions(PRUint8 *aNumActions) { NS_ENSURE_ARG_POINTER(aNumActions); - *aNumActions = mActionContent ? 1 : 0; + *aNumActions = mActionAcc ? 1 : 0; return NS_OK; } @@ -182,11 +171,8 @@ nsLinkableAccessible::DoAction(PRUint8 aIndex) if (aIndex != eAction_Jump) return NS_ERROR_INVALID_ARG; - nsAccessible *actionAcc = GetActionAccessible(); - if (actionAcc) - return actionAcc->DoAction(aIndex); - - return nsAccessibleWrap::DoAction(aIndex); + return mActionAcc ? mActionAcc->DoAction(aIndex) : + nsAccessibleWrap::DoAction(aIndex); } NS_IMETHODIMP @@ -194,11 +180,8 @@ nsLinkableAccessible::GetKeyboardShortcut(nsAString& aKeyboardShortcut) { aKeyboardShortcut.Truncate(); - nsAccessible *actionAcc = GetActionAccessible(); - if (actionAcc) - return actionAcc->GetKeyboardShortcut(aKeyboardShortcut); - - return nsAccessible::GetKeyboardShortcut(aKeyboardShortcut); + return mActionAcc ? mActionAcc->GetKeyboardShortcut(aKeyboardShortcut) : + nsAccessible::GetKeyboardShortcut(aKeyboardShortcut); } //////////////////////////////////////////////////////////////////////////////// @@ -207,7 +190,9 @@ nsLinkableAccessible::GetKeyboardShortcut(nsAString& aKeyboardShortcut) void nsLinkableAccessible::Shutdown() { - mActionContent = nsnull; + mIsLink = PR_FALSE; + mIsOnclick = PR_FALSE; + mActionAcc = nsnull; nsAccessibleWrap::Shutdown(); } @@ -218,14 +203,11 @@ already_AddRefed nsLinkableAccessible::GetAnchorURI(PRUint32 aAnchorIndex) { if (mIsLink) { - nsAccessible* link = GetActionAccessible(); - if (link) { - NS_ASSERTION(link->IsHyperLink(), - "nsIAccessibleHyperLink isn't implemented."); + NS_ASSERTION(mActionAcc->IsHyperLink(), + "nsIAccessibleHyperLink isn't implemented."); - if (link->IsHyperLink()) - return link->GetAnchorURI(aAnchorIndex); - } + if (mActionAcc->IsHyperLink()) + return mActionAcc->GetAnchorURI(aAnchorIndex); } return nsnull; @@ -241,55 +223,36 @@ nsLinkableAccessible::BindToParent(nsAccessible* aParent, nsAccessibleWrap::BindToParent(aParent, aIndexInParent); // Cache action content. - mActionContent = nsnull; + mActionAcc = nsnull; mIsLink = PR_FALSE; mIsOnclick = PR_FALSE; - nsIContent* walkUpContent = mContent; - PRBool isOnclick = nsCoreUtils::HasClickListener(walkUpContent); - - if (isOnclick) { - mActionContent = walkUpContent; + if (nsCoreUtils::HasClickListener(mContent)) { + mActionAcc = this; mIsOnclick = PR_TRUE; return; } - while ((walkUpContent = walkUpContent->GetParent())) { - nsAccessible* walkUpAcc = - GetAccService()->GetAccessibleInWeakShell(walkUpContent, mWeakShell); - + // XXX: The logic looks broken since the click listener may be registered + // on non accessible node in parent chain but this node is skipped when tree + // is traversed. + nsAccessible* walkUpAcc = this; + while ((walkUpAcc = walkUpAcc->GetParent()) && !walkUpAcc->IsDoc()) { if (walkUpAcc && walkUpAcc->Role() == nsIAccessibleRole::ROLE_LINK && walkUpAcc->State() & states::LINKED) { mIsLink = PR_TRUE; - mActionContent = walkUpContent; + mActionAcc = walkUpAcc; return; } - isOnclick = nsCoreUtils::HasClickListener(walkUpContent); - if (isOnclick) { - mActionContent = walkUpContent; + if (nsCoreUtils::HasClickListener(walkUpAcc->GetContent())) { + mActionAcc = walkUpAcc; mIsOnclick = PR_TRUE; return; } } } -//////////////////////////////////////////////////////////////////////////////// -// nsLinkableAccessible: protected - -nsAccessible * -nsLinkableAccessible::GetActionAccessible() const -{ - // Return accessible for the action content if it's different from node of - // this accessible. If the action accessible is not null then it is used to - // redirect methods calls otherwise we use method implementation from the - // base class. - if (!mActionContent || mContent == mActionContent) - return nsnull; - - return GetAccService()->GetAccessibleInWeakShell(mActionContent, mWeakShell); -} - //////////////////////////////////////////////////////////////////////////////// // nsEnumRoleAccessible //////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/src/base/nsBaseWidgetAccessible.h b/accessible/src/base/nsBaseWidgetAccessible.h index 8a776da91f11..d8b0866ce572 100644 --- a/accessible/src/base/nsBaseWidgetAccessible.h +++ b/accessible/src/base/nsBaseWidgetAccessible.h @@ -108,14 +108,10 @@ protected: // nsAccessible virtual void BindToParent(nsAccessible* aParent, PRUint32 aIndexInParent); - // nsLinkableAccessible - /** - * Return an accessible for cached action node. + * Parent accessible that provides an action for this linkable accessible. */ - nsAccessible *GetActionAccessible() const; - - nsCOMPtr mActionContent; + nsAccessible* mActionAcc; PRPackedBool mIsLink; PRPackedBool mIsOnclick; }; diff --git a/accessible/src/base/nsCoreUtils.cpp b/accessible/src/base/nsCoreUtils.cpp index 081888febad0..ea5739664064 100644 --- a/accessible/src/base/nsCoreUtils.cpp +++ b/accessible/src/base/nsCoreUtils.cpp @@ -493,12 +493,10 @@ nsCoreUtils::IsErrorPage(nsIDocument *aDocument) nsCAutoString path; uri->GetPath(path); - nsCAutoString::const_iterator start, end; - path.BeginReading(start); - path.EndReading(end); - NS_NAMED_LITERAL_CSTRING(neterror, "neterror"); - return FindInReadable(neterror, start, end); + NS_NAMED_LITERAL_CSTRING(certerror, "certerror"); + + return StringBeginsWith(path, neterror) || StringBeginsWith(path, certerror); } PRBool diff --git a/accessible/src/base/nsDocAccessible.cpp b/accessible/src/base/nsDocAccessible.cpp index 88a766be0d0e..4b288395d189 100644 --- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -109,6 +109,8 @@ nsDocAccessible:: mDocument(aDocument), mScrollPositionChangedTicks(0), mIsLoaded(PR_FALSE), mCacheRoot(nsnull), mIsPostCacheProcessing(PR_FALSE) { + mFlags |= eDocAccessible; + mDependentIDsHash.Init(); // XXX aaronl should we use an algorithm for the initial cache size? mAccessibleCache.Init(kDefaultCacheSize); @@ -1114,7 +1116,8 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute) // at least until native API comes up with a more meaningful event. if (aAttribute == nsAccessibilityAtoms::aria_grabbed || aAttribute == nsAccessibilityAtoms::aria_dropeffect || - aAttribute == nsAccessibilityAtoms::aria_hidden) { + aAttribute == nsAccessibilityAtoms::aria_hidden || + aAttribute == nsAccessibilityAtoms::aria_sort) { FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED, aContent); } diff --git a/accessible/src/base/nsDocAccessible.h b/accessible/src/base/nsDocAccessible.h index c77a7c6d301f..55d8f753cef0 100644 --- a/accessible/src/base/nsDocAccessible.h +++ b/accessible/src/base/nsDocAccessible.h @@ -552,4 +552,11 @@ protected: NS_DEFINE_STATIC_IID_ACCESSOR(nsDocAccessible, NS_DOCACCESSIBLE_IMPL_CID) +inline nsDocAccessible* +nsAccessible::AsDoc() +{ + return mFlags & eDocAccessible ? + static_cast(this) : nsnull; +} + #endif diff --git a/accessible/src/base/nsOuterDocAccessible.cpp b/accessible/src/base/nsOuterDocAccessible.cpp index 1a13dd9d9002..239c6407a3b3 100644 --- a/accessible/src/base/nsOuterDocAccessible.cpp +++ b/accessible/src/base/nsOuterDocAccessible.cpp @@ -213,8 +213,8 @@ nsOuterDocAccessible::RemoveChild(nsAccessible *aAccessible) return PR_FALSE; } - NS_LOG_ACCDOCDESTROY("remove document from outerdoc", - child->GetDocumentNode()) + NS_LOG_ACCDOCDESTROY_FOR("remove document from outerdoc", + child->GetDocumentNode(), child) NS_LOG_ACCDOCDESTROY_ACCADDRESS("outerdoc", this) PRBool wasRemoved = nsAccessible::RemoveChild(child); diff --git a/accessible/src/base/nsTextEquivUtils.cpp b/accessible/src/base/nsTextEquivUtils.cpp index aedd43043450..8623ecea8d91 100644 --- a/accessible/src/base/nsTextEquivUtils.cpp +++ b/accessible/src/base/nsTextEquivUtils.cpp @@ -297,7 +297,7 @@ nsTextEquivUtils::AppendFromValue(nsAccessible *aAccessible, } //XXX: is it necessary to care the accessible is not a document? - if (aAccessible->IsDocument()) + if (aAccessible->IsDocumentNode()) return NS_ERROR_UNEXPECTED; nsIContent *content = aAccessible->GetContent(); diff --git a/accessible/src/html/nsHyperTextAccessible.cpp b/accessible/src/html/nsHyperTextAccessible.cpp index ae826053be8b..bcafdce71ea0 100644 --- a/accessible/src/html/nsHyperTextAccessible.cpp +++ b/accessible/src/html/nsHyperTextAccessible.cpp @@ -916,7 +916,7 @@ nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTe NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr privateSelection(do_QueryInterface(domSel)); - nsCOMPtr frameSelection; + nsRefPtr frameSelection; rv = privateSelection->GetFrameSelection(getter_AddRefs(frameSelection)); NS_ENSURE_SUCCESS(rv, rv); @@ -1014,7 +1014,7 @@ nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTe } if (aType == eGetBefore) { - endOffset = aOffset; + finalEndOffset = aOffset; } else { // Start moving forward from the start so that we don't get @@ -1680,7 +1680,7 @@ PRInt32 nsHyperTextAccessible::GetCaretLineNumber() getter_AddRefs(domSel)); nsCOMPtr privateSelection(do_QueryInterface(domSel)); NS_ENSURE_TRUE(privateSelection, -1); - nsCOMPtr frameSelection; + nsRefPtr frameSelection; privateSelection->GetFrameSelection(getter_AddRefs(frameSelection)); NS_ENSURE_TRUE(frameSelection, -1); diff --git a/accessible/src/mac/mozAccessible.mm b/accessible/src/mac/mozAccessible.mm index 655cb59c31e8..3a43aa1a0c3c 100644 --- a/accessible/src/mac/mozAccessible.mm +++ b/accessible/src/mac/mozAccessible.mm @@ -238,7 +238,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible) if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) return NSAccessibilityRoleDescription([self role], nil); #endif - if ([attribute isEqualToString:kInstanceDescriptionAttribute]) + if ([attribute isEqualToString: (NSString*) kInstanceDescriptionAttribute]) return [self customDescription]; if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) return [NSNumber numberWithBool:[self isFocused]]; @@ -246,7 +246,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible) return [self size]; if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) return [self window]; - if ([attribute isEqualToString:kTopLevelUIElementAttribute]) + if ([attribute isEqualToString: (NSString*) kTopLevelUIElementAttribute]) return [self window]; if ([attribute isEqualToString:NSAccessibilityTitleAttribute] || [attribute isEqualToString:NSAccessibilityTitleUIElementAttribute]) @@ -471,7 +471,7 @@ GetNativeFromGeckoAccessible(nsIAccessible *anAccessible) NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(mGeckoAccessible), "Does not support nsIAccessibleText when it should"); #endif - return AXRoles[mRole]; + return (NSString*) AXRoles[mRole]; } - (NSString*)subrole diff --git a/accessible/src/mac/nsAccessibleWrap.h b/accessible/src/mac/nsAccessibleWrap.h index 6c08ba0e898b..e36d46df327b 100644 --- a/accessible/src/mac/nsAccessibleWrap.h +++ b/accessible/src/mac/nsAccessibleWrap.h @@ -43,6 +43,8 @@ #ifndef _nsAccessibleWrap_H_ #define _nsAccessibleWrap_H_ +#include + #include "nsAccessible.h" #include "nsAccUtils.h" #include "States.h" @@ -54,7 +56,6 @@ #include "nsAutoPtr.h" struct AccessibleWrapper; -struct objc_class; class nsAccessibleWrap : public nsAccessible { @@ -71,7 +72,7 @@ class nsAccessibleWrap : public nsAccessible // the objective-c |Class| type that this accessible's native object // should be instantied with. used on runtime to determine the // right type for this accessible's associated native object. - virtual objc_class* GetNativeType (); + virtual Class GetNativeType (); virtual void Shutdown (); virtual void InvalidateChildren(); diff --git a/accessible/src/mac/nsAccessibleWrap.mm b/accessible/src/mac/nsAccessibleWrap.mm index 181d5d3488d2..316ca7d56356 100644 --- a/accessible/src/mac/nsAccessibleWrap.mm +++ b/accessible/src/mac/nsAccessibleWrap.mm @@ -88,7 +88,7 @@ nsAccessibleWrap::GetNativeInterface (void **aOutInterface) // overridden in subclasses to create the right kind of object. by default we create a generic // 'mozAccessible' node. -objc_class* +Class nsAccessibleWrap::GetNativeType () { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; diff --git a/accessible/src/mac/nsRootAccessibleWrap.h b/accessible/src/mac/nsRootAccessibleWrap.h index c40063636912..ee69b23f6d52 100644 --- a/accessible/src/mac/nsRootAccessibleWrap.h +++ b/accessible/src/mac/nsRootAccessibleWrap.h @@ -54,7 +54,7 @@ public: nsIWeakReference *aShell); virtual ~nsRootAccessibleWrap(); - objc_class* GetNativeType (); + Class GetNativeType (); // let's our native accessible get in touch with the // native cocoa view that is our accessible parent. diff --git a/accessible/src/mac/nsRootAccessibleWrap.mm b/accessible/src/mac/nsRootAccessibleWrap.mm index cbd1452a4463..b4bc62f07c12 100644 --- a/accessible/src/mac/nsRootAccessibleWrap.mm +++ b/accessible/src/mac/nsRootAccessibleWrap.mm @@ -59,7 +59,7 @@ nsRootAccessibleWrap::~nsRootAccessibleWrap() { } -objc_class* +Class nsRootAccessibleWrap::GetNativeType () { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; diff --git a/accessible/src/msaa/nsAccessNodeWrap.cpp b/accessible/src/msaa/nsAccessNodeWrap.cpp index 5de92ed83391..5e8a1f6ece61 100644 --- a/accessible/src/msaa/nsAccessNodeWrap.cpp +++ b/accessible/src/msaa/nsAccessNodeWrap.cpp @@ -275,7 +275,7 @@ STDMETHODIMP nsAccessNodeWrap::get_attributes( __try{ *aNumAttribs = 0; - if (IsDefunct() || IsDocument()) + if (IsDefunct() || IsDocumentNode()) return E_FAIL; PRUint32 numAttribs = mContent->GetAttrCount(); @@ -348,7 +348,7 @@ STDMETHODIMP nsAccessNodeWrap::get_computedStyle( __try{ *aNumStyleProperties = 0; - if (IsDefunct() || IsDocument()) + if (IsDefunct() || IsDocumentNode()) return E_FAIL; nsCOMPtr cssDecl = @@ -383,7 +383,7 @@ STDMETHODIMP nsAccessNodeWrap::get_computedStyleForProperties( /* [length_is][size_is][out] */ BSTR __RPC_FAR *aStyleValues) { __try { - if (IsDefunct() || IsDocument()) + if (IsDefunct() || IsDocumentNode()) return E_FAIL; nsCOMPtr cssDecl = diff --git a/accessible/src/msaa/nsAccessibleWrap.cpp b/accessible/src/msaa/nsAccessibleWrap.cpp index dddee69e4dde..c51ced2fdca4 100644 --- a/accessible/src/msaa/nsAccessibleWrap.cpp +++ b/accessible/src/msaa/nsAccessibleWrap.cpp @@ -1762,6 +1762,38 @@ nsAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild) if (nsAccUtils::MustPrune(this)) return nsnull; + // If lVal negative then it is treated as child ID and we should look for + // accessible through whole accessible subtree including subdocuments. + // Otherwise we treat lVal as index in parent. + + if (aVarChild.lVal < 0) { + // Convert child ID to unique ID. + void* uniqueID = reinterpret_cast(-aVarChild.lVal); + + // Document. + if (IsDoc()) + return AsDoc()->GetAccessibleByUniqueIDInSubtree(uniqueID); + + // ARIA document. + if (ARIARole() == nsIAccessibleRole::ROLE_DOCUMENT) { + nsDocAccessible* document = GetDocAccessible(); + nsAccessible* child = + document->GetAccessibleByUniqueIDInSubtree(uniqueID); + + // Check whether the accessible for the given ID is a child of ARIA + // document. + nsAccessible* parent = child ? child->GetParent() : nsnull; + while (parent && parent != document) { + if (parent == this) + return child; + + parent = parent->GetParent(); + } + } + + return nsnull; + } + // Gecko child indices are 0-based in contrast to indices used in MSAA. return GetChildAt(aVarChild.lVal - 1); } diff --git a/accessible/src/msaa/nsAccessibleWrap.h b/accessible/src/msaa/nsAccessibleWrap.h index 5591793f35bc..b4f936f5cbfb 100644 --- a/accessible/src/msaa/nsAccessibleWrap.h +++ b/accessible/src/msaa/nsAccessibleWrap.h @@ -327,7 +327,7 @@ public: // construction, destruction /** * Find an accessible by the given child ID in cached documents. */ - virtual nsAccessible *GetXPAccessibleFor(const VARIANT& aVarChild); + nsAccessible* GetXPAccessibleFor(const VARIANT& aVarChild); NS_IMETHOD GetNativeInterface(void **aOutAccessible); diff --git a/accessible/src/msaa/nsDocAccessibleWrap.cpp b/accessible/src/msaa/nsDocAccessibleWrap.cpp index 3db504ca1ea8..b89cbb8e3eeb 100644 --- a/accessible/src/msaa/nsDocAccessibleWrap.cpp +++ b/accessible/src/msaa/nsDocAccessibleWrap.cpp @@ -99,22 +99,6 @@ STDMETHODIMP nsDocAccessibleWrap::QueryInterface(REFIID iid, void** ppv) return S_OK; } -nsAccessible* -nsDocAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild) -{ - // If lVal negative then it is treated as child ID and we should look for - // accessible through whole accessible subtree including subdocuments. - // Otherwise we treat lVal as index in parent. - - if (aVarChild.vt == VT_I4 && aVarChild.lVal < 0) { - // Convert child ID to unique ID. - void* uniqueID = reinterpret_cast(-aVarChild.lVal); - return GetAccessibleByUniqueIDInSubtree(uniqueID); - } - - return nsAccessibleWrap::GetXPAccessibleFor(aVarChild); -} - STDMETHODIMP nsDocAccessibleWrap::get_URL(/* [out] */ BSTR __RPC_FAR *aURL) { __try { diff --git a/accessible/src/msaa/nsDocAccessibleWrap.h b/accessible/src/msaa/nsDocAccessibleWrap.h index 827e428ff5c9..1c541ef9cc4f 100644 --- a/accessible/src/msaa/nsDocAccessibleWrap.h +++ b/accessible/src/msaa/nsDocAccessibleWrap.h @@ -92,9 +92,6 @@ public: // nsAccessNode virtual void Shutdown(); - // nsAccessibleWrap - virtual nsAccessible *GetXPAccessibleFor(const VARIANT& varChild); - // nsDocAccessible virtual void* GetNativeWindow() const; diff --git a/accessible/tests/mochitest/events/Makefile.in b/accessible/tests/mochitest/events/Makefile.in index 180570d7bfef..1c099e789eaf 100644 --- a/accessible/tests/mochitest/events/Makefile.in +++ b/accessible/tests/mochitest/events/Makefile.in @@ -51,8 +51,8 @@ _TEST_FILES =\ focus.html \ scroll.html \ test_aria_alert.html \ - test_aria_hidden.html \ test_aria_menu.html \ + test_aria_objattr.html \ test_aria_statechange.html \ test_attrs.html \ test_caretmove.html \ diff --git a/accessible/tests/mochitest/events/docload_wnd.xul b/accessible/tests/mochitest/events/docload_wnd.xul index 06402e8e987b..808f1d698087 100644 --- a/accessible/tests/mochitest/events/docload_wnd.xul +++ b/accessible/tests/mochitest/events/docload_wnd.xul @@ -192,11 +192,11 @@ /** * Load wrong URI what results in error page loading. */ - function loadErrorPageInvoker() + function loadErrorPageInvoker(aURL, aURLDescr) { this.invoke = function loadErrorPageInvoker_invoke() { - gTabBrowser.loadURI("www.wronguri.wronguri"); + gTabBrowser.loadURI(aURL); } this.eventSeq = [ @@ -209,7 +209,7 @@ this.getID = function loadErrorPageInvoker_getID() { - return "load error page"; + return "load error page: '" + aURLDescr + "'"; } } @@ -230,7 +230,11 @@ gQueue.push(new clickReloadBtnInvoker()); gQueue.push(new loadURIInvoker("about:mozilla")); gQueue.push(new reloadInvoker()); - gQueue.push(new loadErrorPageInvoker()); + gQueue.push(new loadErrorPageInvoker("www.wronguri.wronguri", + "Server not found")); + gQueue.push(new loadErrorPageInvoker("https://nocert.example.com:443", + "Untrusted Connection")); + gQueue.onFinish = function() { window.close(); } gQueue.invoke(); } diff --git a/accessible/tests/mochitest/events/test_aria_hidden.html b/accessible/tests/mochitest/events/test_aria_objattr.html similarity index 65% rename from accessible/tests/mochitest/events/test_aria_hidden.html rename to accessible/tests/mochitest/events/test_aria_objattr.html index 25e72833210a..a4810fe1e895 100644 --- a/accessible/tests/mochitest/events/test_aria_hidden.html +++ b/accessible/tests/mochitest/events/test_aria_objattr.html @@ -1,7 +1,7 @@ - Accessible ARIA hidden attribute + Accessible ARIA object attribute changes @@ -43,14 +43,38 @@ } } + function updateSort(aID, aSort) + { + this.node = getNode(aID); + this.accessible = getAccessible(this.node); + + this.eventSeq = [ + new invokerChecker(EVENT_OBJECT_ATTRIBUTE_CHANGED, this.accessible), + ]; + + this.invoke = function updateSort_invoke() + { + this.node.setAttribute("aria-sort", aSort); + } + + this.getID = function updateSort_getID() + { + return "aria-sort for " + aID + " " + aSort; + } + } + + // Debug stuff. + // gA11yEventDumpID = "eventdump"; + // gA11yEventDumpToConsole = true; + function doTests() { - //gA11yEventDumpID = "eventdump"; // debug stuff - gQueue = new eventQueue(); gQueue.push(new hideNode("hideable", "true")); + gQueue.push(new updateSort("sortable", "ascending")); + gQueue.invoke(); // Will call SimpleTest.finish(); } @@ -67,6 +91,12 @@ Mozilla Bug 581096 + + Mozilla Bug 640707 + +

@@ -75,5 +105,6 @@
 
   
Hi
there
+
aria-sort
diff --git a/accessible/tests/mochitest/text/Makefile.in b/accessible/tests/mochitest/text/Makefile.in index 83946f4c46ce..15b33314a2c8 100644 --- a/accessible/tests/mochitest/text/Makefile.in +++ b/accessible/tests/mochitest/text/Makefile.in @@ -50,8 +50,8 @@ _TEST_FILES = \ test_doc.html \ test_hypertext.html \ test_passwords.html \ - $(warning test_singleline.html disabled due to bug 652459) \ - $(warning test_whitespaces.html disabled due to bug 652459) \ + test_singleline.html \ + test_whitespaces.html \ test_words.html \ $(NULL) diff --git a/accessible/tests/mochitest/text/test_singleline.html b/accessible/tests/mochitest/text/test_singleline.html index 6c10b6fa4d78..61f1b45366c7 100644 --- a/accessible/tests/mochitest/text/test_singleline.html +++ b/accessible/tests/mochitest/text/test_singleline.html @@ -216,10 +216,10 @@ // BOUNDARY_WORD_START testTextBeforeOffset(0, BOUNDARY_WORD_START, "", 0, 0, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(1, BOUNDARY_WORD_START, "", 0, 0, "input", kTodo, kOk, kTodo, "div", kTodo, kOk, kTodo, @@ -231,10 +231,10 @@ "editable", kTodo, kOk, kTodo, "textarea", kTodo, kOk, kTodo); testTextBeforeOffset(6, BOUNDARY_WORD_START, "hello ", 0, 6, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(7, BOUNDARY_WORD_START, "hello ", 0, 6, "input", kTodo, kTodo, kTodo, "div", kTodo, kTodo, kTodo, @@ -246,10 +246,10 @@ "editable", kTodo, kTodo, kTodo, "textarea", kTodo, kTodo, kTodo); testTextBeforeOffset(9, BOUNDARY_WORD_START, "my ", 6, 9, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(10, BOUNDARY_WORD_START, "my ", 6, 9, "input", kTodo, kTodo, kTodo, "div", kTodo, kTodo, kTodo, @@ -268,10 +268,10 @@ // BOUNDARY_WORD_END testTextBeforeOffset(0, BOUNDARY_WORD_END, "", 0, 0, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(1, BOUNDARY_WORD_END, "", 0, 0, "input", kTodo, kOk, kTodo, "div", kTodo, kOk, kTodo, @@ -283,10 +283,10 @@ "editable", kTodo, kOk, kTodo, "textarea", kTodo, kOk, kTodo); testTextBeforeOffset(6, BOUNDARY_WORD_END, "hello ", 0, 6, - "input", kTodo, kTodo, kTodo, - "div", kTodo, kTodo, kTodo, - "editable", kTodo, kTodo, kTodo, - "textarea", kTodo, kTodo, kTodo); + "input", kTodo, kTodo, kOk, + "div", kTodo, kTodo, kOk, + "editable", kTodo, kTodo, kOk, + "textarea", kTodo, kTodo, kOk); testTextBeforeOffset(7, BOUNDARY_WORD_END, "hello ", 0, 6, "input", kTodo, kTodo, kTodo, "div", kTodo, kTodo, kTodo, @@ -320,10 +320,10 @@ // BOUNDARY_LINE_START testTextBeforeOffset(0, BOUNDARY_LINE_START, "", 0, 0, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(1, BOUNDARY_LINE_START, "", 0, 0, "input", kTodo, kOk, kTodo, "div", kTodo, kOk, kTodo, @@ -342,10 +342,10 @@ // BOUNDARY_LINE_END testTextBeforeOffset(0, BOUNDARY_LINE_END, "", 0, 0, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(1, BOUNDARY_LINE_END, "", 0, 0, "input", kTodo, kOk, kTodo, "div", kTodo, kOk, kTodo, diff --git a/accessible/tests/mochitest/text/test_whitespaces.html b/accessible/tests/mochitest/text/test_whitespaces.html index e6fa5b6110ed..28ec7f4d3210 100644 --- a/accessible/tests/mochitest/text/test_whitespaces.html +++ b/accessible/tests/mochitest/text/test_whitespaces.html @@ -196,10 +196,10 @@ // BOUNDARY_WORD_START testTextBeforeOffset(0, BOUNDARY_WORD_START, "", 0, 0, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(1, BOUNDARY_WORD_START, "", 0, 0, "input", kTodo, kOk, kTodo, "div", kTodo, kOk, kTodo, @@ -211,10 +211,10 @@ "editable", kTodo, kOk, kTodo, "textarea", kTodo, kOk, kTodo); testTextBeforeOffset(6, BOUNDARY_WORD_START, "Brave ", 0, 6, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(9, BOUNDARY_WORD_START, "Brave ", 0, 6, "input", kTodo, kTodo, kTodo, "div", kTodo, kTodo, kTodo, @@ -226,10 +226,10 @@ "editable", kTodo, kTodo, kTodo, "textarea", kTodo, kTodo, kTodo); testTextBeforeOffset(11, BOUNDARY_WORD_START, "Sir ", 6, 11, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(15, BOUNDARY_WORD_START, "Sir ", 6, 11, "input", kTodo, kTodo, kTodo, "div", kTodo, kTodo, kTodo, @@ -251,10 +251,10 @@ "editable", kTodo, kTodo, kTodo, "textarea", kTodo, kTodo, kTodo); testTextBeforeOffset(19, BOUNDARY_WORD_START, "Robin ", 11, 19, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(20, BOUNDARY_WORD_START, "Robin ", 11, 19, "input", kTodo, kTodo, kTodo, "div", kTodo, kTodo, kTodo, @@ -268,10 +268,10 @@ // BOUNDARY_WORD_END testTextBeforeOffset(0, BOUNDARY_WORD_END, "", 0, 0, - "input", kTodo, kOk, kTodo, - "div", kTodo, kOk, kTodo, - "editable", kTodo, kOk, kTodo, - "textarea", kTodo, kOk, kTodo); + "input", kOk, kOk, kOk, + "div", kOk, kOk, kOk, + "editable", kOk, kOk, kOk, + "textarea", kOk, kOk, kOk); testTextBeforeOffset(1, BOUNDARY_WORD_END, "", 0, 0, "input", kTodo, kOk, kTodo, "div", kTodo, kOk, kTodo, diff --git a/browser/app/Makefile.in b/browser/app/Makefile.in index db8a00d87a82..dd3a89ffa6e1 100644 --- a/browser/app/Makefile.in +++ b/browser/app/Makefile.in @@ -185,8 +185,7 @@ endif ifeq ($(OS_ARCH),WINNT) OS_LIBS += $(call EXPAND_LIBNAME,comctl32 comdlg32 uuid shell32 ole32 oleaut32 version winspool) -OS_LIBS += $(call EXPAND_LIBNAME,usp10 msimg32 delayimp) -LDFLAGS += -delayload:xul.dll -delayload:xpcom.dll -delayload:plc4.dll -delayload:nspr4.dll -delayload:mozalloc.dll +OS_LIBS += $(call EXPAND_LIBNAME,usp10 msimg32) endif ifeq ($(OS_ARCH),WINNT) diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp index e0f034055fec..f8cbf7933824 100644 --- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -56,7 +56,6 @@ #ifdef XP_WIN // we want to use the DLL blocklist if possible #define XRE_WANT_DLL_BLOCKLIST -#define XRE_PRELOAD_XUL // we want a wmain entry point #include "nsWindowsWMain.cpp" #endif diff --git a/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/setup.js b/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/setup.js index a22c23bea73b..350202f4d6f1 100644 --- a/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/setup.js +++ b/browser/app/profile/extensions/testpilot@labs.mozilla.com/modules/setup.js @@ -254,18 +254,15 @@ let TestPilotSetup = { Ci.nsITimer.TYPE_REPEATING_SLACK); this.getVersion(function() { - // Show first run page (in front window) if newly installed or upgraded. - let currVersion = self._prefs.getValue(VERSION_PREF, "firstrun"); - - if (currVersion != self.version) { - if(!self._isBetaChannel()) { - // Don't show first run page in ffx4 beta version. + /* Show first run page (in front window) only the first time after install; + * Don't show first run page in Feedback UI version. */ + if ((self._prefs.getValue(VERSION_PREF, "") == "") && + (!self._interfaceBuilder.channelUsesFeedback())) { self._prefs.setValue(VERSION_PREF, self.version); let browser = self._getFrontBrowserWindow().getBrowser(); let url = self._prefs.getValue(FIRST_RUN_PREF, ""); let tab = browser.addTab(url); browser.selectedTab = tab; - } } // Install tasks. (This requires knowing the version, so it is diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 0e27a6e4fc05..612107707bcc 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -785,6 +785,8 @@ pref("browser.sessionstore.max_resumed_crashes", 1); // Other tabs won't be restored until they are selected // N = The number of tabs to restore at the same time pref("browser.sessionstore.max_concurrent_tabs", 3); +// Whether to automatically restore hidden tabs (i.e., tabs in other tab groups) or not +pref("browser.sessionstore.restore_hidden_tabs", false); // allow META refresh by default pref("accessibility.blockautorefresh", false); diff --git a/browser/base/content/aboutDialog.js b/browser/base/content/aboutDialog.js index 49ac1cd32ced..ce092540c0b0 100644 --- a/browser/base/content/aboutDialog.js +++ b/browser/base/content/aboutDialog.js @@ -359,7 +359,6 @@ appUpdater.prototype = // notified with the normal app update user interface so this is safe. gAppUpdater.isChecking = false; gAppUpdater.selectPanel("noUpdatesFound"); - return; }, /** @@ -613,6 +612,8 @@ var gChannelSelector = { // Change app update channel. Services.prefs.setCharPref("app.update.desiredChannel", this.channelValue); + // Stop any downloads in progress + gAppUpdater.aus.pauseDownload(); // App updater will look at app.update.desiredChannel for new channel value // and will clear it when the update is complete. gAppUpdater.isChecking = true; diff --git a/browser/base/content/browser-tabview.js b/browser/base/content/browser-tabview.js index 3020c7a58385..0a492d3cdae1 100644 --- a/browser/base/content/browser-tabview.js +++ b/browser/base/content/browser-tabview.js @@ -40,10 +40,13 @@ let TabView = { _deck: null, _iframe: null, _window: null, - _firstUseExperienced: false, _browserKeyHandlerInitialized: false, _isFrameLoading: false, _initFrameCallbacks: [], + PREF_BRANCH: "browser.panorama.", + PREF_FIRST_RUN: "browser.panorama.experienced_first_run", + PREF_STARTUP_PAGE: "browser.startup.page", + PREF_RESTORE_ENABLED_ONCE: "browser.panorama.session_restore_enabled_once", VISIBILITY_IDENTIFIER: "tabview-visibility", // ---------- @@ -57,24 +60,35 @@ let TabView = { // ---------- get firstUseExperienced() { - return this._firstUseExperienced; + let pref = this.PREF_FIRST_RUN; + if (Services.prefs.prefHasUserValue(pref)) + return Services.prefs.getBoolPref(pref); + + return false; }, // ---------- set firstUseExperienced(val) { - if (val != this._firstUseExperienced) - Services.prefs.setBoolPref("browser.panorama.experienced_first_run", val); + Services.prefs.setBoolPref(this.PREF_FIRST_RUN, val); + }, + + // ---------- + get sessionRestoreEnabledOnce() { + let pref = this.PREF_RESTORE_ENABLED_ONCE; + if (Services.prefs.prefHasUserValue(pref)) + return Services.prefs.getBoolPref(pref); + + return false; + }, + + // ---------- + set sessionRestoreEnabledOnce(val) { + Services.prefs.setBoolPref(this.PREF_RESTORE_ENABLED_ONCE, val); }, // ---------- init: function TabView_init() { - if (!Services.prefs.prefHasUserValue("browser.panorama.experienced_first_run") || - !Services.prefs.getBoolPref("browser.panorama.experienced_first_run")) { - Services.prefs.addObserver( - "browser.panorama.experienced_first_run", this, false); - } else { - this._firstUseExperienced = true; - + if (this.firstUseExperienced) { if ((gBrowser.tabs.length - gBrowser.visibleTabs.length) > 0) this._setBrowserKeyHandlers(); @@ -100,26 +114,24 @@ let TabView = { "TabShow", this._tabShowEventListener, true); } } + + Services.prefs.addObserver(this.PREF_BRANCH, this, false); }, // ---------- // Observes topic changes. observe: function TabView_observe(subject, topic, data) { - if (topic == "nsPref:changed") { - Services.prefs.removeObserver( - "browser.panorama.experienced_first_run", this); - this._firstUseExperienced = true; + if (data == this.PREF_FIRST_RUN && this.firstUseExperienced) { this._addToolbarButton(); + this.enableSessionRestore(); } }, // ---------- // Uninitializes TabView. uninit: function TabView_uninit() { - if (!this._firstUseExperienced) { - Services.prefs.removeObserver( - "browser.panorama.experienced_first_run", this); - } + Services.prefs.removeObserver(this.PREF_BRANCH, this); + if (this._tabShowEventListener) { gBrowser.tabContainer.removeEventListener( "TabShow", this._tabShowEventListener, true); @@ -366,5 +378,23 @@ let TabView = { toolbar.currentSet = currentSet; toolbar.setAttribute("currentset", currentSet); document.persist(toolbar.id, "currentset"); + }, + + // ---------- + // Function: enableSessionRestore + // Enables automatic session restore when the browser is started. Does + // nothing if we already did that once in the past. + enableSessionRestore: function UI_enableSessionRestore() { + if (!this._window || !this.firstUseExperienced) + return; + + // do nothing if we already enabled session restore once + if (this.sessionRestoreEnabledOnce) + return; + + this.sessionRestoreEnabledOnce = true; + + // enable session restore + Services.prefs.setIntPref(this.PREF_STARTUP_PAGE, 3); } }; diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index ce05e573878d..9281c70d70d0 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -306,22 +306,28 @@ function SetClickAndHoldHandlers() { aElm.addEventListener("click", clickHandler, true); } - // Bug 414797: Clone the dropmarker's menu into both the back and - // the forward buttons. + // Bug 414797: Clone unified-back-forward-button's context menu into both the + // back and the forward buttons. var unifiedButton = document.getElementById("unified-back-forward-button"); if (unifiedButton && !unifiedButton._clickHandlersAttached) { - var popup = document.getElementById("backForwardMenu").cloneNode(true); + unifiedButton._clickHandlersAttached = true; + + let popup = document.getElementById("backForwardMenu").cloneNode(true); popup.removeAttribute("id"); - var backButton = document.getElementById("back-button"); + // Prevent the context attribute on unified-back-forward-button from being + // inherited. + popup.setAttribute("context", ""); + + let backButton = document.getElementById("back-button"); backButton.setAttribute("type", "menu"); backButton.appendChild(popup); _addClickAndHoldListenersOnElement(backButton); - var forwardButton = document.getElementById("forward-button"); + + let forwardButton = document.getElementById("forward-button"); popup = popup.cloneNode(true); forwardButton.setAttribute("type", "menu"); forwardButton.appendChild(popup); _addClickAndHoldListenersOnElement(forwardButton); - unifiedButton._clickHandlersAttached = true; } } @@ -4118,7 +4124,7 @@ var XULBrowserWindow = { startTime: 0, statusText: "", isBusy: false, - inContentWhitelist: ["about:addons"], + inContentWhitelist: ["about:addons", "about:permissions"], QueryInterface: function (aIID) { if (aIID.equals(Ci.nsIWebProgressListener) || diff --git a/browser/base/content/syncSetup.js b/browser/base/content/syncSetup.js index 7f2ef409fb7c..cc156836c58b 100644 --- a/browser/base/content/syncSetup.js +++ b/browser/base/content/syncSetup.js @@ -92,9 +92,9 @@ var gSyncSetup = { init: function () { let obs = [ ["weave:service:changepph:finish", "onResetPassphrase"], - ["weave:service:verify-login:start", "onLoginStart"], - ["weave:service:verify-login:error", "onLoginEnd"], - ["weave:service:verify-login:finish", "onLoginEnd"]]; + ["weave:service:login:start", "onLoginStart"], + ["weave:service:login:error", "onLoginEnd"], + ["weave:service:login:finish", "onLoginEnd"]]; // Add the observers now and remove them on unload let self = this; @@ -216,6 +216,8 @@ var gSyncSetup = { feedback = server; break; case Weave.LOGIN_FAILED_LOGIN_REJECTED: + case Weave.LOGIN_FAILED_NO_USERNAME: + case Weave.LOGIN_FAILED_NO_PASSWORD: feedback = password; break; case Weave.LOGIN_FAILED_INVALID_PASSPHRASE: diff --git a/browser/base/content/syncUtils.js b/browser/base/content/syncUtils.js index e331f437dfbc..e72a64a0913f 100644 --- a/browser/base/content/syncUtils.js +++ b/browser/base/content/syncUtils.js @@ -194,12 +194,13 @@ let gSyncUtils = { */ passphraseSave: function(elid) { let dialogTitle = this.bundle.GetStringFromName("save.synckey.title"); + let defaultSaveName = this.bundle.GetStringFromName("save.default.label"); this._preparePPiframe(elid, function(iframe) { let filepicker = Cc["@mozilla.org/filepicker;1"] .createInstance(Ci.nsIFilePicker); filepicker.init(window, dialogTitle, Ci.nsIFilePicker.modeSave); filepicker.appendFilters(Ci.nsIFilePicker.filterHTML); - filepicker.defaultString = "Firefox Sync Key.html"; + filepicker.defaultString = defaultSaveName; let rv = filepicker.show(); if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) { diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 792bcb92069f..c809ffdb1285 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -1540,8 +1540,10 @@ } this._removingTabs.push(aTab); - - this.tabContainer.updateVisibility(); + if (newTab) + this.addTab("about:blank", {skipAnimation: true}); + else + this.tabContainer.updateVisibility(); // We're committed to closing the tab now. // Dispatch a notification. @@ -1597,8 +1599,6 @@ // update the UI early for responsiveness aTab.collapsed = true; - if (aNewTab) - this.addTab("about:blank", {skipAnimation: true}); this.tabContainer._fillTrailingGap(); this._blurTab(aTab); diff --git a/browser/base/content/tabview/groupitems.js b/browser/base/content/tabview/groupitems.js index 63c396de5a0d..ec2d808ba0d3 100644 --- a/browser/base/content/tabview/groupitems.js +++ b/browser/base/content/tabview/groupitems.js @@ -2163,7 +2163,16 @@ let GroupItems = { } toClose.forEach(function(groupItem) { - groupItem.destroy({immediately: true}); + // All remaining children in to-be-closed groups are re-used by + // session restore. Reconnect them so that they're put into their + // right groups. + groupItem.getChildren().forEach(function (tabItem) { + if (tabItem.parent && tabItem.parent.hidden) + iQ(tabItem.container).show(); + tabItem._reconnected = false; + tabItem._reconnect(); + }); + groupItem.close({immediately: true}); }); } diff --git a/browser/base/content/tabview/modules/AllTabs.jsm b/browser/base/content/tabview/modules/AllTabs.jsm index e1f36ccdf06b..22ed7b2e8131 100644 --- a/browser/base/content/tabview/modules/AllTabs.jsm +++ b/browser/base/content/tabview/modules/AllTabs.jsm @@ -57,7 +57,10 @@ let AllTabs = { get tabs() { // Get tabs from each browser window and flatten them into one array return Array.concat.apply(null, browserWindows.map(function(browserWindow) { - return Array.slice(browserWindow.gBrowser.tabs); + let removingTabs = browserWindow.gBrowser._removingTabs; + return Array.filter(browserWindow.gBrowser.tabs, function (tab) { + return removingTabs.indexOf(tab) == -1; + }); })); }, diff --git a/browser/base/content/tabview/ui.js b/browser/base/content/tabview/ui.js index 4f4c448d91f5..e9cba640ccf2 100644 --- a/browser/base/content/tabview/ui.js +++ b/browser/base/content/tabview/ui.js @@ -552,6 +552,9 @@ let UI = { TabItems.resumePainting(); } + + if (gTabView.firstUseExperienced) + gTabView.enableSessionRestore(); }, // ---------- @@ -739,9 +742,9 @@ let UI = { } else { // If we're currently in the process of entering private browsing, // we don't want to go to the Tab View UI. - if (self._privateBrowsing.transitionMode) - return; - + if (self._storageBusyCount) + return; + // if not closing the last tab if (gBrowser.tabs.length > 1) { // Don't return to TabView if there are any app tabs diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index 5b3f03ab1122..47650084c3b4 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -201,6 +201,7 @@ _BROWSER_FILES = \ browser_scratchpad_ui.js \ browser_scratchpad_bug_646070_chrome_context_pref.js \ browser_overflowScroll.js \ + browser_locationBarExternalLoad.js \ browser_pageInfo.js \ browser_page_style_menu.js \ browser_pinnedTabs.js \ diff --git a/browser/base/content/test/browser_bug553455.js b/browser/base/content/test/browser_bug553455.js index bd83866bad7e..42aac1fba10f 100644 --- a/browser/base/content/test/browser_bug553455.js +++ b/browser/base/content/test/browser_bug553455.js @@ -96,11 +96,10 @@ function test_disabled_install() { wait_for_notification_close(function() { try { - Services.prefs.getBoolPref("xpinstall.disabled"); - ok(false, "xpinstall.disabled should not be set"); + ok(Services.prefs.getBoolPref("xpinstall.enabled"), "Installation should be enabled"); } catch (e) { - ok(true, "xpinstall.disabled should not be set"); + ok(false, "xpinstall.enabled should be set"); } gBrowser.removeTab(gBrowser.selectedTab); diff --git a/browser/base/content/test/browser_locationBarExternalLoad.js b/browser/base/content/test/browser_locationBarExternalLoad.js new file mode 100644 index 000000000000..8d1d470a04c8 --- /dev/null +++ b/browser/base/content/test/browser_locationBarExternalLoad.js @@ -0,0 +1,45 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + waitForExplicitFinish(); + + nextTest(); +} + +let urls = [ + "javascript:'foopy';", + "data:text/html," +]; + +function nextTest() { + let url = urls.shift(); + if (url) + testURL(url, nextTest); + else + finish(); +} + +function testURL(newURL, func) { + let tab = gBrowser.selectedTab = gBrowser.addTab(); + registerCleanupFunction(function () { + gBrowser.removeTab(tab); + }); + addPageShowListener(function () { + let pagePrincipal = gBrowser.contentPrincipal; + gURLBar.value = newURL; + gURLBar.handleCommand(); + + addPageShowListener(function () { + ok(!gBrowser.contentPrincipal.equals(pagePrincipal), "load of " + newURL + " produced a page with a different principal"); + func(); + }); + }); +} + +function addPageShowListener(func) { + gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() { + gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false); + func(); + }); +} diff --git a/browser/base/content/test/tabview/Makefile.in b/browser/base/content/test/tabview/Makefile.in index 8fa21faf7506..e8cc37f58ecc 100644 --- a/browser/base/content/test/tabview/Makefile.in +++ b/browser/base/content/test/tabview/Makefile.in @@ -64,6 +64,7 @@ _BROWSER_FILES = \ browser_tabview_bug595518.js \ browser_tabview_bug595521.js \ browser_tabview_bug595560.js \ + browser_tabview_bug595601.js \ browser_tabview_bug595804.js \ browser_tabview_bug595930.js \ browser_tabview_bug595943.js \ @@ -131,13 +132,16 @@ _BROWSER_FILES = \ browser_tabview_bug640765.js \ browser_tabview_bug641802.js \ browser_tabview_bug642793.js \ + browser_tabview_bug643392.js \ browser_tabview_bug644097.js \ browser_tabview_bug645653.js \ browser_tabview_bug648882.js \ browser_tabview_bug649006.js \ browser_tabview_bug649307.js \ + browser_tabview_bug650573.js \ browser_tabview_bug651311.js \ browser_tabview_bug654941.js \ + browser_tabview_bug656778.js \ browser_tabview_dragdrop.js \ browser_tabview_exit_button.js \ browser_tabview_expander.js \ diff --git a/browser/base/content/test/tabview/browser_tabview_bug589324.js b/browser/base/content/test/tabview/browser_tabview_bug589324.js index 24b514a46129..491c87ad13ed 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug589324.js +++ b/browser/base/content/test/tabview/browser_tabview_bug589324.js @@ -1,93 +1,121 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -function test() { - const DUMMY_PAGE_URL = "http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html"; - const DUMMY_PAGE_URL_2 = "http://mochi.test:8888/"; +const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); - let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); +const DUMMY_PAGE_URL = "http://mochi.test:8888/browser/browser/base/content/test/tabview/dummy_page.html"; +const DUMMY_PAGE_URL_2 = "http://mochi.test:8888/"; + +let state = { + windows: [{ + tabs: [{ + entries: [{ url: DUMMY_PAGE_URL }], + hidden: true, + attributes: {}, + extData: { + "tabview-tab": + '{"bounds":{"left":21,"top":29,"width":204,"height":153},' + + '"userSize":null,"url":"' + DUMMY_PAGE_URL + '","groupID":1,' + + '"imageData":null,"title":null}' + } + },{ + entries: [{ url: DUMMY_PAGE_URL_2 }], + hidden: false, + attributes: {}, + extData: { + "tabview-tab": + '{"bounds":{"left":315,"top":29,"width":111,"height":84},' + + '"userSize":null,"url":"' + DUMMY_PAGE_URL_2 + '","groupID":2,' + + '"imageData":null,"title":null}' + }, + }], + selected:2, + _closedTabs: [], + extData: { + "tabview-groups": '{"nextID":3,"activeGroupId":2}', + "tabview-group": + '{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},' + + '"userSize":null,"title":"","id":1},' + + '"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},' + + '"userSize":null,"title":"","id":2}}', + "tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":788,"height":548}}' + }, sizemode:"normal" + }] +}; + +function test() { waitForExplicitFinish(); - // open a new window and setup the window state. - let newWin = openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no"); - newWin.addEventListener("load", function(event) { - this.removeEventListener("load", arguments.callee, false); + registerCleanupFunction(function () { + Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs"); + }); - let newState = { - windows: [{ - tabs: [{ - entries: [{ url: DUMMY_PAGE_URL }], - hidden: true, - attributes: {}, - extData: { - "tabview-tab": - '{"bounds":{"left":21,"top":29,"width":204,"height":153},' + - '"userSize":null,"url":"' + DUMMY_PAGE_URL + '","groupID":1,' + - '"imageData":null,"title":null}' - } - },{ - entries: [{ url: DUMMY_PAGE_URL_2 }], - hidden: false, - attributes: {}, - extData: { - "tabview-tab": - '{"bounds":{"left":315,"top":29,"width":111,"height":84},' + - '"userSize":null,"url":"' + DUMMY_PAGE_URL_2 + '","groupID":2,' + - '"imageData":null,"title":null}' - }, - }], - selected:2, - _closedTabs: [], - extData: { - "tabview-groups": '{"nextID":3,"activeGroupId":2}', - "tabview-group": - '{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},' + - '"userSize":null,"title":"","id":1},' + - '"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},' + - '"userSize":null,"title":"","id":2}}', - "tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":788,"height":548}}' - }, sizemode:"normal" - }] - }; - ss.setWindowState(newWin, JSON.stringify(newState), true); + Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", false); - let firstTab = newWin.gBrowser.tabs[0]; - let secondTab = newWin.gBrowser.tabs[1]; + testTabSwitchAfterRestore(function () { + Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", true); - // wait until the first tab is fully loaded - let browser = newWin.gBrowser.getBrowserForTab(firstTab); - let onLoad = function() { - browser.removeEventListener("load", onLoad, true); + testTabSwitchAfterRestore(function () { + waitForFocus(finish); + }); + }); +} - is(browser.currentURI.spec, DUMMY_PAGE_URL, - "The url of first tab url is dummy_page.html"); +function testTabSwitchAfterRestore(callback) { + newWindowWithState(state, function (win) { + registerCleanupFunction(function () win.close()); - // check the hidden state of both tabs. - ok(firstTab.hidden, "The first tab is hidden"); - ok(!secondTab.hidden, "The second tab is not hidden"); - is(secondTab, newWin.gBrowser.selectedTab, "The second tab is selected"); + let [firstTab, secondTab] = win.gBrowser.tabs; + is(firstTab.linkedBrowser.currentURI.spec, DUMMY_PAGE_URL, + "The url of first tab url is dummy_page.html"); - // when the second tab is hidden, the iframe should be initialized and - // the first tab should be visible. - let onTabHide = function() { - newWin.gBrowser.tabContainer.removeEventListener("TabHide", onTabHide, true); + // check the hidden state of both tabs. + ok(firstTab.hidden, "The first tab is hidden"); + ok(!secondTab.hidden, "The second tab is not hidden"); + is(secondTab, win.gBrowser.selectedTab, "The second tab is selected"); - ok(newWin.TabView.getContentWindow(), ""); + // when the second tab is hidden, Panorama should be initialized and + // the first tab should be visible. + let container = win.gBrowser.tabContainer; + container.addEventListener("TabHide", function onTabHide() { + container.removeEventListener("TabHide", onTabHide, false); - ok(!firstTab.hidden, "The first tab is not hidden"); - is(firstTab, newWin.gBrowser.selectedTab, "The first tab is selected"); - ok(secondTab.hidden, "The second tab is hidden"); + ok(win.TabView.getContentWindow(), "Panorama is loaded"); + ok(!firstTab.hidden, "The first tab is not hidden"); + is(firstTab, win.gBrowser.selectedTab, "The first tab is selected"); + ok(secondTab.hidden, "The second tab is hidden"); - // clean up and finish - newWin.close(); + callback(); + }, false); - finish(); - }; - newWin.gBrowser.tabContainer.addEventListener("TabHide", onTabHide, true); + // switch to another tab + win.switchToTabHavingURI(DUMMY_PAGE_URL); + }); +} - // switch to another tab - newWin.switchToTabHavingURI(DUMMY_PAGE_URL); - } - browser.addEventListener("load", onLoad, true); +function newWindowWithState(state, callback) { + let opts = "chrome,all,dialog=no,height=800,width=800"; + let win = window.openDialog(getBrowserURL(), "_blank", opts); + + whenWindowLoaded(win, function () { + ss.setWindowState(win, JSON.stringify(state), true); + }); + + whenWindowStateReady(win, function () { + afterAllTabsLoaded(function () callback(win), win); + }); +} + +function whenWindowLoaded(win, callback) { + win.addEventListener("load", function onLoad() { + win.removeEventListener("load", onLoad, false); + executeSoon(callback); + }, false); +} + +function whenWindowStateReady(win, callback) { + win.addEventListener("SSWindowStateReady", function onReady() { + win.removeEventListener("SSWindowStateReady", onReady, false); + executeSoon(callback); }, false); } diff --git a/browser/base/content/test/tabview/browser_tabview_bug595560.js b/browser/base/content/test/tabview/browser_tabview_bug595560.js index 85fdca91debf..5ebeeff1723c 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug595560.js +++ b/browser/base/content/test/tabview/browser_tabview_bug595560.js @@ -1,134 +1,97 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -let newTabOne; -let originalTab; +let win; +let cw; function test() { waitForExplicitFinish(); - originalTab = gBrowser.visibleTabs[0]; - newTabOne = gBrowser.addTab("http://mochi.test:8888/"); - - let browser = gBrowser.getBrowserForTab(newTabOne); - let onLoad = function() { - browser.removeEventListener("load", onLoad, true); - - // show the tab view - window.addEventListener("tabviewshown", onTabViewWindowLoaded, false); - TabView.toggle(); - } - browser.addEventListener("load", onLoad, true); -} - -function onTabViewWindowLoaded() { - window.removeEventListener("tabviewshown", onTabViewWindowLoaded, false); - ok(TabView.isVisible(), "Tab View is visible"); - - afterAllTabItemsUpdated(function() { - let contentWindow = document.getElementById("tab-view").contentWindow; - testOne(contentWindow); - }); -} - -function testOne(contentWindow) { - onSearchEnabledAndDisabled(contentWindow, function() { - testTwo(contentWindow); - }); - // press cmd/ctrl F - EventUtils.synthesizeKey("f", { accelKey: true }); -} - -function testTwo(contentWindow) { - onSearchEnabledAndDisabled(contentWindow, function() { - testThree(contentWindow); - }); - // press / - EventUtils.synthesizeKey("VK_SLASH", { type: "keydown" }, contentWindow); -} - -function testThree(contentWindow) { - let groupItem = createEmptyGroupItem(contentWindow, 200); - - let onTabViewHidden = function() { - window.removeEventListener("tabviewhidden", onTabViewHidden, false); - TabView.toggle(); + let onLoad = function (tvwin) { + win = tvwin; + registerCleanupFunction(function () win.close()); + win.gBrowser.loadOneTab("http://mochi.test:8888/", {inBackground: true}); }; - let onTabViewShown = function() { - window.removeEventListener("tabviewshown", onTabViewShown, false); - is(contentWindow.UI.getActiveTab(), groupItem.getChild(0), + let onShow = function () { + cw = win.TabView.getContentWindow(); + ok(win.TabView.isVisible(), "Tab View is visible"); + afterAllTabItemsUpdated(testOne, win); + }; + + newWindowWithTabView(onShow, onLoad); +} + +function testOne() { + whenSearchEnabledAndDisabled(testTwo); + // press cmd/ctrl F + EventUtils.synthesizeKey("f", {accelKey: true}, cw); +} + +function testTwo() { + whenSearchEnabledAndDisabled(testThree); + // press / + EventUtils.synthesizeKey("VK_SLASH", {}, cw); +} + +function testThree() { + let onTabViewShown = function () { + is(cw.UI.getActiveTab(), groupItem.getChild(0), "The active tab is newly created tab item"); - let onSearchEnabled = function() { - contentWindow.removeEventListener( - "tabviewsearchenabled", onSearchEnabled, false); + let onSearchEnabled = function () { + let doc = cw.document; + let searchBox = cw.iQ("#searchbox"); + let hasFocus = doc.hasFocus() && doc.activeElement == searchBox[0]; + ok(hasFocus, "The search box has focus"); - let searchBox = contentWindow.iQ("#searchbox"); + let tab = win.gBrowser.tabs[1]; + searchBox.val(tab._tabViewTabItem.$tabTitle[0].innerHTML); - ok(contentWindow.document.hasFocus() && - contentWindow.document.activeElement == searchBox[0], - "The search box has focus"); - searchBox.val(newTabOne._tabViewTabItem.$tabTitle[0].innerHTML); + cw.performSearch(); - contentWindow.performSearch(); - - let checkSelectedTab = function() { - window.removeEventListener("tabviewhidden", checkSelectedTab, false); - is(newTabOne, gBrowser.selectedTab, "The search result tab is shown"); - cleanUpAndFinish(groupItem.getChild(0), contentWindow); - }; - window.addEventListener("tabviewhidden", checkSelectedTab, false); + whenTabViewIsHidden(function () { + is(tab, win.gBrowser.selectedTab, "The search result tab is shown"); + waitForFocus(finish); + }, win); // use the tabview menu (the same as pressing cmd/ctrl + e) - document.getElementById("menu_tabview").doCommand(); - }; - contentWindow.addEventListener("tabviewsearchenabled", onSearchEnabled, false); - EventUtils.synthesizeKey("VK_SLASH", { type: "keydown" }, contentWindow); + win.document.getElementById("menu_tabview").doCommand(); + }; + + whenSearchEnabled(onSearchEnabled); + EventUtils.synthesizeKey("VK_SLASH", {}, cw); }; - window.addEventListener("tabviewhidden", onTabViewHidden, false); - window.addEventListener("tabviewshown", onTabViewShown, false); - + + whenTabViewIsHidden(function () { + showTabView(onTabViewShown, win); + }, win); + // click on the + button + let groupItem = createEmptyGroupItem(cw, 300, 300, 200); let newTabButton = groupItem.container.getElementsByClassName("newTabButton"); ok(newTabButton[0], "New tab button exists"); - EventUtils.sendMouseEvent({ type: "click" }, newTabButton[0], contentWindow); + EventUtils.sendMouseEvent({type: "click"}, newTabButton[0], cw); } -function onSearchEnabledAndDisabled(contentWindow, callback) { - let onSearchEnabled = function() { - contentWindow.removeEventListener( - "tabviewsearchenabled", onSearchEnabled, false); - contentWindow.addEventListener("tabviewsearchdisabled", onSearchDisabled, false); - contentWindow.hideSearch(); - } - let onSearchDisabled = function() { - contentWindow.removeEventListener( - "tabviewsearchdisabled", onSearchDisabled, false); +function whenSearchEnabledAndDisabled(callback) { + whenSearchEnabled(function () { + whenSearchDisabled(callback); + cw.hideSearch(); + }); +} + +function whenSearchEnabled(callback) { + cw.addEventListener("tabviewsearchenabled", function onSearchEnabled() { + cw.removeEventListener("tabviewsearchenabled", onSearchEnabled, false); callback(); - } - contentWindow.addEventListener("tabviewsearchenabled", onSearchEnabled, false); + }, false); } -function cleanUpAndFinish(tabItem, contentWindow) { - gBrowser.selectedTab = originalTab; - gBrowser.removeTab(newTabOne); - gBrowser.removeTab(tabItem.tab); - - finish(); +function whenSearchDisabled(callback) { + cw.addEventListener("tabviewsearchdisabled", function onSearchDisabled() { + cw.removeEventListener("tabviewsearchdisabled", onSearchDisabled, false); + callback(); + }, false); } - -function createEmptyGroupItem(contentWindow, padding) { - let pageBounds = contentWindow.Items.getPageBounds(); - pageBounds.inset(padding, padding); - - let box = new contentWindow.Rect(pageBounds); - box.width = 300; - box.height = 300; - - let emptyGroupItem = new contentWindow.GroupItem([], { bounds: box }); - - return emptyGroupItem; -} - diff --git a/browser/base/content/test/tabview/browser_tabview_bug595601.js b/browser/base/content/test/tabview/browser_tabview_bug595601.js new file mode 100644 index 000000000000..7784d28f662c --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_bug595601.js @@ -0,0 +1,184 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); + +const TAB_STATE_NEEDS_RESTORE = 1; +const TAB_STATE_RESTORING = 2; + +let stateBackup = ss.getBrowserState(); + +let state = {windows:[{tabs:[ + // first group + {entries:[{url:"http://example.com#1"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#1\",\"groupID\":2}"}}, + {entries:[{url:"http://example.com#2"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#2\",\"groupID\":2}"}}, + {entries:[{url:"http://example.com#3"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#3\",\"groupID\":2}"}}, + {entries:[{url:"http://example.com#4"}],extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#4\",\"groupID\":2}"}}, + + // second group + {entries:[{url:"http://example.com#5"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#5\",\"groupID\":1}"}}, + {entries:[{url:"http://example.com#6"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#6\",\"groupID\":1}"}}, + {entries:[{url:"http://example.com#7"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#7\",\"groupID\":1}"}}, + {entries:[{url:"http://example.com#8"}],hidden:true,extData:{"tabview-tab":"{\"bounds\":{\"left\":20,\"top\":20,\"width\":20,\"height\":20},\"url\":\"http://example.com#8\",\"groupID\":1}"}} +],selected:5,extData:{ + "tabview-groups":"{\"nextID\":8,\"activeGroupId\":1}","tabview-group":"{\"1\":{\"bounds\":{\"left\":15,\"top\":10,\"width\":415,\"height\":367},\"userSize\":{\"x\":415,\"y\":367},\"title\":\"\",\"id\":1},\"2\":{\"bounds\":{\"left\":286,\"top\":488,\"width\":418,\"height\":313},\"title\":\"\",\"id\":2}}", + "tabview-ui":"{\"pageBounds\":{\"left\":0,\"top\":0,\"width\":940,\"height\":1075}}" +}}]}; + +function test() { + waitForExplicitFinish(); + + Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", false); + + TabsProgressListener.init(); + + registerCleanupFunction(function () { + TabsProgressListener.uninit(); + + Services.prefs.clearUserPref("browser.sessionstore.max_concurrent_tabs"); + Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs"); + + ss.setBrowserState(stateBackup); + }); + + Services.prefs.setIntPref("browser.sessionstore.max_concurrent_tabs", 3); + + TabView._initFrame(function () { + executeSoon(testRestoreWithHiddenTabs); + }); +} + +function testRestoreWithHiddenTabs() { + let checked = false; + let ssReady = false; + let tabsRestored = false; + + let check = function () { + if (checked || !ssReady || !tabsRestored) + return; + + checked = true; + + is(gBrowser.tabs.length, 8, "there are now eight tabs"); + is(gBrowser.visibleTabs.length, 4, "four visible tabs"); + + let cw = TabView.getContentWindow(); + is(cw.GroupItems.groupItems.length, 2, "there are now two groupItems"); + + testSwitchToInactiveGroup(); + } + + whenSessionStoreReady(function () { + ssReady = true; + check(); + }); + + TabsProgressListener.setCallback(function (needsRestore, isRestoring) { + if (4 < needsRestore) + return; + + TabsProgressListener.unsetCallback(); + is(needsRestore, 4, "4/8 tabs restored"); + + tabsRestored = true; + check(); + }); + + ss.setBrowserState(JSON.stringify(state)); +} + +function testSwitchToInactiveGroup() { + let firstProgress = true; + + TabsProgressListener.setCallback(function (needsRestore, isRestoring) { + if (firstProgress) { + firstProgress = false; + is(isRestoring, 3, "restoring 3 tabs concurrently"); + } else { + ok(isRestoring < 4, "restoring max. 3 tabs concurrently"); + } + + if (needsRestore) + return; + + TabsProgressListener.unsetCallback(); + + is(gBrowser.visibleTabs.length, 4, "four visible tabs"); + waitForFocus(finish); + }); + + gBrowser.selectedTab = gBrowser.tabs[4]; +} + +function whenSessionStoreReady(callback) { + window.addEventListener("SSWindowStateReady", function onReady() { + window.removeEventListener("SSWindowStateReady", onReady, false); + executeSoon(callback); + }, false); +} + +function countTabs() { + let needsRestore = 0, isRestoring = 0; + let windowsEnum = Services.wm.getEnumerator("navigator:browser"); + + while (windowsEnum.hasMoreElements()) { + let window = windowsEnum.getNext(); + if (window.closed) + continue; + + for (let i = 0; i < window.gBrowser.tabs.length; i++) { + let browser = window.gBrowser.tabs[i].linkedBrowser; + if (browser.__SS_restoreState == TAB_STATE_RESTORING) + isRestoring++; + else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) + needsRestore++; + } + } + + return [needsRestore, isRestoring]; +} + +let TabsProgressListener = { + init: function () { + gBrowser.addTabsProgressListener(this); + }, + + uninit: function () { + this.unsetCallback(); + gBrowser.removeTabsProgressListener(this); + }, + + setCallback: function (callback) { + this.callback = callback; + }, + + unsetCallback: function () { + delete this.callback; + }, + + onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { + let isNetwork = aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK; + let isWindow = aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW; + + if (!(this.callback && isNetwork && isWindow)) + return; + + let self = this; + let finalize = function () { + if (wasRestoring) + delete aBrowser.__wasRestoring; + + self.callback.apply(null, countTabs()); + }; + + let isRestoring = aBrowser.__SS_restoreState == TAB_STATE_RESTORING; + let wasRestoring = !aBrowser.__SS_restoreState && aBrowser.__wasRestoring; + let hasStopped = aStateFlags & Ci.nsIWebProgressListener.STATE_STOP; + + if (isRestoring && !hasStopped) + aBrowser.__wasRestoring = true; + + if (hasStopped && (isRestoring || wasRestoring)) + finalize(); + } +} diff --git a/browser/base/content/test/tabview/browser_tabview_bug624265.js b/browser/base/content/test/tabview/browser_tabview_bug624265.js index d51fd64f630d..e0d85e4384a2 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug624265.js +++ b/browser/base/content/test/tabview/browser_tabview_bug624265.js @@ -38,6 +38,7 @@ function test() { if (!callback) callback = finish; + assertOneSingleGroupItem(); callback(); }); } @@ -111,7 +112,7 @@ function test() { // some callback waiting to be fired after gBrowser.loadOneTab(). After // that the browser is in a state where loadURI() will create a new entry // in the session history (that is vital for back/forward functionality). - afterAllTabsLoaded(function () SimpleTest.executeSoon(continueTest)); + afterAllTabsLoaded(function () executeSoon(continueTest)); } // ---------- @@ -190,7 +191,7 @@ function enterAndLeavePrivateBrowsing(callback) { pb.privateBrowsingEnabled = false; else { Services.obs.removeObserver(pbObserver, "private-browsing-transition-complete"); - afterAllTabsLoaded(callback); + afterAllTabsLoaded(function () executeSoon(callback)); } } diff --git a/browser/base/content/test/tabview/browser_tabview_bug624727.js b/browser/base/content/test/tabview/browser_tabview_bug624727.js index fa36ed567047..fb28f2537a83 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug624727.js +++ b/browser/base/content/test/tabview/browser_tabview_bug624727.js @@ -62,7 +62,10 @@ function test() { let testStateAfterEnteringPB = function () { let prefix = 'enter'; ok(!pb.privateBrowsingEnabled, prefix + ': private browsing is disabled'); - registerCleanupFunction(function () pb.privateBrowsingEnabled = false); + registerCleanupFunction(function () { + if (pb.privateBrowsingEnabled) + pb.privateBrowsingEnabled = false + }); togglePrivateBrowsing(function () { assertTabViewIsHidden(prefix); @@ -110,6 +113,8 @@ function test() { showTabView(function () { cw = TabView.getContentWindow(); + assertNumberOfGroups('start', 1); + createGroupItem(); afterAllTabsLoaded(function () { diff --git a/browser/base/content/test/tabview/browser_tabview_bug625195.js b/browser/base/content/test/tabview/browser_tabview_bug625195.js index 29fa5e523622..9b857090436c 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug625195.js +++ b/browser/base/content/test/tabview/browser_tabview_bug625195.js @@ -16,10 +16,8 @@ function test() { showTabView(function() { registerCleanupFunction(function () { - if (gBrowser.tabs[1]) + while (gBrowser.tabs.length > 1) gBrowser.removeTab(gBrowser.tabs[1]); - if (gBrowser.tabs[2]) - gBrowser.removeTab(gBrowser.tabs[2]); TabView.hide(); }); diff --git a/browser/base/content/test/tabview/browser_tabview_bug629195.js b/browser/base/content/test/tabview/browser_tabview_bug629195.js index 469a3998ff91..8961aefe048c 100644 --- a/browser/base/content/test/tabview/browser_tabview_bug629195.js +++ b/browser/base/content/test/tabview/browser_tabview_bug629195.js @@ -109,6 +109,6 @@ function restore(groupId) { }] }; let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); - ss.setWindowState(win, JSON.stringify(newState), false); + ss.setWindowState(win, JSON.stringify(newState), true); } diff --git a/browser/base/content/test/tabview/browser_tabview_bug643392.js b/browser/base/content/test/tabview/browser_tabview_bug643392.js new file mode 100644 index 000000000000..5980cf24fbe2 --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_bug643392.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); + +let state = { + windows: [{ + tabs: [{ + entries: [{ url: "about:home" }], + hidden: true, + extData: {"tabview-tab": '{"url":"about:home","groupID":1,"bounds":{"left":20,"top":20,"width":20,"height":20}}'} + },{ + entries: [{ url: "about:home" }], + hidden: false, + extData: {"tabview-tab": '{"url":"about:home","groupID":2,"bounds":{"left":20,"top":20,"width":20,"height":20}}'}, + }], + selected: 2, + extData: { + "tabview-groups": '{"nextID":3,"activeGroupId":2}', + "tabview-group": + '{"1":{"bounds":{"left":15,"top":5,"width":280,"height":232},"id":1},' + + '"2":{"bounds":{"left":309,"top":5,"width":267,"height":226},"id":2}}' + } + }] +}; + +function test() { + waitForExplicitFinish(); + + newWindowWithState(state, function (win) { + registerCleanupFunction(function () win.close()); + + is(win.gBrowser.tabs.length, 2, "two tabs"); + + let opts = {animate: true, byMouse: true}; + win.gBrowser.removeTab(win.gBrowser.visibleTabs[0], opts); + + let checkTabCount = function () { + if (win.gBrowser.tabs.length > 1) { + executeSoon(checkTabCount); + return; + } + + is(win.gBrowser.tabs.length, 1, "one tab"); + + showTabView(function () { + let cw = win.TabView.getContentWindow(); + is(cw.TabItems.items.length, 1, "one tabItem"); + + waitForFocus(finish); + }, win); + }; + + checkTabCount(); + }); +} diff --git a/browser/base/content/test/tabview/browser_tabview_bug650573.js b/browser/base/content/test/tabview/browser_tabview_bug650573.js new file mode 100644 index 000000000000..92588824041c --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_bug650573.js @@ -0,0 +1,100 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); +let stateBackup = ss.getBrowserState(); + +function test() { + waitForExplicitFinish(); + + registerCleanupFunction(function () { + ss.setBrowserState(stateBackup); + }); + + TabView._initFrame(function() { + executeSoon(testRestoreNormal); + }); +} + +function testRestoreNormal() { + testRestore("normal", function () { + waitForBrowserState(JSON.parse(stateBackup), testRestorePinned); + }); +} + +function testRestorePinned() { + gBrowser.loadOneTab("about:blank", {inBackground: true}); + gBrowser.pinTab(gBrowser.tabs[0]); + + testRestore("pinned", function () { + waitForBrowserState(JSON.parse(stateBackup), testRestoreHidden); + }); +} + +function testRestoreHidden() { + let groupItem = createGroupItemWithBlankTabs(window, 20, 20, 20, 1); + let tabItem = groupItem.getChild(0); + + hideGroupItem(groupItem, function () { + testRestore("hidden", function () { + isnot(tabItem.container.style.display, "none", "tabItem is visible"); + waitForFocus(finish); + }); + }); +} + +function testRestore(prefix, callback) { + waitForBrowserState(createBrowserState(), function () { + is(gBrowser.tabs.length, 2, prefix + ": two tabs restored"); + + let cw = TabView.getContentWindow(); + is(cw.GroupItems.groupItems.length, 2, prefix + ": we have two groupItems"); + + let [groupItem1, groupItem2] = cw.GroupItems.groupItems; + is(groupItem1.id, "1st-group-id", prefix + ": groupItem1's ID is valid"); + is(groupItem1.getChildren().length, 1, prefix + ": groupItem1 has one child"); + + is(groupItem2.id, "2nd-group-id", prefix + ": groupItem2's ID is valid"); + is(groupItem2.getChildren().length, 1, prefix + ": groupItem2 has one child"); + + callback(); + }); +} + +function waitForBrowserState(state, callback) { + window.addEventListener("SSWindowStateReady", function onReady() { + window.removeEventListener("SSWindowStateReady", onReady, false); + executeSoon(callback); + }, false); + + ss.setBrowserState(JSON.stringify(state)); +} + +function createBrowserState() { + let bounds = {left: 20, top: 20, width: 20, height: 20}; + + let tabViewGroups = {nextID: 99, activeGroupId: 1}; + let tabViewGroup = { + "1st-group-id": {bounds: bounds, title: "new group 1", id: "1st-group-id"}, + "2nd-group-id": {bounds: bounds, title: "new group 2", id: "2nd-group-id"} + }; + + let tab1Data = {bounds: bounds, url: "about:robots", groupID: "2nd-group-id"}; + let tab1 = { + entries: [{url: "about:robots"}], + extData: {"tabview-tab": JSON.stringify(tab1Data)} + }; + + let tab2Data = {bounds: bounds, url: "about:mozilla", groupID: "1st-group-id"}; + let tab2 = { + entries: [{url: "about:mozilla"}], + extData: {"tabview-tab": JSON.stringify(tab2Data)} + }; + + return {windows: [{ + tabs: [tab1, tab2], + selected: 1, + extData: {"tabview-groups": JSON.stringify(tabViewGroups), + "tabview-group": JSON.stringify(tabViewGroup)} + }]}; +} diff --git a/browser/base/content/test/tabview/browser_tabview_bug656778.js b/browser/base/content/test/tabview/browser_tabview_bug656778.js new file mode 100644 index 000000000000..a17bdf3afcb7 --- /dev/null +++ b/browser/base/content/test/tabview/browser_tabview_bug656778.js @@ -0,0 +1,141 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + waitForExplicitFinish(); + + registerCleanupFunction(function () { + Services.prefs.clearUserPref(TabView.PREF_FIRST_RUN); + Services.prefs.clearUserPref(TabView.PREF_STARTUP_PAGE); + Services.prefs.clearUserPref(TabView.PREF_RESTORE_ENABLED_ONCE); + }); + + let assertBoolPref = function (pref, value) { + is(Services.prefs.getBoolPref(pref), value, pref + " is " + value); + }; + + let assertIntPref = function (pref, value) { + is(Services.prefs.getIntPref(pref), value, pref + " is " + value); + }; + + let setPreferences = function (startupPage, firstRun, enabledOnce) { + Services.prefs.setIntPref(TabView.PREF_STARTUP_PAGE, startupPage); + Services.prefs.setBoolPref(TabView.PREF_FIRST_RUN, firstRun); + Services.prefs.setBoolPref(TabView.PREF_RESTORE_ENABLED_ONCE, enabledOnce); + }; + + let assertPreferences = function (startupPage, firstRun, enabledOnce) { + assertIntPref(TabView.PREF_STARTUP_PAGE, startupPage); + assertBoolPref(TabView.PREF_FIRST_RUN, firstRun); + assertBoolPref(TabView.PREF_RESTORE_ENABLED_ONCE, enabledOnce); + }; + + let next = function () { + if (tests.length == 0) { + waitForFocus(finish); + return; + } + + let test = tests.shift(); + info("running " + test.name + "..."); + test(); + }; + + // State: + // Panorama was already used before (firstUseExperienced = true) but session + // restore is deactivated. We did not automatically enable SR, yet. + // + // Expected result: + // When entering Panorma session restore will be enabled and a notification + // banner is shown. + let test1 = function test1() { + setPreferences(1, true, false); + + newWindowWithTabView(function (win) { + assertPreferences(3, true, true); + + win.close(); + next(); + }); + }; + + // State: + // Panorama has not been used before (firstUseExperienced = false) and session + // restore is deactivated. We did not automatically enable SR, yet. That state + // is equal to starting the browser the first time. + // + // Expected result: + // When entering Panorma nothing happens. When we detect that Panorama is + // really used (firstUseExperienced = true) we notify that session restore + // is now enabled. + let test2 = function test2() { + setPreferences(1, false, false); + + newWindowWithTabView(function (win) { + assertPreferences(1, false, false); + + win.TabView.firstUseExperienced = true; + + assertPreferences(3, true, true); + + win.close(); + next(); + }); + }; + + // State: + // Panorama was already used before (firstUseExperienced = true) and session + // restore is activated. We did not automatically enable SR, yet. + // + // Expected result: + // When entering Panorama nothing happens because session store is already + // enabled so there's no reason to notify. + let test3 = function test3() { + setPreferences(3, true, false); + + newWindowWithTabView(function (win) { + assertPreferences(3, true, true); + + win.close(); + next(); + }); + }; + + // State: + // Panorama was already used before (firstUseExperienced = true) and session + // restore has been automatically activated. + // + // Expected result: + // When entering Panorama nothing happens. + let test4 = function test4() { + setPreferences(3, true, true); + + newWindowWithTabView(function (win) { + assertPreferences(3, true, true); + + win.close(); + next(); + }); + }; + + // State: + // Panorama was already used before (firstUseExperienced = true) and session + // restore has been automatically activated. Session store was afterwards + // disabled by the user so we won't touch that again. + // + // Expected result: + // When entering Panorama nothing happens and we didn't enable session restore. + let test5 = function test5() { + setPreferences(1, true, true); + + newWindowWithTabView(function (win) { + assertPreferences(1, true, true); + + win.close(); + next(); + }); + }; + + let tests = [test1, test2, test3, test4, test5]; + next(); +} diff --git a/browser/base/content/test/tabview/head.js b/browser/base/content/test/tabview/head.js index 83e0c1517de6..10d21b064662 100644 --- a/browser/base/content/test/tabview/head.js +++ b/browser/base/content/test/tabview/head.js @@ -93,9 +93,13 @@ function newWindowWithTabView(shownCallback, loadCallback, width, height) { // ---------- function afterAllTabsLoaded(callback, win) { + const TAB_STATE_NEEDS_RESTORE = 1; + win = win || window; let stillToLoad = 0; + let restoreHiddenTabs = Services.prefs.getBoolPref( + "browser.sessionstore.restore_hidden_tabs"); function onLoad() { this.removeEventListener("load", onLoad, true); @@ -105,8 +109,14 @@ function afterAllTabsLoaded(callback, win) { } for (let a = 0; a < win.gBrowser.tabs.length; a++) { - let browser = win.gBrowser.tabs[a].linkedBrowser; - if (browser.contentDocument.readyState != "complete" || + let tab = win.gBrowser.tabs[a]; + let browser = tab.linkedBrowser; + + let isRestorable = !(tab.hidden && !restoreHiddenTabs && + browser.__SS_restoreState && + browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE); + + if (isRestorable && browser.contentDocument.readyState != "complete" || browser.webProgress.isLoadingDocument) { stillToLoad++; browser.addEventListener("load", onLoad, true); @@ -114,7 +124,7 @@ function afterAllTabsLoaded(callback, win) { } if (!stillToLoad) - callback(); + executeSoon(callback); } // ---------- @@ -261,3 +271,33 @@ function unhideGroupItem(groupItem, callback) { }); groupItem._unhide(); } + +// ---------- +function whenWindowLoaded(win, callback) { + win.addEventListener("load", function onLoad() { + win.removeEventListener("load", onLoad, false); + executeSoon(callback); + }, false); +} + +// ---------- +function whenWindowStateReady(win, callback) { + win.addEventListener("SSWindowStateReady", function onReady() { + win.removeEventListener("SSWindowStateReady", onReady, false); + executeSoon(callback); + }, false); +} + +// ---------- +function newWindowWithState(state, callback) { + let opts = "chrome,all,dialog=no,height=800,width=800"; + let win = window.openDialog(getBrowserURL(), "_blank", opts); + + whenWindowLoaded(win, function () { + ss.setWindowState(win, JSON.stringify(state), true); + }); + + whenWindowStateReady(win, function () { + afterAllTabsLoaded(function () callback(win), win); + }); +} diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml index d9c1564b18be..366063a9a16f 100644 --- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -316,9 +316,13 @@ allowThirdPartyFixup: true}); aTriggeringEvent.preventDefault(); aTriggeringEvent.stopPropagation(); + } else { + // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from + // inheriting the currently loaded document's principal. + let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | + Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER; + gBrowser.loadURIWithFlags(url, flags, null, null, postData); } - else - loadURI(url, null, postData, true /* allow third party fixup */); gBrowser.selectedBrowser.focus(); ]]> diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp index 0172b341b0cb..b03c012ae799 100644 --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -103,6 +103,8 @@ static RedirEntry kRedirMap[] = { { "home", "chrome://browser/content/aboutHome.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | nsIAboutModule::ALLOW_SCRIPT }, + { "permissions", "chrome://browser/content/preferences/aboutPermissions.xul", + nsIAboutModule::ALLOW_SCRIPT }, }; static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap); diff --git a/browser/components/build/nsBrowserCompsCID.h b/browser/components/build/nsBrowserCompsCID.h index cd6a7c6f7e43..277f37e6570c 100644 --- a/browser/components/build/nsBrowserCompsCID.h +++ b/browser/components/build/nsBrowserCompsCID.h @@ -46,33 +46,14 @@ #ifdef XP_MACOSX #define NS_SAFARIPROFILEMIGRATOR_CID \ { 0x29e3b139, 0xad19, 0x44f3, { 0xb2, 0xc2, 0xe9, 0xf1, 0x3b, 0xa2, 0xbb, 0xc6 } } - -#define NS_MACIEPROFILEMIGRATOR_CID \ -{ 0xf1a4e549, 0x5c4b, 0x41ff, { 0xb5, 0xe3, 0xeb, 0x87, 0xae, 0x31, 0x41, 0x9b } } - -#define NS_OMNIWEBPROFILEMIGRATOR_CID \ -{ 0xb80ae6d8, 0x766c, 0x43da, { 0x9c, 0x7a, 0xd, 0x82, 0x44, 0x52, 0x61, 0x6a } } - -#define NS_CAMINOPROFILEMIGRATOR_CID \ -{ 0x01d88ea9, 0x0feb, 0x495e, { 0x8c, 0x9b, 0x41, 0x65, 0x99, 0x55, 0x52, 0x65 } } - -#define NS_ICABPROFILEMIGRATOR_CID \ -{ 0xf394a036, 0xc5e1, 0x46d8, { 0x99, 0x39, 0x6b, 0x35, 0xe1, 0x13, 0x0a, 0x27 } } - #endif #define NS_OPERAPROFILEMIGRATOR_CID \ { 0xf34ff792, 0x722e, 0x4490, { 0xb1, 0x95, 0x47, 0xd2, 0x42, 0xed, 0xca, 0x1c } } -#define NS_DOGBERTPROFILEMIGRATOR_CID \ -{ 0x24f92fae, 0xf793, 0x473b, { 0x80, 0x61, 0x71, 0x34, 0x8, 0xbd, 0x11, 0xd5 } } - #define NS_SEAMONKEYPROFILEMIGRATOR_CID \ { 0x9a28ffa7, 0xe6ef, 0x4b52, { 0xa1, 0x27, 0x6a, 0xd9, 0x51, 0xde, 0x8e, 0x9b } } -#define NS_PHOENIXPROFILEMIGRATOR_CID \ -{ 0x78481e4a, 0x50e4, 0x4489, { 0xb6, 0x8a, 0xef, 0x82, 0x67, 0xe, 0xd6, 0x3f } } - #define NS_SHELLSERVICE_CID \ { 0x63c7b9f4, 0xcc8, 0x43f8, { 0xb6, 0x66, 0xa, 0x66, 0x16, 0x55, 0xcb, 0x73 } } diff --git a/browser/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp index f3a577c9f3c6..4a557e612a8c 100644 --- a/browser/components/build/nsModule.cpp +++ b/browser/components/build/nsModule.cpp @@ -50,20 +50,14 @@ #endif #include "nsProfileMigrator.h" -#include "nsDogbertProfileMigrator.h" #if !defined(XP_OS2) #include "nsOperaProfileMigrator.h" #endif -#include "nsPhoenixProfileMigrator.h" #include "nsSeamonkeyProfileMigrator.h" #if defined(XP_WIN) && !defined(__MINGW32__) #include "nsIEProfileMigrator.h" #elif defined(XP_MACOSX) #include "nsSafariProfileMigrator.h" -#include "nsOmniWebProfileMigrator.h" -#include "nsMacIEProfileMigrator.h" -#include "nsCaminoProfileMigrator.h" -#include "nsICabProfileMigrator.h" #endif #include "rdf.h" @@ -87,21 +81,15 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacShellService) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init) #endif -NS_GENERIC_FACTORY_CONSTRUCTOR(nsDogbertProfileMigrator) #if !defined(XP_OS2) NS_GENERIC_FACTORY_CONSTRUCTOR(nsOperaProfileMigrator) #endif -NS_GENERIC_FACTORY_CONSTRUCTOR(nsPhoenixProfileMigrator) NS_GENERIC_FACTORY_CONSTRUCTOR(nsProfileMigrator) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSeamonkeyProfileMigrator) #if defined(XP_WIN) && !defined(__MINGW32__) NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEProfileMigrator) #elif defined(XP_MACOSX) NS_GENERIC_FACTORY_CONSTRUCTOR(nsSafariProfileMigrator) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsOmniWebProfileMigrator) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacIEProfileMigrator) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsCaminoProfileMigrator) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsICabProfileMigrator) #endif NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer) @@ -122,16 +110,10 @@ NS_DEFINE_NAMED_CID(NS_WINIEPROFILEMIGRATOR_CID); #elif defined(XP_MACOSX) NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID); NS_DEFINE_NAMED_CID(NS_SAFARIPROFILEMIGRATOR_CID); -NS_DEFINE_NAMED_CID(NS_MACIEPROFILEMIGRATOR_CID); -NS_DEFINE_NAMED_CID(NS_OMNIWEBPROFILEMIGRATOR_CID); -NS_DEFINE_NAMED_CID(NS_CAMINOPROFILEMIGRATOR_CID); -NS_DEFINE_NAMED_CID(NS_ICABPROFILEMIGRATOR_CID); #endif #if !defined(XP_OS2) NS_DEFINE_NAMED_CID(NS_OPERAPROFILEMIGRATOR_CID); #endif -NS_DEFINE_NAMED_CID(NS_DOGBERTPROFILEMIGRATOR_CID); -NS_DEFINE_NAMED_CID(NS_PHOENIXPROFILEMIGRATOR_CID); NS_DEFINE_NAMED_CID(NS_SEAMONKEYPROFILEMIGRATOR_CID); NS_DEFINE_NAMED_CID(NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID); @@ -150,16 +132,10 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = { #elif defined(XP_MACOSX) { &kNS_SHELLSERVICE_CID, false, NULL, nsMacShellServiceConstructor }, { &kNS_SAFARIPROFILEMIGRATOR_CID, false, NULL, nsSafariProfileMigratorConstructor }, - { &kNS_MACIEPROFILEMIGRATOR_CID, false, NULL, nsMacIEProfileMigratorConstructor }, - { &kNS_OMNIWEBPROFILEMIGRATOR_CID, false, NULL, nsOmniWebProfileMigratorConstructor }, - { &kNS_CAMINOPROFILEMIGRATOR_CID, false, NULL, nsCaminoProfileMigratorConstructor }, - { &kNS_ICABPROFILEMIGRATOR_CID, false, NULL, nsICabProfileMigratorConstructor }, #endif #if !defined(XP_OS2) { &kNS_OPERAPROFILEMIGRATOR_CID, false, NULL, nsOperaProfileMigratorConstructor }, #endif - { &kNS_DOGBERTPROFILEMIGRATOR_CID, false, NULL, nsDogbertProfileMigratorConstructor }, - { &kNS_PHOENIXPROFILEMIGRATOR_CID, false, NULL, nsPhoenixProfileMigratorConstructor }, { &kNS_SEAMONKEYPROFILEMIGRATOR_CID, false, NULL, nsSeamonkeyProfileMigratorConstructor }, { &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID, false, NULL, nsPrivateBrowsingServiceWrapperConstructor }, { NULL } @@ -186,22 +162,17 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = { { NS_ABOUT_MODULE_CONTRACTID_PREFIX "sync-tabs", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, #endif { NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, + { NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID }, { NS_PROFILEMIGRATOR_CONTRACTID, &kNS_FIREFOX_PROFILEMIGRATOR_CID }, #if defined(XP_WIN) && !defined(__MINGW32__) { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "ie", &kNS_WINIEPROFILEMIGRATOR_CID }, #elif defined(XP_MACOSX) { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID }, { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "safari", &kNS_SAFARIPROFILEMIGRATOR_CID }, - { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "macie", &kNS_MACIEPROFILEMIGRATOR_CID }, - { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "omniweb", &kNS_OMNIWEBPROFILEMIGRATOR_CID }, - { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "camino", &kNS_CAMINOPROFILEMIGRATOR_CID }, - { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "icab", &kNS_ICABPROFILEMIGRATOR_CID }, #endif #if !defined(XP_OS2) { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "opera", &kNS_OPERAPROFILEMIGRATOR_CID }, #endif - { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "dogbert", &kNS_DOGBERTPROFILEMIGRATOR_CID }, - { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "phoenix", &kNS_PHOENIXPROFILEMIGRATOR_CID }, { NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX "seamonkey", &kNS_SEAMONKEYPROFILEMIGRATOR_CID }, { NS_PRIVATE_BROWSING_SERVICE_CONTRACTID, &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID }, { NULL } diff --git a/browser/components/dirprovider/tests/unit/xpcshell.ini b/browser/components/dirprovider/tests/unit/xpcshell.ini new file mode 100644 index 000000000000..dc6d591390e8 --- /dev/null +++ b/browser/components/dirprovider/tests/unit/xpcshell.ini @@ -0,0 +1,6 @@ +[DEFAULT] +head = head_dirprovider.js +tail = + +[test_bookmark_pref.js] +[test_keys.js] diff --git a/browser/components/feeds/test/unit/xpcshell.ini b/browser/components/feeds/test/unit/xpcshell.ini new file mode 100644 index 000000000000..4300140dc73e --- /dev/null +++ b/browser/components/feeds/test/unit/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = head_feeds.js +tail = + +[test_355473.js] diff --git a/browser/components/migration/content/migration.js b/browser/components/migration/content/migration.js index 1d7fb19376f0..34688b7c81ca 100644 --- a/browser/components/migration/content/migration.js +++ b/browser/components/migration/content/migration.js @@ -128,8 +128,7 @@ var MigrationWizard = { return; } - if (migrator.sourceExists && - !(suffix == "phoenix" && !this._autoMigrate)) { + if (migrator.sourceExists) { // Save this as the first selectable item, if we don't already have // one, or if it is the migrator that was passed to us. if (!selectedMigrator || this._source == suffix) @@ -333,15 +332,11 @@ var MigrationWizard = { var source = null; switch (this._source) { case "ie": - case "macie": source = "sourceNameIE"; break; case "opera": source = "sourceNameOpera"; break; - case "dogbert": - source = "sourceNameDogbert"; - break; case "safari": source = "sourceNameSafari"; break; diff --git a/browser/components/migration/content/migration.xul b/browser/components/migration/content/migration.xul index 618fe9280532..7ec730cc0028 100644 --- a/browser/components/migration/content/migration.xul +++ b/browser/components/migration/content/migration.xul @@ -68,43 +68,21 @@ - -#ifdef XP_UNIX #ifdef XP_MACOSX - - - -#else +#elifdef XP_UNIX - - -#endif -#endif -#ifdef XP_WIN +#elifdef XP_WIN #ifndef NO_IE_MIGRATOR #endif - -#endif -#ifndef XP_UNIX -#ifndef XP_WIN +#else - -#endif #endif
  • To make the timer start on your signal and fire every 10 milliseconds of wall-clock time use: @@ -189,82 +205,87 @@ corresponding to one function. A typical section looks something like this:
    -             141300 PL_ProcessPendingEvents
    -                927 PL_ProcessEventsBeforeID
    - 29358   0   142227 PL_HandleEvent
    -              92394 nsInputStreamReadyEvent::EventHandler(PLEvent*)
    -              49181 HandlePLEvent(ReflowEvent*)
    -                481 handleTimerEvent(TimerEventType*)
    -                158 nsTransportStatusEvent::HandleEvent(PLEvent*)
    -                  9 PL_DestroyEvent
    -
    -                  4 __restore_rt
    + index  Count         Hits      Function Name
    +                           545 (46.4%) nsBlockFrame::ReflowInlineFrames(nsBlockReflowState&, nsLineList_iterator, int*)
    +                           100 (8.5%)  nsBlockFrame::ReflowDirtyLines(nsBlockReflowState&)
    + 72870      4 (0.3%)       645 (54.9%) nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&, nsLineLayout&, nsLineList_iterator, nsFlowAreaRect&, int&, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)
    +                           545 (46.4%) nsBlockFrame::ReflowInlineFrame(nsBlockReflowState&, nsLineLayout&, nsLineList_iterator, nsIFrame*, LineReflowStatus*)
    +                            83 (7.1%)  nsBlockFrame::PlaceLine(nsBlockReflowState&, nsLineLayout&, nsLineList_iterator, nsFloatManager::SavedState*, nsRect&, int&, int*)
    +                             9 (0.8%)  nsLineLayout::BeginLineReflow(int, int, int, int, int, int)
    +                             1 (0.1%)  nsTextFrame::GetType() const
    +                             1 (0.1%)  nsLineLayout::RelativePositionFrames(nsOverflowAreas&)
    +                             1 (0.1%)  __i686.get_pc_thunk.bx
    +                             1 (0.1%)  PL_ArenaAllocate
     
    The information this block tells us is:
      -
    • There were 0 profiler hits in PL_HandleEvent -
    • There were 142227 profiler hits under PL_HandleEvent. Of these: +
    • There were 4 profiler hits in nsBlockFrame::DoReflowInlineFrames +
    • There were 645 profiler hits in or under nsBlockFrame::DoReflowInlineFrames. Of these:
        -
      • 92394 were in or under nsInputStreamReadyEvent::EventHandler -
      • 49181 were in or under HandlePLEvent(ReflowEvent*) -
      • 481 were in or under handleTimerEvent -
      • 158 were in or under nsTransportStatusEvent::HandleEvent -
      • 9 were in or under PL_DestroyEvent -
      • 4 were in or under __restore_rt +
      • 545 were in or under nsBlockFrame::ReflowInlineFrame +
      • 83 were in or under nsBlockFrame::PlaceLine +
      • 9 were in or under nsLineLayout::BeginLineReflow +
      • 1 was in or under nsTextFrame::GetType +
      • 1 was in or under nsLineLayout::RelativePositionFrames +
      • 1 was in or under __i686.get_pc_thunk.bx +
      • 1 was in or under PL_ArenaAllocate
      -
    • Of these 142227 calls into PL_HandleEvent: +
    • Of these 645 calls into nsBlockFrame::DoReflowInlineFrames:
        -
      • 141300 came from PL_ProcessPendingEvents -
      • 927 came from PL_ProcessEventsBeforeID +
      • 545 came from nsBlockFrame::ReflowInlineFrames +
      • 100 came from nsBlockFrame::ReflowDirtyLines
    The rest of this section explains how to read this information off from the jprof output. -

    This block corresponds to the function PL_HandleEvent, which is +

    This block corresponds to the function nsBlockFrame::DoReflowInlineFrames, which is therefore bolded and not a link. The name of this function is preceded by -three numbers which have the following meaning. The number on the left (29358) -is the index number, and is not important. The center number (0) is the number -of times this function was interrupted by the timer. The last number (142227) -is the number of times this function was in the call stack when the timer went +five numbers which have the following meaning. The number on the left (72870) +is the index number, and is not important. The next number (4) and the +percentage following (0.3%) are the number +of times this function was interrupted by the timer and the percentage of +the total hits that is. The last number pair ("645 (54.9%)") +are the number of times this function was in the call stack when the timer went off. That is, the timer went off while we were in code that was ultimately -called from PL_HandleEvent. +called from nsBlockFrame::DoReflowInlineFrames.

    For our example we can see that our function was in the call stack for -142227 interrupt ticks, but we were never the function that was running when -the interrupt arrived. +645 interrupt ticks, but we were only the function that was running when +the interrupt arrived 4 times.

    -The functions listed above the line for PL_HandleEvent are its +The functions listed above the line for nsBlockFrame::DoReflowInlineFrames are its callers. The numbers to the left of these function names are the numbers of times these functions were in the call stack as callers of -PL_HandleEvent. In our example, we were called 927 times by -PL_ProcessEventsBeforeID and 141300 times by -PL_ProcessPendingEvents. +nsBlockFrame::DoReflowInlineFrames. In our example, we were called 545 times by +nsBlockFrame::ReflowInlineFrames and 100 times by +nsBlockFrame::ReflowDirtyLines.

    -The functions listed below the line for PL_HandleEvent are its +The functions listed below the line for nsBlockFrame::DoReflowInlineFrames are its callees. The numbers to the left of the function names are the numbers of -times these functions were in the callstack as callees of PL_HandleEvent. In our example, of the 142227 profiler hits under PL_HandleEvent 92394 were under nsInputStreamReadyEvent::EventHandler, 49181 were under HandlePLEvent(ReflowEvent*), and so forth. +times these functions were in the callstack as callees of +nsBlockFrame::DoReflowInlineFrames and the corresponding percentages. In our example, of the 645 profiler hits under nsBlockFrame::DoReflowInlineFrames 545 were under nsBlockFrame::ReflowInlineFrame, 83 were under nsBlockFrame::PlaceLine, and so forth.

    + +NOTE: If there are loops of execution or recursion, the numbers will +not add up and percentages can exceed 100%. If a function directly calls +itself "(self)" will be appended to the line, but indirect recursion will +not be marked.

    Bugs

    -Jprof has only been tested under Red Hat Linux 6.0, 6.1, and 6.2. It does -not work under 6.0, though it is possible hack up the source code and make -it work there. The way I determine the stack trace from inside the -signal handler is tightly bound to the version of glibc that is running. -If you know of a more portable way to get this information please let -me know. - -

    Update

    +The current build of Jprof has only been tested under Ubuntu 8.04 LTS, but +should work under any fairly modern linux distribution using GCC/GLIBC. +Please update this document with any known compatibilities/incompatibilities. +

    +If you get an error:

    Inconsistency detected by ld.so: dl-open.c: 260: dl_open_worker: Assertion `_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT' failed! +

    that means you've hit a timing hole in the version of glibc you're +running. See Redhat bug 4578. + diff --git a/tools/jprof/leaky.cpp b/tools/jprof/leaky.cpp index bcc6c58a2f15..4ebd3887f789 100644 --- a/tools/jprof/leaky.cpp +++ b/tools/jprof/leaky.cpp @@ -1,3 +1,4 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -128,6 +129,7 @@ leaky::leaky() quiet = TRUE; showAddress = FALSE; + showThreads = FALSE; stackDepth = 100000; mappedLogFile = -1; @@ -149,7 +151,8 @@ leaky::~leaky() void leaky::usageError() { - fprintf(stderr, "Usage: %s prog log\n", (char*) applicationName); + fprintf(stderr, "Usage: %s [-v][-t] [-e exclude] [-i include] [-s stackdepth] prog log\n", (char*) applicationName); + fprintf(stderr, "\t-v: verbose\n\t-t: split threads\n"); exit(-1); } @@ -165,14 +168,15 @@ void leaky::initialize(int argc, char** argv) int arg; int errflg = 0; - while ((arg = getopt(argc, argv, "adEe:gh:i:r:Rs:tqx")) != -1) { + while ((arg = getopt(argc, argv, "adEe:gh:i:r:Rs:tqvx")) != -1) { switch (arg) { case '?': + default: errflg++; break; case 'a': break; - case 'A': + case 'A': // not implemented showAddress = TRUE; break; case 'd': @@ -184,7 +188,7 @@ void leaky::initialize(int argc, char** argv) break; case 'g': break; - case 'r': + case 'r': // not implemented roots.add(optarg); if (!includes.IsEmpty()) { errflg++; @@ -207,7 +211,12 @@ void leaky::initialize(int argc, char** argv) case 'x': break; case 'q': - quiet = TRUE; + break; + case 'v': + quiet = !quiet; + break; + case 't': + showThreads = TRUE; break; } } @@ -265,6 +274,10 @@ void leaky::LoadMap() void leaky::open() { + int threadArray[100]; // should auto-expand + int last_thread = -1; + int numThreads=0; + LoadMap(); setupSymbols(progFile); @@ -279,7 +292,61 @@ void leaky::open() firstLogEntry = (malloc_log_entry*) mapFile(mappedLogFile, PROT_READ, &size); lastLogEntry = (malloc_log_entry*)((char*)firstLogEntry + size); - analyze(); + fprintf(stdout,"Jprof Profile Report\n"); + fprintf(stdout,"

    Jprof Profile Report

    \n"); + + if (showThreads) + { + // Find all the threads captured + + // pthread/linux docs say the signal can be delivered to any thread in + // the process. In practice, it appears in Linux that it's always + // delivered to the thread that called setitimer(), and each thread can + // have a separate itimer. There's a support library for gprof that + // overlays pthread_create() to set timers in any threads you spawn. + + // This loop walks through all the call stacks we recorded + for (malloc_log_entry* lep=firstLogEntry; + lep < lastLogEntry; + lep = reinterpret_cast(&lep->pcs[lep->numpcs])) { + if (lep->thread != last_thread) + { + int i; + for (i=0; ithread == threadArray[i]) + break; + } + if (i == numThreads && + i < (int) (sizeof(threadArray)/sizeof(threadArray[0]))) + { + threadArray[i] = lep->thread; + numThreads++; + fprintf(stderr,"new thread %d\n",lep->thread); + } + } + } + fprintf(stderr,"Num threads %d\n",numThreads); + + fprintf(stdout,"
    Threads:

    \n");
    +    for (int i=0; i%d

    \n", + threadArray[i],threadArray[i]); + } + fprintf(stdout,"


    "); + + for (int i=0; i\n"); exit(0); } @@ -428,14 +495,19 @@ void leaky::dumpEntryToLog(malloc_log_entry* lep) displayStackTrace(stdout, lep); } -void leaky::generateReportHTML(FILE *fp, int *countArray, int count) +void leaky::generateReportHTML(FILE *fp, int *countArray, int count, int thread) { - fprintf(fp,"Jprof Profile Report\n"); - fprintf(fp,"

    Jprof Profile Report

    \n"); fprintf(fp,"
    "); - fprintf(fp,"flat | hierarchical"); + if (showThreads) + { + fprintf(fp,"
    Thread: %d

    ", + thread,thread); + } + fprintf(fp,"flat | hierarchical", + thread,thread); fprintf(fp,"

    \n"); + int totalTimerHits = count; int *rankingTable = new int[usefulSymbols]; for(int cnt=usefulSymbols; --cnt>=0; rankingTable[cnt]=cnt); @@ -464,23 +536,29 @@ void leaky::generateReportHTML(FILE *fp, int *countArray, int count) // this loop. Later we can get callers and callees into it like gprof // does fprintf(fp, - "

    Hierarchical Profile


    \n"); + "

    Hierarchical Profile


    \n", + thread); fprintf(fp, "
    \n");
    -  fprintf(fp, "%5s %5s    %4s %s\n",
    -  "index", "Count", "Hits", "Function Name");
    +  fprintf(fp, "%6s %6s         %4s      %s\n",
    +          "index", "Count", "Hits", "Function Name");
     
       for(i=0; i0; i++) {
         Symbol *sp=&externalSymbols[rankingTable[i]];
         
    -    sp->cntP.printReport(fp, this);
    +    sp->cntP.printReport(fp, this, rankingTable[i], totalTimerHits);
     
         char *symname = htmlify(sp->name);
    -    fprintf(fp, "%6d %3d %8d %s\n", rankingTable[i],
    -            sp->timerHit, rankingTable[i], countArray[rankingTable[i]],
    +    fprintf(fp, "%6d %6d (%3.1f%%)%s %8d (%3.1f%%)%s %s\n", 
    +            rankingTable[i],
    +            sp->timerHit, (sp->timerHit*1000/totalTimerHits)/10.0,
    +            (sp->timerHit*1000/totalTimerHits)/10.0 >= 10.0 ? "" : " ",
    +            rankingTable[i], countArray[rankingTable[i]],
    +            (countArray[rankingTable[i]]*1000/totalTimerHits)/10.0,
    +            (countArray[rankingTable[i]]*1000/totalTimerHits)/10.0 >= 10.0 ? "" : " ",
                 symname);
         delete [] symname;
     
    -    sp->cntC.printReport(fp, this);
    +    sp->cntC.printReport(fp, this, rankingTable[i], totalTimerHits);
     
         fprintf(fp, "
    \n"); } @@ -508,14 +586,21 @@ void leaky::generateReportHTML(FILE *fp, int *countArray, int count) // I wanted the total before walking the list, if this // double-pass over externalSymbols gets slow we can // do single-pass and print this out after the loop finishes. - int totalTimerHits = 0; + totalTimerHits = 0; for(i=0; i0; i++) { Symbol *sp=&externalSymbols[rankingTable[i]]; totalTimerHits += sp->timerHit; } + if (totalTimerHits == 0) + totalTimerHits = 1; - fprintf(fp,"

    Flat Profile


    \n"); + if (totalTimerHits != count) + fprintf(stderr,"Hit count mismatch: count=%d; totalTimerHits=%d", + count,totalTimerHits); + + fprintf(fp,"

    Flat Profile


    \n", + thread); fprintf(fp, "
    \n");
     
       fprintf(fp, "Total hit count: %d\n", totalTimerHits);
    @@ -532,11 +617,9 @@ void leaky::generateReportHTML(FILE *fp, int *countArray, int count)
                 ((float)sp->timerHit/(float)totalTimerHits)*100.0, symname);
         delete [] symname;
       }
    -
    -  fprintf(fp,"
    \n"); } -void leaky::analyze() +void leaky::analyze(int thread) { int *countArray = new int[usefulSymbols]; int *flagArray = new int[usefulSymbols]; @@ -558,8 +641,11 @@ void leaky::analyze() lep < lastLogEntry; lep = reinterpret_cast(&lep->pcs[lep->numpcs])) { - if (excluded(lep) || !included(lep)) + if ((thread != 0 && lep->thread != thread) || + excluded(lep) || !included(lep)) + { continue; + } ++stacks; // How many stack frames did we collect @@ -568,7 +654,7 @@ void leaky::analyze() u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth; char** pcp = &lep->pcs[n-1]; int idx=-1, parrentIdx=-1; // Init idx incase n==0 - for(int i=n-1; i>=0; --i, --pcp, parrentIdx=idx) { + for (int i=n-1; i>=0; --i, --pcp) { idx = findSymbolIndex(reinterpret_cast(*pcp)); if(idx>=0) { @@ -593,6 +679,9 @@ void leaky::analyze() externalSymbols[parrentIdx].regChild(idx); externalSymbols[idx].regParrent(parrentIdx); } + // inside if() so an unknown in the middle of a stack won't break + // the link! + parrentIdx=idx; } } @@ -602,12 +691,12 @@ void leaky::analyze() } } - generateReportHTML(stdout, countArray, stacks); + generateReportHTML(stdout, countArray, stacks, thread); } -void FunctionCount::printReport(FILE *fp, leaky *lk) +void FunctionCount::printReport(FILE *fp, leaky *lk, int parent, int total) { - const char *fmt = " %6d %s\n"; + const char *fmt = " %8d (%3.1f%%)%s %s%s\n"; int nmax, tmax=((~0U)>>1); @@ -618,7 +707,11 @@ void FunctionCount::printReport(FILE *fp, leaky *lk) if(cnt==tmax) { int idx = getIndex(j); char *symname = htmlify(lk->indexToName(idx)); - fprintf(fp, fmt, idx, getCount(j), symname); + fprintf(fp, fmt, idx, getCount(j), + getCount(j)*100.0/total, + getCount(j)*100.0/total >= 10.0 ? "" : " ", + symname, + parent == idx ? " (self)" : ""); delete [] symname; } else if(cntnmax) { nmax=cnt; diff --git a/tools/jprof/leaky.h b/tools/jprof/leaky.h index 1b65ca23caeb..41250c58fd3f 100644 --- a/tools/jprof/leaky.h +++ b/tools/jprof/leaky.h @@ -52,7 +52,7 @@ struct leaky; class FunctionCount : public IntCount { public: - void printReport(FILE *fp, leaky *lk); + void printReport(FILE *fp, leaky *lk, int parent, int total); }; struct Symbol { @@ -90,6 +90,7 @@ struct leaky { int quiet; int showAddress; + int showThreads; u_int stackDepth; int mappedLogFile; @@ -115,7 +116,7 @@ struct leaky { void LoadMap(); - void analyze(); + void analyze(int thread); void dumpEntryToLog(malloc_log_entry* lep); @@ -133,7 +134,7 @@ struct leaky { const char* indexToName(int idx) {return externalSymbols[idx].name;} private: - void generateReportHTML(FILE *fp, int *countArray, int count); + void generateReportHTML(FILE *fp, int *countArray, int count, int thread); int findSymbolIndex(u_long address); }; diff --git a/tools/jprof/stub/Makefile.in b/tools/jprof/stub/Makefile.in index 52757a9673d3..8da3eac1b19f 100644 --- a/tools/jprof/stub/Makefile.in +++ b/tools/jprof/stub/Makefile.in @@ -48,6 +48,9 @@ EXPORTS = LIBRARY_NAME = jprof EXPORT_LIBRARY = 1 +# override optimization +MOZ_OPTIMIZE_FLAGS = -fno-omit-frame-pointer + CPPSRCS = \ libmalloc.cpp \ $(NULL) diff --git a/tools/jprof/stub/libmalloc.cpp b/tools/jprof/stub/libmalloc.cpp index 5e092e956c9f..5a81e7a53603 100644 --- a/tools/jprof/stub/libmalloc.cpp +++ b/tools/jprof/stub/libmalloc.cpp @@ -23,6 +23,7 @@ * Jim Nance * L. David Baron - JP_REALTIME, JPROF_PTHREAD_HACK, and SIGUSR1 handling * Mike Shaver - JP_RTC_HZ support + * Randell Jesup - glibc backtrace() support * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -61,7 +62,9 @@ #include #include #include +#include #include +#include #include "libmalloc.h" #include "jprof.h" @@ -77,6 +80,10 @@ extern r_debug _r_debug; #include #endif +#define USE_GLIBC_BACKTRACE 1 +// To debug, use #define JPROF_STATIC +#define JPROF_STATIC //static + static int gLogFD = -1; static pthread_t main_thread; @@ -87,9 +94,32 @@ static int enableRTCSignals(bool enable); //---------------------------------------------------------------------- #if defined(i386) || defined(_i386) || defined(__x86_64__) -static void CrawlStack(malloc_log_entry* me, - void* stack_top, void* top_instr_ptr) +JPROF_STATIC void CrawlStack(malloc_log_entry* me, + void* stack_top, void* top_instr_ptr) { +#if USE_GLIBC_BACKTRACE + // This probably works on more than x86! But we need a way to get the + // top instruction pointer, which is kindof arch-specific + void *array[500]; + int cnt, i; + u_long numpcs = 0; + bool tracing = false; + + // This is from glibc. A more generic version might use + // libunwind and/or CaptureStackBackTrace() on Windows + cnt = backtrace(&array[0],sizeof(array)/sizeof(array[0])); + + // StackHook->JprofLog->CrawlStack + // Then we have sigaction, which replaced top_instr_ptr + array[3] = top_instr_ptr; + for (i = 3; i < cnt; i++) + { + me->pcs[numpcs++] = (char *) array[i]; + } + me->numpcs = numpcs; + +#else + // original code - this breaks on many platforms void **bp; #if defined(__i386) __asm__( "movl %%ebp, %0" : "=g"(bp)); @@ -102,6 +132,7 @@ static void CrawlStack(malloc_log_entry* me, bp = __builtin_frame_address(0); #endif u_long numpcs = 0; + bool tracing = false; me->pcs[numpcs++] = (char*) top_instr_ptr; @@ -111,13 +142,17 @@ static void CrawlStack(malloc_log_entry* me, if (nextbp < bp) { break; } - if (bp > stack_top) { + if (tracing) { // Skip the signal handling. me->pcs[numpcs++] = (char*) pc; } + else if (pc == top_instr_ptr) { + tracing = true; + } bp = nextbp; } me->numpcs = numpcs; +#endif } #endif @@ -169,13 +204,14 @@ static void EndProfilingHook(int signum) //---------------------------------------------------------------------- -static void -Log(u_long aTime, void* stack_top, void* top_instr_ptr) +JPROF_STATIC void +JprofLog(u_long aTime, void* stack_top, void* top_instr_ptr) { // Static is simply to make debugging tollerable static malloc_log_entry me; me.delTime = aTime; + me.thread = syscall(SYS_gettid); //gettid(); CrawlStack(&me, stack_top, top_instr_ptr); @@ -281,7 +317,7 @@ static int enableRTCSignals(bool enable) } #endif -static void StackHook( +JPROF_STATIC void StackHook( int signum, siginfo_t *info, void *ucontext) @@ -325,9 +361,9 @@ void *ucontext) gregset_t &gregs = ((ucontext_t*)ucontext)->uc_mcontext.gregs; #ifdef __x86_64__ - Log(millisec, (void*)gregs[REG_RSP], (void*)gregs[REG_RIP]); + JprofLog(millisec, (void*)gregs[REG_RSP], (void*)gregs[REG_RIP]); #else - Log(millisec, (void*)gregs[REG_ESP], (void*)gregs[REG_EIP]); + JprofLog(millisec, (void*)gregs[REG_ESP], (void*)gregs[REG_EIP]); #endif if (!rtcHz) @@ -371,21 +407,26 @@ NS_EXPORT_(void) setupProfilingStuff(void) char *delay = strstr(tst,"JP_PERIOD="); if(delay) { - double tmp = strtod(delay+10, NULL); - if(tmp>1e-3) { + double tmp = strtod(delay+strlen("JP_PERIOD="), NULL); + if (tmp>=1e-3) { timerMiliSec = static_cast(1000 * tmp); - } + } else { + fprintf(stderr, + "JP_PERIOD of %g less than 0.001 (1ms), using 1ms\n", + tmp); + timerMiliSec = 1; + } } char *first = strstr(tst, "JP_FIRST="); if(first) { - firstDelay = atol(first+9); + firstDelay = atol(first+strlen("JP_FIRST=")); } char *rtc = strstr(tst, "JP_RTC_HZ="); if (rtc) { #if defined(linux) - rtcHz = atol(rtc+10); + rtcHz = atol(rtc+strlen("JP_RTC_HZ=")); timerMiliSec = 0; /* This makes JP_FIRST work right. */ realTime = 1; /* It's the _R_TC and all. ;) */ @@ -420,6 +461,8 @@ NS_EXPORT_(void) setupProfilingStuff(void) atexit(DumpAddressMap); main_thread = pthread_self(); + //fprintf(stderr,"jprof: main_thread = %u\n", + // (unsigned int)main_thread); sigemptyset(&mset); action.sa_handler = NULL; diff --git a/tools/jprof/stub/libmalloc.h b/tools/jprof/stub/libmalloc.h index 80e7b57cca0a..b6d40a1fe8c0 100644 --- a/tools/jprof/stub/libmalloc.h +++ b/tools/jprof/stub/libmalloc.h @@ -52,6 +52,7 @@ typedef unsigned long u_long; struct malloc_log_entry { u_long delTime; u_long numpcs; + int thread; char* pcs[MAX_STACK_CRAWL]; }; diff --git a/tools/update-packaging/common.sh b/tools/update-packaging/common.sh index 1b7d4ca7797b..b2e3562a6086 100755 --- a/tools/update-packaging/common.sh +++ b/tools/update-packaging/common.sh @@ -108,7 +108,7 @@ append_remove_instructions() { fixedprefix="" else f=$(echo $f | sed -e 's:^\.\.\/::') - fixedprefix=$(echo "$prefix" | sed -e 's:^[^\/]*\/::') + fixedprefix=$(echo "$prefix" | sed -e 's:[^\/]*\/$::') fi fi fi diff --git a/tools/update-packaging/make_incremental_updates.py b/tools/update-packaging/make_incremental_updates.py index 6a196d416bbf..3fe8ce317bd3 100755 --- a/tools/update-packaging/make_incremental_updates.py +++ b/tools/update-packaging/make_incremental_updates.py @@ -302,9 +302,15 @@ def process_explicit_remove_files(dir_path, patch_info): for line in lines: # Exclude any blank and comment lines. if line and not line.startswith("#"): + if prefix != "": + if line.startswith("../"): + line = line.replace("../../", "") + line = line.replace("../", "Contents/") + else: + line = os.path.join(prefix,line) # Python on windows uses \ for path separators and the update # manifests expects / for path separators on all platforms. - line=os.path.join(prefix,line).replace("\\", "/") + line = line.replace("\\", "/") patch_info.append_remove_instruction(line) def create_partial_patch(from_dir_path, to_dir_path, patch_filename, shas, patch_info, forced_updates): diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index f0e14bc98df3..00c10f832cb0 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -109,6 +109,7 @@ #endif #include "nsIPluginHost.h" // XXX needed for ext->type mapping (bug 233289) +#include "nsPluginHost.h" #include "nsEscape.h" #include "nsIStringBundle.h" // XXX needed to localize error msgs @@ -2758,7 +2759,8 @@ NS_IMETHODIMP nsExternalHelperAppService::GetTypeFromExtension(const nsACString& const nsCString& flatExt = PromiseFlatCString(aFileExt); // Try the plugins const char* mimeType; - nsCOMPtr pluginHost (do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv)); + nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID, &rv)); + nsPluginHost* pluginHost = static_cast(pluginHostCOM.get()); if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(pluginHost->IsPluginEnabledForExtension(flatExt.get(), mimeType))) { aContentType = mimeType; diff --git a/uriloader/exthandler/tests/unit/xpcshell.ini b/uriloader/exthandler/tests/unit/xpcshell.ini new file mode 100644 index 000000000000..1ec0e6ce3236 --- /dev/null +++ b/uriloader/exthandler/tests/unit/xpcshell.ini @@ -0,0 +1,8 @@ +[DEFAULT] +head = head_handlerService.js +tail = tail_handlerService.js + +[test_getTypeFromExtension_ext_to_type_mapping.js] +[test_getTypeFromExtension_with_empty_Content_Type.js] +[test_handlerService.js] +[test_punycodeURIs.js] diff --git a/uriloader/exthandler/tests/unit_ipc/xpcshell.ini b/uriloader/exthandler/tests/unit_ipc/xpcshell.ini new file mode 100644 index 000000000000..a68bd041733c --- /dev/null +++ b/uriloader/exthandler/tests/unit_ipc/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = +tail = + +[test_encoding.js] diff --git a/widget/public/nsGUIEvent.h b/widget/public/nsGUIEvent.h index ddea45e1bd0e..3747057b2262 100644 --- a/widget/public/nsGUIEvent.h +++ b/widget/public/nsGUIEvent.h @@ -415,6 +415,12 @@ class nsHashKey; // Query if the DOM element under nsEvent::refPoint belongs to our widget // or not. #define NS_QUERY_DOM_WIDGET_HITTEST (NS_QUERY_CONTENT_EVENT_START + 9) +// Query for some information about mouse wheel event's target +// XXX This is used only for supporting high resolution mouse scroll on Windows +// and it's going to be reimplemented with another approach. At that time, +// this even is going to be removed. Therefore, DON'T use this event for +// other purpose. +#define NS_QUERY_SCROLL_TARGET_INFO (NS_QUERY_CONTENT_EVENT_START + 99) // Video events #ifdef MOZ_MEDIA @@ -1188,9 +1194,11 @@ public: // as needed. kNoDefer = 1 << 5, // For scrollable views, indicates scroll should not // occur asynchronously. - kIsMomentum = 1 << 6 // Marks scroll events that aren't controlled by the + kIsMomentum = 1 << 6, // Marks scroll events that aren't controlled by the // user but fire automatically as the result of a // "momentum" scroll. + kAllowSmoothScroll = 1 << 7 // Allow smooth scroll for the pixel scroll + // event. }; nsMouseScrollEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w) @@ -1285,6 +1293,13 @@ public: refPoint = aPoint; } + void InitForQueryScrollTargetInfo(nsMouseScrollEvent* aEvent) + { + NS_ASSERTION(message == NS_QUERY_SCROLL_TARGET_INFO, + "wrong initializer is called"); + mInput.mMouseScrollEvent = aEvent; + } + PRUint32 GetSelectionStart(void) const { NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, @@ -1304,6 +1319,8 @@ public: struct { PRUint32 mOffset; PRUint32 mLength; + // used by NS_QUERY_SCROLL_TARGET_INFO + nsMouseScrollEvent* mMouseScrollEvent; } mInput; struct { void* mContentsRoot; @@ -1317,6 +1334,10 @@ public: PRPackedBool mWidgetIsHit; // true if DOM element under mouse belongs to widget // used by NS_QUERY_SELECTION_AS_TRANSFERABLE nsCOMPtr mTransferable; + // used by NS_QUERY_SCROLL_TARGET_INFO + PRInt32 mLineHeight; + PRInt32 mPageWidth; + PRInt32 mPageHeight; } mReply; enum { @@ -1620,15 +1641,7 @@ enum nsDragDropEventStatus { ((evnt)->message == NS_PLUGIN_FOCUS)) #define NS_IS_QUERY_CONTENT_EVENT(evnt) \ - (((evnt)->message == NS_QUERY_SELECTED_TEXT) || \ - ((evnt)->message == NS_QUERY_TEXT_CONTENT) || \ - ((evnt)->message == NS_QUERY_CARET_RECT) || \ - ((evnt)->message == NS_QUERY_TEXT_RECT) || \ - ((evnt)->message == NS_QUERY_EDITOR_RECT) || \ - ((evnt)->message == NS_QUERY_CONTENT_STATE) || \ - ((evnt)->message == NS_QUERY_SELECTION_AS_TRANSFERABLE) || \ - ((evnt)->message == NS_QUERY_CHARACTER_AT_POINT) || \ - ((evnt)->message == NS_QUERY_DOM_WIDGET_HITTEST)) + ((evnt)->eventStructType == NS_QUERY_CONTENT_EVENT) #define NS_IS_SELECTION_EVENT(evnt) \ (((evnt)->message == NS_SELECTION_SET)) @@ -1670,7 +1683,8 @@ enum nsDragDropEventStatus { // cases, you should use NS_IS_IME_RELATED_EVENT instead. #define NS_IS_IME_RELATED_EVENT(evnt) \ (NS_IS_IME_EVENT(evnt) || \ - NS_IS_QUERY_CONTENT_EVENT(evnt) || \ + (NS_IS_QUERY_CONTENT_EVENT(evnt) && \ + evnt->message != NS_QUERY_SCROLL_TARGET_INFO) || \ NS_IS_SELECTION_EVENT(evnt)) /* diff --git a/widget/public/nsGUIEventIPC.h b/widget/public/nsGUIEventIPC.h index 9c1cb2be9696..78901256e199 100644 --- a/widget/public/nsGUIEventIPC.h +++ b/widget/public/nsGUIEventIPC.h @@ -109,6 +109,50 @@ struct ParamTraits } }; +template<> +struct ParamTraits +{ + typedef nsMouseEvent_base paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, static_cast(aParam)); + WriteParam(aMsg, aParam.button); + WriteParam(aMsg, aParam.pressure); + WriteParam(aMsg, aParam.inputSource); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, static_cast(aResult)) && + ReadParam(aMsg, aIter, &aResult->button) && + ReadParam(aMsg, aIter, &aResult->pressure) && + ReadParam(aMsg, aIter, &aResult->inputSource); + } +}; + +template<> +struct ParamTraits +{ + typedef nsMouseScrollEvent paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, static_cast(aParam)); + WriteParam(aMsg, aParam.scrollFlags); + WriteParam(aMsg, aParam.delta); + WriteParam(aMsg, aParam.scrollOverflow); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, static_cast(aResult)) && + ReadParam(aMsg, aIter, &aResult->scrollFlags) && + ReadParam(aMsg, aIter, &aResult->delta) && + ReadParam(aMsg, aIter, &aResult->scrollOverflow); + } +}; + template<> struct ParamTraits { @@ -235,12 +279,16 @@ struct ParamTraits WriteParam(aMsg, aParam.mSucceeded); WriteParam(aMsg, aParam.mInput.mOffset); WriteParam(aMsg, aParam.mInput.mLength); + WriteParam(aMsg, *aParam.mInput.mMouseScrollEvent); WriteParam(aMsg, aParam.mReply.mOffset); WriteParam(aMsg, aParam.mReply.mString); WriteParam(aMsg, aParam.mReply.mRect); WriteParam(aMsg, aParam.mReply.mReversed); WriteParam(aMsg, aParam.mReply.mHasSelection); WriteParam(aMsg, aParam.mReply.mWidgetIsHit); + WriteParam(aMsg, aParam.mReply.mLineHeight); + WriteParam(aMsg, aParam.mReply.mPageHeight); + WriteParam(aMsg, aParam.mReply.mPageWidth); } static bool Read(const Message* aMsg, void** aIter, paramType* aResult) @@ -250,12 +298,16 @@ struct ParamTraits ReadParam(aMsg, aIter, &aResult->mSucceeded) && ReadParam(aMsg, aIter, &aResult->mInput.mOffset) && ReadParam(aMsg, aIter, &aResult->mInput.mLength) && + ReadParam(aMsg, aIter, aResult->mInput.mMouseScrollEvent) && ReadParam(aMsg, aIter, &aResult->mReply.mOffset) && ReadParam(aMsg, aIter, &aResult->mReply.mString) && ReadParam(aMsg, aIter, &aResult->mReply.mRect) && ReadParam(aMsg, aIter, &aResult->mReply.mReversed) && ReadParam(aMsg, aIter, &aResult->mReply.mHasSelection) && - ReadParam(aMsg, aIter, &aResult->mReply.mWidgetIsHit); + ReadParam(aMsg, aIter, &aResult->mReply.mWidgetIsHit) && + ReadParam(aMsg, aIter, &aResult->mReply.mLineHeight) && + ReadParam(aMsg, aIter, &aResult->mReply.mPageHeight) && + ReadParam(aMsg, aIter, &aResult->mReply.mPageWidth); } }; diff --git a/widget/public/nsILookAndFeel.h b/widget/public/nsILookAndFeel.h index 5d79c3f77efc..57dc89242553 100644 --- a/widget/public/nsILookAndFeel.h +++ b/widget/public/nsILookAndFeel.h @@ -43,10 +43,10 @@ // for |#ifdef NS_DEBUG| struct nsSize; -// 2e89c566-0a31-4c93-bdff-222651df45a0 +// 89401022-94b3-413e-a6b8-2203dab824f3 #define NS_ILOOKANDFEEL_IID \ -{ 0x2e89c566, 0x0a31, 0x4c93, \ - { 0xbd, 0xff, 0x22, 0x26, 0x51, 0xdf, 0x45, 0xa0 } } +{ 0x89401022, 0x94b3, 0x413e, \ + { 0xa6, 0xb8, 0x22, 0x03, 0xda, 0xb8, 0x24, 0xf3 } } class nsILookAndFeel: public nsISupports { public: @@ -326,6 +326,7 @@ public: }; enum { + eMetric_ScrollArrowNone = 0, eMetric_ScrollArrowStartBackward = 0x1000, eMetric_ScrollArrowStartForward = 0x0100, eMetric_ScrollArrowEndBackward = 0x0010, diff --git a/widget/reftests/progressbar-fallback-default-style-ref.html b/widget/reftests/progressbar-fallback-default-style-ref.html index 19cee0169171..30918cf36c91 100644 --- a/widget/reftests/progressbar-fallback-default-style-ref.html +++ b/widget/reftests/progressbar-fallback-default-style-ref.html @@ -29,6 +29,8 @@ height: 100%; width: 100%; + -moz-box-sizing: border-box; + /* Default style in case of there is -moz-appearance: none; */ background-color: ThreeDShadow; } diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index c728a53af1f0..663a23091b9a 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -69,7 +69,7 @@ #include "nsGfxCIID.h" #include "nsIMenuRollup.h" #include "nsIDOMSimpleGestureEvent.h" -#include "nsIPluginInstance.h" +#include "nsNPAPIPluginInstance.h" #include "nsThemeConstants.h" #include "nsDragService.h" @@ -717,8 +717,8 @@ void nsChildView::HidePlugin() [(ChildView*)mView pluginDrawingModel] == NPDrawingModelQuickDraw) { NPWindow* window; mPluginInstanceOwner->GetWindow(window); - nsCOMPtr instance; - mPluginInstanceOwner->GetInstance(*getter_AddRefs(instance)); + nsRefPtr instance; + mPluginInstanceOwner->GetInstance(getter_AddRefs(instance)); if (window && instance) { window->clipRect.top = 0; window->clipRect.left = 0; @@ -1182,8 +1182,8 @@ void nsChildView::PaintQD() updateEvent.what = updateEvt; updateEvent.message = UInt32(window); - nsCOMPtr instance; - mPluginInstanceOwner->GetInstance(*getter_AddRefs(instance)); + nsRefPtr instance; + mPluginInstanceOwner->GetInstance(getter_AddRefs(instance)); instance->HandleEvent(&updateEvent, nsnull); EndDrawPlugin(); diff --git a/widget/src/cocoa/nsLookAndFeel.mm b/widget/src/cocoa/nsLookAndFeel.mm index f4e49f2e517e..576d91b761db 100644 --- a/widget/src/cocoa/nsLookAndFeel.mm +++ b/widget/src/cocoa/nsLookAndFeel.mm @@ -343,22 +343,25 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricID aID, PRInt32 & aMetric) aMetric = 4; break; case eMetric_ScrollArrowStyle: - { - NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; - if ([buttonPlacement isEqualToString:@"Single"]) { - aMetric = eMetric_ScrollArrowStyleSingle; - } else if ([buttonPlacement isEqualToString:@"DoubleMin"]) { - aMetric = eMetric_ScrollArrowStyleBothAtTop; - } else if ([buttonPlacement isEqualToString:@"DoubleBoth"]) { - aMetric = eMetric_ScrollArrowStyleBothAtEachEnd; + if (nsToolkit::OnLionOrLater()) { + // OS X Lion's scrollbars have no arrows + aMetric = eMetric_ScrollArrowNone; } else { - aMetric = eMetric_ScrollArrowStyleBothAtBottom; // The default is BothAtBottom. + NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; + if ([buttonPlacement isEqualToString:@"Single"]) { + aMetric = eMetric_ScrollArrowStyleSingle; + } else if ([buttonPlacement isEqualToString:@"DoubleMin"]) { + aMetric = eMetric_ScrollArrowStyleBothAtTop; + } else if ([buttonPlacement isEqualToString:@"DoubleBoth"]) { + aMetric = eMetric_ScrollArrowStyleBothAtEachEnd; + } else { + aMetric = eMetric_ScrollArrowStyleBothAtBottom; // The default is BothAtBottom. + } } - } - break; + break; case eMetric_ScrollSliderStyle: - aMetric = eMetric_ScrollThumbStyleProportional; - break; + aMetric = eMetric_ScrollThumbStyleProportional; + break; case eMetric_TreeOpenDelay: aMetric = 1000; break; diff --git a/widget/src/cocoa/nsMenuItemIconX.mm b/widget/src/cocoa/nsMenuItemIconX.mm index 3605a8c89d23..107a10ba12da 100644 --- a/widget/src/cocoa/nsMenuItemIconX.mm +++ b/widget/src/cocoa/nsMenuItemIconX.mm @@ -548,8 +548,7 @@ NS_IMETHODIMP nsMenuItemIconX::OnStopRequest(imgIRequest* aRequest, PRBool aIsLastPart) { - NS_ASSERTION(mIconRequest, "NULL mIconRequest! Multiple calls to OnStopRequest()?"); - if (mIconRequest) { + if (mIconRequest && mIconRequest == aRequest) { mIconRequest->Cancel(NS_BINDING_ABORTED); mIconRequest = nsnull; } diff --git a/widget/src/cocoa/nsNativeThemeCocoa.mm b/widget/src/cocoa/nsNativeThemeCocoa.mm index fe4255384eee..4831fe9b396d 100644 --- a/widget/src/cocoa/nsNativeThemeCocoa.mm +++ b/widget/src/cocoa/nsNativeThemeCocoa.mm @@ -1137,40 +1137,82 @@ nsNativeThemeCocoa::DrawFrame(CGContextRef cgContext, HIThemeFrameKind inKind, NS_OBJC_END_TRY_ABORT_BLOCK; } -static const CellRenderSettings progressSettings[2] = { - // Determined settings. +static const CellRenderSettings progressSettings[2][2] = { + // Vertical progress bar. { + // Determined settings. { - NSZeroSize, // mini - NSMakeSize(0, 10), // small - NSMakeSize(0, 16) // regular + { + NSZeroSize, // mini + NSMakeSize(10, 0), // small + NSMakeSize(16, 0) // regular + }, + { + NSZeroSize, NSZeroSize, NSZeroSize + }, + { + { // Leopard + {0, 0, 0, 0}, // mini + {1, 1, 1, 1}, // small + {1, 1, 1, 1} // regular + } + } }, + // There is no horizontal margin in regular undetermined size. { - NSZeroSize, NSZeroSize, NSZeroSize - }, - { - { // Leopard - {0, 0, 0, 0}, // mini - {1, 1, 1, 1}, // small - {1, 1, 1, 1} // regular + { + NSZeroSize, // mini + NSMakeSize(10, 0), // small + NSMakeSize(16, 0) // regular + }, + { + NSZeroSize, NSZeroSize, NSZeroSize + }, + { + { // Leopard + {0, 0, 0, 0}, // mini + {1, 1, 1, 1}, // small + {1, 0, 1, 0} // regular + } } } }, - // There is no horizontal margin in regular undetermined size. + // Horizontal progress bar. { + // Determined settings. { - NSZeroSize, // mini - NSMakeSize(0, 10), // small - NSMakeSize(0, 16) // regular + { + NSZeroSize, // mini + NSMakeSize(0, 10), // small + NSMakeSize(0, 16) // regular + }, + { + NSZeroSize, NSZeroSize, NSZeroSize + }, + { + { // Leopard + {0, 0, 0, 0}, // mini + {1, 1, 1, 1}, // small + {1, 1, 1, 1} // regular + } + } }, + // There is no horizontal margin in regular undetermined size. { - NSZeroSize, NSZeroSize, NSZeroSize - }, - { - { // Leopard - {0, 0, 0, 0}, // mini - {1, 1, 1, 1}, // small - {0, 1, 0, 1} // regular + { + NSZeroSize, // mini + NSMakeSize(0, 10), // small + NSMakeSize(0, 16) // regular + }, + { + NSZeroSize, NSZeroSize, NSZeroSize + }, + { + { // Leopard + {0, 0, 0, 0}, // mini + {1, 1, 1, 1}, // small + {0, 1, 0, 1} // regular + } } } } @@ -1194,7 +1236,7 @@ nsNativeThemeCocoa::DrawProgress(CGContextRef cgContext, const HIRect& inBoxRect : NSClearControlTint)]; DrawCellWithSnapping(cell, cgContext, inBoxRect, - progressSettings[inIsIndeterminate], + progressSettings[inIsHorizontal][inIsIndeterminate], VerticalAlignFactor(aFrame), mCellDrawView, IsFrameRTL(aFrame)); @@ -1428,9 +1470,12 @@ nsNativeThemeCocoa::GetScrollbarDrawInfo(HIThemeTrackDrawInfo& aTdi, nsIFrame *a aTdi.trackInfo.scrollbar.pressState = 0; - // Only go get these scrollbar button states if we need it. For example, there's no reaon to look up scrollbar button - // states when we're only creating a TrackDrawInfo to determine the size of the thumb. - if (aShouldGetButtonStates) { + // Only go get these scrollbar button states if we need it. For example, + // there's no reason to look up scrollbar button states when we're only + // creating a TrackDrawInfo to determine the size of the thumb. There's + // also no reason to do this on Lion or later, whose scrollbars have no + // arrow buttons. + if (aShouldGetButtonStates && !nsToolkit::OnLionOrLater()) { nsEventStates buttonStates[4]; GetScrollbarPressStates(aFrame, buttonStates); NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; @@ -1892,8 +1937,8 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsRenderingContext* aContext, NS_WARNING("Unable to animate progressbar!"); } DrawProgress(cgContext, macRect, IsIndeterminateProgress(aFrame, eventState), - PR_TRUE, GetProgressValue(aFrame), - GetProgressMaxValue(aFrame), aFrame); + aFrame->GetStyleDisplay()->mOrient != NS_STYLE_ORIENT_VERTICAL, + GetProgressValue(aFrame), GetProgressMaxValue(aFrame), aFrame); break; case NS_THEME_PROGRESSBAR_VERTICAL: @@ -2155,23 +2200,26 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext, case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL: case NS_THEME_SCROLLBAR_TRACK_VERTICAL: { - // There's only an endcap to worry about when both arrows are on the bottom - NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; - if (!buttonPlacement || [buttonPlacement isEqualToString:@"DoubleMax"]) { - PRBool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL); + // On Lion and later, scrollbars have no arrows. + if (!nsToolkit::OnLionOrLater()) { + // There's only an endcap to worry about when both arrows are on the bottom + NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; + if (!buttonPlacement || [buttonPlacement isEqualToString:@"DoubleMax"]) { + PRBool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL); - nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame); - if (!scrollbarFrame) return NS_ERROR_FAILURE; - PRBool isSmall = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL); + nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame); + if (!scrollbarFrame) return NS_ERROR_FAILURE; + PRBool isSmall = (scrollbarFrame->GetStyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL); - // There isn't a metric for this, so just hardcode a best guess at the value. - // This value is even less exact due to the fact that the endcap is partially concave. - PRInt32 endcapSize = isSmall ? 5 : 6; + // There isn't a metric for this, so just hardcode a best guess at the value. + // This value is even less exact due to the fact that the endcap is partially concave. + PRInt32 endcapSize = isSmall ? 5 : 6; - if (isHorizontal) - aResult->SizeTo(endcapSize, 0, 0, 0); - else - aResult->SizeTo(0, endcapSize, 0, 0); + if (isHorizontal) + aResult->SizeTo(endcapSize, 0, 0, 0); + else + aResult->SizeTo(0, endcapSize, 0, 0); + } } break; } diff --git a/widget/src/cocoa/nsToolkit.h b/widget/src/cocoa/nsToolkit.h index c849facc029c..e19e2e397865 100644 --- a/widget/src/cocoa/nsToolkit.h +++ b/widget/src/cocoa/nsToolkit.h @@ -48,6 +48,7 @@ #define MAC_OS_X_VERSION_10_5_HEX 0x00001050 #define MAC_OS_X_VERSION_10_6_HEX 0x00001060 +#define MAC_OS_X_VERSION_10_7_HEX 0x00001070 class nsToolkit : public nsIToolkit { @@ -60,6 +61,7 @@ public: static PRInt32 OSXVersion(); static PRBool OnSnowLeopardOrLater(); + static PRBool OnLionOrLater(); static void PostSleepWakeNotification(const char* aNotification); diff --git a/widget/src/cocoa/nsToolkit.mm b/widget/src/cocoa/nsToolkit.mm index 2142654317e9..041f29974d17 100644 --- a/widget/src/cocoa/nsToolkit.mm +++ b/widget/src/cocoa/nsToolkit.mm @@ -407,6 +407,11 @@ PRBool nsToolkit::OnSnowLeopardOrLater() return (OSXVersion() >= MAC_OS_X_VERSION_10_6_HEX); } +PRBool nsToolkit::OnLionOrLater() +{ + return (OSXVersion() >= MAC_OS_X_VERSION_10_7_HEX); +} + // An alternative to [NSObject poseAsClass:] that isn't deprecated on OS X // Leopard and is available to 64-bit binaries on Leopard and above. Based on // ideas and code from http://www.cocoadev.com/index.pl?MethodSwizzling. diff --git a/widget/src/gtk2/gtk2drawing.c b/widget/src/gtk2/gtk2drawing.c index d824ed65d8bd..4417a101dfe7 100644 --- a/widget/src/gtk2/gtk2drawing.c +++ b/widget/src/gtk2/gtk2drawing.c @@ -2248,28 +2248,38 @@ moz_gtk_progress_chunk_paint(GdkDrawable* drawable, GdkRectangle* rect, TSOffsetStyleGCs(style, rect->x, rect->y); - if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE) { + if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE || + widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) { /** - * The bar's width and the bar speed are set depending of the progress - * bar size. These could also be constant for all progress bars easily. + * The bar's size and the bar speed are set depending of the progress' + * size. These could also be constant for all progress bars easily. */ + gboolean vertical = (widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE); + + /* The size of the dimension we are going to use for the animation. */ + const gint progressSize = vertical ? rect->height : rect->width; /* The bar is using a fifth of the element size, based on GtkProgressBar * activity-blocks property. */ - const gint barWidth = MAX(1, rect->width / 5); + const gint barSize = MAX(1, progressSize / 5); /* Represents the travel that has to be done for a complete cycle. */ - const gint travel = 2 * (rect->width - barWidth); + const gint travel = 2 * (progressSize - barSize); /* period equals to travel / pixelsPerMillisecond - * where pixelsPerMillisecond equals rect->width / 1000.0. + * where pixelsPerMillisecond equals progressSize / 1000.0. * This is equivalent to 1600. */ - const guint period = 1600; + static const guint period = 1600; const gint t = PR_IntervalToMilliseconds(PR_IntervalNow()) % period; const gint dx = travel * t / period; - rect->x += (dx < travel / 2) ? dx : travel - dx; - rect->width = barWidth; + if (vertical) { + rect->y += (dx < travel / 2) ? dx : travel - dx; + rect->height = barSize; + } else { + rect->x += (dx < travel / 2) ? dx : travel - dx; + rect->width = barSize; + } } gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, @@ -2986,6 +2996,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, case MOZ_GTK_GRIPPER: case MOZ_GTK_PROGRESS_CHUNK: case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE: + case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE: case MOZ_GTK_EXPANDER: case MOZ_GTK_TREEVIEW_EXPANDER: case MOZ_GTK_TOOLBAR_SEPARATOR: @@ -3333,6 +3344,7 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, break; case MOZ_GTK_PROGRESS_CHUNK: case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE: + case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE: return moz_gtk_progress_chunk_paint(drawable, rect, cliprect, direction, widget); break; diff --git a/widget/src/gtk2/gtkdrawing.h b/widget/src/gtk2/gtkdrawing.h index 32bdc719f798..74763d2bbbe4 100644 --- a/widget/src/gtk2/gtkdrawing.h +++ b/widget/src/gtk2/gtkdrawing.h @@ -180,6 +180,8 @@ typedef enum { MOZ_GTK_PROGRESS_CHUNK, /* Paints a progress chunk of an indeterminated GtkProgressBar. */ MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE, + /* Paints a progress chunk of a vertical indeterminated GtkProgressBar. */ + MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE, /* Paints a tab of a GtkNotebook. flags is a GtkTabFlags, defined above. */ MOZ_GTK_TAB, /* Paints the background and border of a GtkNotebook. */ diff --git a/widget/src/gtk2/nsDragService.cpp b/widget/src/gtk2/nsDragService.cpp index 1caa30184543..feaca717b22e 100644 --- a/widget/src/gtk2/nsDragService.cpp +++ b/widget/src/gtk2/nsDragService.cpp @@ -1585,8 +1585,7 @@ nsDragService::SourceDataGet(GtkWidget *aWidget, } } -/* static */ -void +static void invisibleSourceDragDataGet(GtkWidget *aWidget, GdkDragContext *aContext, GtkSelectionData *aSelectionData, @@ -1600,8 +1599,7 @@ invisibleSourceDragDataGet(GtkWidget *aWidget, aSelectionData, aInfo, aTime); } -/* static */ -gboolean +static gboolean invisibleSourceDragFailed(GtkWidget *aWidget, GdkDragContext *aContext, gint aResult, @@ -1620,8 +1618,7 @@ invisibleSourceDragFailed(GtkWidget *aWidget, return FALSE; } -/* static */ -void +static void invisibleSourceDragEnd(GtkWidget *aWidget, GdkDragContext *aContext, gpointer aData) diff --git a/widget/src/gtk2/nsNativeThemeGTK.cpp b/widget/src/gtk2/nsNativeThemeGTK.cpp index 9ff182139095..800271f122e8 100644 --- a/widget/src/gtk2/nsNativeThemeGTK.cpp +++ b/widget/src/gtk2/nsNativeThemeGTK.cpp @@ -571,7 +571,9 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame, nsEventStates eventStates = GetContentState(stateFrame, aWidgetType); aGtkWidgetType = IsIndeterminateProgress(stateFrame, eventStates) - ? MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE + ? (stateFrame->GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL) + ? MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE + : MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE : MOZ_GTK_PROGRESS_CHUNK; } break; @@ -881,7 +883,8 @@ nsNativeThemeGTK::DrawWidgetBackground(nsRenderingContext* aContext, } // Indeterminate progress bar are animated. - if (gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE) { + if (gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE || + gtkWidgetType == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) { if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 30)) { NS_WARNING("unable to animate widget!"); } diff --git a/widget/src/gtk2/nsWindow.cpp b/widget/src/gtk2/nsWindow.cpp index 009271834ddd..8e40828136b0 100644 --- a/widget/src/gtk2/nsWindow.cpp +++ b/widget/src/gtk2/nsWindow.cpp @@ -255,7 +255,7 @@ static gboolean drag_drop_event_cb (GtkWidget *aWidget, gint aX, gint aY, guint aTime, - gpointer *aData); + gpointer aData); static void drag_data_received_event_cb(GtkWidget *aWidget, GdkDragContext *aDragContext, gint aX, @@ -3619,7 +3619,7 @@ nsWindow::OnDragDropEvent(GtkWidget *aWidget, gint aX, gint aY, guint aTime, - gpointer *aData) + gpointer aData) { LOGDRAG(("nsWindow::OnDragDropSignal\n")); @@ -5251,7 +5251,7 @@ nsWindow::HideWindowChrome(PRBool aShouldHide) return NS_OK; } -PRBool +static PRBool check_for_rollup(GdkWindow *aWindow, gdouble aMouseX, gdouble aMouseY, PRBool aIsWheel, PRBool aAlwaysRollup) { @@ -5322,8 +5322,7 @@ nsWindow::DragInProgress(void) return (sLastDragMotionWindow || sIsDraggingOutOf); } -/* static */ -PRBool +static PRBool is_mouse_in_window (GdkWindow* aWindow, gdouble aMouseX, gdouble aMouseY) { gint x = 0; @@ -5364,8 +5363,7 @@ is_mouse_in_window (GdkWindow* aWindow, gdouble aMouseX, gdouble aMouseY) return PR_FALSE; } -/* static */ -nsWindow * +static nsWindow * get_window_for_gtk_widget(GtkWidget *widget) { gpointer user_data = g_object_get_data(G_OBJECT(widget), "nsWindow"); @@ -5373,8 +5371,7 @@ get_window_for_gtk_widget(GtkWidget *widget) return static_cast(user_data); } -/* static */ -nsWindow * +static nsWindow * get_window_for_gdk_window(GdkWindow *window) { gpointer user_data = g_object_get_data(G_OBJECT(window), "nsWindow"); @@ -5382,8 +5379,7 @@ get_window_for_gdk_window(GdkWindow *window) return static_cast(user_data); } -/* static */ -GtkWidget * +static GtkWidget * get_gtk_widget_for_gdk_window(GdkWindow *window) { gpointer user_data = NULL; @@ -5392,8 +5388,7 @@ get_gtk_widget_for_gdk_window(GdkWindow *window) return GTK_WIDGET(user_data); } -/* static */ -GdkCursor * +static GdkCursor * get_gtk_cursor(nsCursor aCursor) { GdkPixmap *cursor; @@ -5548,8 +5543,7 @@ get_gtk_cursor(nsCursor aCursor) // gtk callbacks -/* static */ -gboolean +static gboolean expose_event_cb(GtkWidget *widget, GdkEventExpose *event) { nsRefPtr window = get_window_for_gdk_window(event->window); @@ -5568,8 +5562,7 @@ expose_event_cb(GtkWidget *widget, GdkEventExpose *event) return FALSE; } -/* static */ -gboolean +static gboolean configure_event_cb(GtkWidget *widget, GdkEventConfigure *event) { @@ -5580,8 +5573,7 @@ configure_event_cb(GtkWidget *widget, return window->OnConfigureEvent(widget, event); } -/* static */ -void +static void container_unrealize_cb (GtkWidget *widget) { nsRefPtr window = get_window_for_gtk_widget(widget); @@ -5591,8 +5583,7 @@ container_unrealize_cb (GtkWidget *widget) window->OnContainerUnrealize(widget); } -/* static */ -void +static void size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation) { nsRefPtr window = get_window_for_gtk_widget(widget); @@ -5602,8 +5593,7 @@ size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation) window->OnSizeAllocate(widget, allocation); } -/* static */ -gboolean +static gboolean delete_event_cb(GtkWidget *widget, GdkEventAny *event) { nsRefPtr window = get_window_for_gtk_widget(widget); @@ -5615,8 +5605,7 @@ delete_event_cb(GtkWidget *widget, GdkEventAny *event) return TRUE; } -/* static */ -gboolean +static gboolean enter_notify_event_cb(GtkWidget *widget, GdkEventCrossing *event) { @@ -5629,8 +5618,7 @@ enter_notify_event_cb(GtkWidget *widget, return TRUE; } -/* static */ -gboolean +static gboolean leave_notify_event_cb(GtkWidget *widget, GdkEventCrossing *event) { @@ -5657,7 +5645,7 @@ leave_notify_event_cb(GtkWidget *widget, return TRUE; } -nsWindow* +static nsWindow* GetFirstNSWindowForGDKWindow(GdkWindow *aGdkWindow) { nsWindow* window; @@ -5674,8 +5662,7 @@ GetFirstNSWindowForGDKWindow(GdkWindow *aGdkWindow) return window; } -/* static */ -gboolean +static gboolean motion_notify_event_cb(GtkWidget *widget, GdkEventMotion *event) { UpdateLastInputEventTime(); @@ -5692,8 +5679,7 @@ motion_notify_event_cb(GtkWidget *widget, GdkEventMotion *event) return TRUE; } -/* static */ -gboolean +static gboolean button_press_event_cb(GtkWidget *widget, GdkEventButton *event) { UpdateLastInputEventTime(); @@ -5707,8 +5693,7 @@ button_press_event_cb(GtkWidget *widget, GdkEventButton *event) return TRUE; } -/* static */ -gboolean +static gboolean button_release_event_cb(GtkWidget *widget, GdkEventButton *event) { UpdateLastInputEventTime(); @@ -5722,8 +5707,7 @@ button_release_event_cb(GtkWidget *widget, GdkEventButton *event) return TRUE; } -/* static */ -gboolean +static gboolean focus_in_event_cb(GtkWidget *widget, GdkEventFocus *event) { nsRefPtr window = get_window_for_gtk_widget(widget); @@ -5735,8 +5719,7 @@ focus_in_event_cb(GtkWidget *widget, GdkEventFocus *event) return FALSE; } -/* static */ -gboolean +static gboolean focus_out_event_cb(GtkWidget *widget, GdkEventFocus *event) { nsRefPtr window = get_window_for_gtk_widget(widget); @@ -5767,7 +5750,7 @@ focus_out_event_cb(GtkWidget *widget, GdkEventFocus *event) // example), a request to make the parent window active is issued. When the // parent window becomes active, keyboard events will be received. -GdkFilterReturn +static GdkFilterReturn popup_take_focus_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) @@ -5811,8 +5794,7 @@ popup_take_focus_filter(GdkXEvent *gdk_xevent, return GDK_FILTER_REMOVE; } -/* static */ -GdkFilterReturn +static GdkFilterReturn plugin_window_filter_func(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) { GdkWindow *plugin_window; @@ -5870,8 +5852,7 @@ plugin_window_filter_func(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) return return_val; } -/* static */ -GdkFilterReturn +static GdkFilterReturn plugin_client_message_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) @@ -5905,8 +5886,7 @@ plugin_client_message_filter(GdkXEvent *gdk_xevent, } #endif /* MOZ_X11 */ -/* static */ -gboolean +static gboolean key_press_event_cb(GtkWidget *widget, GdkEventKey *event) { LOG(("key_press_event_cb\n")); @@ -5949,7 +5929,7 @@ key_press_event_cb(GtkWidget *widget, GdkEventKey *event) return focusWindow->OnKeyPressEvent(widget, event); } -gboolean +static gboolean key_release_event_cb(GtkWidget *widget, GdkEventKey *event) { LOG(("key_release_event_cb\n")); @@ -5966,8 +5946,7 @@ key_release_event_cb(GtkWidget *widget, GdkEventKey *event) return focusWindow->OnKeyReleaseEvent(widget, event); } -/* static */ -gboolean +static gboolean scroll_event_cb(GtkWidget *widget, GdkEventScroll *event) { nsWindow *window = GetFirstNSWindowForGDKWindow(event->window); @@ -5979,8 +5958,7 @@ scroll_event_cb(GtkWidget *widget, GdkEventScroll *event) return TRUE; } -/* static */ -gboolean +static gboolean visibility_notify_event_cb (GtkWidget *widget, GdkEventVisibility *event) { nsRefPtr window = get_window_for_gdk_window(event->window); @@ -6030,8 +6008,7 @@ hierarchy_changed_cb (GtkWidget *widget, } } -/* static */ -gboolean +static gboolean window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event) { nsRefPtr window = get_window_for_gtk_widget(widget); @@ -6043,8 +6020,7 @@ window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event) return FALSE; } -/* static */ -void +static void theme_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data) { nsRefPtr window = data; @@ -6103,8 +6079,7 @@ nsWindow::UpdateDragStatus(GdkDragContext *aDragContext, } -/* static */ -gboolean +static gboolean drag_motion_event_cb(GtkWidget *aWidget, GdkDragContext *aDragContext, gint aX, @@ -6120,8 +6095,8 @@ drag_motion_event_cb(GtkWidget *aWidget, aDragContext, aX, aY, aTime, aData); } -/* static */ -void + +static void drag_leave_event_cb(GtkWidget *aWidget, GdkDragContext *aDragContext, guint aTime, @@ -6135,14 +6110,13 @@ drag_leave_event_cb(GtkWidget *aWidget, } -/* static */ -gboolean +static gboolean drag_drop_event_cb(GtkWidget *aWidget, GdkDragContext *aDragContext, gint aX, gint aY, guint aTime, - gpointer *aData) + gpointer aData) { nsRefPtr window = get_window_for_gtk_widget(aWidget); if (!window) @@ -6153,8 +6127,7 @@ drag_drop_event_cb(GtkWidget *aWidget, aX, aY, aTime, aData); } -/* static */ -void +static void drag_data_received_event_cb(GtkWidget *aWidget, GdkDragContext *aDragContext, gint aX, @@ -6175,8 +6148,7 @@ drag_data_received_event_cb(GtkWidget *aWidget, aInfo, aTime, aData); } -/* static */ -nsresult +static nsresult initialize_prefs(void) { nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); @@ -6221,8 +6193,7 @@ nsWindow::DragLeaveTimerCallback(nsITimer *aTimer, void *aClosure) window->FireDragLeaveTimer(); } -/* static */ -GdkWindow * +static GdkWindow * get_inner_gdk_window (GdkWindow *aWindow, gint x, gint y, gint *retx, gint *rety) @@ -6249,7 +6220,7 @@ get_inner_gdk_window (GdkWindow *aWindow, return aWindow; } -inline PRBool +static inline PRBool is_context_menu_key(const nsKeyEvent& aKeyEvent) { return ((aKeyEvent.keyCode == NS_VK_F10 && aKeyEvent.isShift && @@ -6258,7 +6229,7 @@ is_context_menu_key(const nsKeyEvent& aKeyEvent) !aKeyEvent.isControl && !aKeyEvent.isMeta && !aKeyEvent.isAlt)); } -void +static void key_event_to_context_menu_event(nsMouseEvent &aEvent, GdkEventKey *aGdkEvent) { @@ -6271,8 +6242,7 @@ key_event_to_context_menu_event(nsMouseEvent &aEvent, aEvent.clickCount = 1; } -/* static */ -int +static int is_parent_ungrab_enter(GdkEventCrossing *aEvent) { return (GDK_CROSSING_UNGRAB == aEvent->mode) && @@ -6281,8 +6251,7 @@ is_parent_ungrab_enter(GdkEventCrossing *aEvent) } -/* static */ -int +static int is_parent_grab_leave(GdkEventCrossing *aEvent) { return (GDK_CROSSING_GRAB == aEvent->mode) && diff --git a/widget/src/gtk2/nsWindow.h b/widget/src/gtk2/nsWindow.h index 3d8f1cbefc05..5a161204bede 100644 --- a/widget/src/gtk2/nsWindow.h +++ b/widget/src/gtk2/nsWindow.h @@ -241,7 +241,7 @@ public: gint aX, gint aY, guint aTime, - void *aData); + gpointer aData); void OnDragLeaveEvent(GtkWidget * aWidget, GdkDragContext *aDragContext, guint aTime, @@ -251,7 +251,7 @@ public: gint aX, gint aY, guint aTime, - gpointer *aData); + gpointer aData); void OnDragDataReceivedEvent(GtkWidget *aWidget, GdkDragContext *aDragContext, gint aX, diff --git a/widget/src/windows/nsAppShell.cpp b/widget/src/windows/nsAppShell.cpp index 082e96e61880..2ee951247997 100644 --- a/widget/src/windows/nsAppShell.cpp +++ b/widget/src/windows/nsAppShell.cpp @@ -38,6 +38,7 @@ * * ***** END LICENSE BLOCK ***** */ +#include "mozilla/ipc/RPCChannel.h" #include "nsAppShell.h" #include "nsToolkit.h" #include "nsThreadUtils.h" @@ -307,6 +308,9 @@ nsAppShell::ProcessNextNativeEvent(PRBool mayWait) } #endif + // Notify ipc we are spinning a (possibly nested) gecko event loop. + mozilla::ipc::RPCChannel::NotifyGeckoEventDispatch(); + PRBool gotMessage = PR_FALSE; do { diff --git a/widget/src/windows/nsNativeThemeWin.cpp b/widget/src/windows/nsNativeThemeWin.cpp index b6152f0db6f8..7975db480824 100644 --- a/widget/src/windows/nsNativeThemeWin.cpp +++ b/widget/src/windows/nsNativeThemeWin.cpp @@ -349,18 +349,14 @@ static CaptionButtonPadding buttonData[3] = { * These values are found by experimenting and comparing against native widgets * used by the system. They are very unlikely exact but try to not be too wrong. */ -// PP_CHUNK is overflowing on the bottom for no appearant reasons. -// This is a fix around this issue. -static const PRInt32 kProgressDeterminedXPOverflow = 11; -// Same thing but for PP_FILL. -static const PRInt32 kProgressDeterminedVistaOverflow = 4; -// Same thing but for indeterminate progress bar. -// The value is the same for PP_CHUNK and PP_MOVEOVERLAY in that case. -static const PRInt32 kProgressIndeterminateOverflow = 2; -// The width of the overlay used to animate the progress bar (Vista and later). -static const PRInt32 kProgressVistaOverlayWidth = 120; -// The width of the overlay used to for indeterminate progress bars on XP. -static const PRInt32 kProgressXPOverlayWidth = 55; +// The width of the overlay used to animate the horizontal progress bar (Vista and later). +static const PRInt32 kProgressHorizontalVistaOverlaySize = 120; +// The width of the overlay used for the horizontal indeterminate progress bars on XP. +static const PRInt32 kProgressHorizontalXPOverlaySize = 55; +// The height of the overlay used to animate the vertical progress bar (Vista and later). +static const PRInt32 kProgressVerticalOverlaySize = 45; +// The height of the overlay used for the vertical indeterminate progress bar (Vista and later). +static const PRInt32 kProgressVerticalIndeterminateOverlaySize = 60; // Speed (px per ms) of the animation for determined Vista and later progress bars. static const double kProgressDeterminedVistaSpeed = 0.225; // Speed (px per ms) of the animation for indeterminate progress bars. @@ -680,17 +676,24 @@ nsNativeThemeWin::GetThemePartAndState(nsIFrame* aFrame, PRUint8 aWidgetType, return NS_OK; } case NS_THEME_PROGRESSBAR: { - aPart = PP_BAR; + aPart = IsVerticalProgress(aFrame) ? PP_BARVERT : PP_BAR; aState = TS_NORMAL; return NS_OK; } case NS_THEME_PROGRESSBAR_CHUNK: { nsIFrame* stateFrame = aFrame->GetParent(); nsEventStates eventStates = GetContentState(stateFrame, aWidgetType); - // If the element is indeterminate, we are going to render it ourself so - // we have to return aPart = -1. - aPart = IsIndeterminateProgress(stateFrame, eventStates) - ? -1 : nsUXThemeData::sIsVistaOrLater ? PP_FILL : PP_CHUNK; + + if (IsIndeterminateProgress(stateFrame, eventStates)) { + // If the element is indeterminate, we are going to render it ourself so + // we have to return aPart = -1. + aPart = -1; + } else if (IsVerticalProgress(stateFrame)) { + aPart = nsUXThemeData::sIsVistaOrLater ? PP_FILLVERT : PP_CHUNKVERT; + } else { + aPart = nsUXThemeData::sIsVistaOrLater ? PP_FILL : PP_CHUNK; + } + aState = TS_NORMAL; return NS_OK; } @@ -1326,14 +1329,6 @@ RENDER_AGAIN: } else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) { OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE); - } else if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK) { - nsIFrame* stateFrame = aFrame->GetParent(); - nsEventStates eventStates = GetContentState(stateFrame, aWidgetType); - widgetRect.bottom -= IsIndeterminateProgress(stateFrame, eventStates) - ? kProgressIndeterminateOverflow - : nsUXThemeData::sIsVistaOrLater - ? kProgressDeterminedVistaOverflow - : kProgressDeterminedXPOverflow; } // widgetRect is the bounding box for a widget, yet the scale track is only @@ -1583,43 +1578,75 @@ RENDER_AGAIN: nsIFrame* stateFrame = aFrame->GetParent(); nsEventStates eventStates = GetContentState(stateFrame, aWidgetType); bool indeterminate = IsIndeterminateProgress(stateFrame, eventStates); + bool vertical = IsVerticalProgress(stateFrame); if (indeterminate || nsUXThemeData::sIsVistaOrLater) { if (!QueueAnimatedContentForRefresh(aFrame->GetContent(), 60)) { NS_WARNING("unable to animate progress widget!"); } - const PRInt32 overlayWidth = nsUXThemeData::sIsVistaOrLater - ? kProgressVistaOverlayWidth - : kProgressXPOverlayWidth; + /** + * Unfortunately, vertical progress bar support on Windows seems weak and + * PP_MOVEOVERLAYRECT looks really different from PP_MOVEOVERLAY. + * Thus, we have to change the size and even don't use it for vertical + * indeterminate progress bars. + */ + PRInt32 overlaySize; + if (nsUXThemeData::sIsVistaOrLater) { + if (vertical) { + overlaySize = indeterminate ? kProgressVerticalIndeterminateOverlaySize + : kProgressVerticalOverlaySize; + } else { + overlaySize = kProgressHorizontalVistaOverlaySize; + } + } else { + overlaySize = kProgressHorizontalXPOverlaySize; + } + const double pixelsPerMillisecond = indeterminate ? kProgressIndeterminateSpeed : kProgressDeterminedVistaSpeed; const PRInt32 delay = indeterminate ? kProgressIndeterminateDelay : kProgressDeterminedVistaDelay; - const PRInt32 frameWidth = widgetRect.right - widgetRect.left; - const PRInt32 animationWidth = frameWidth + overlayWidth + + const PRInt32 frameSize = vertical ? widgetRect.bottom - widgetRect.top + : widgetRect.right - widgetRect.left; + const PRInt32 animationSize = frameSize + overlaySize + static_cast(pixelsPerMillisecond * delay); - const double interval = animationWidth / pixelsPerMillisecond; + const double interval = animationSize / pixelsPerMillisecond; // We have to pass a double* to modf and we can't pass NULL. double tempValue; double ratio = modf(PR_IntervalToMilliseconds(PR_IntervalNow())/interval, &tempValue); // If the frame direction is RTL, we want to have the animation going RTL. // ratio is in [0.0; 1.0[ range, inverting it reverse the animation. - if (IsFrameRTL(aFrame)) { + if (!vertical && IsFrameRTL(aFrame)) { ratio = 1.0 - ratio; } - PRInt32 dx = static_cast(animationWidth * ratio) - overlayWidth; + PRInt32 dx = static_cast(animationSize * ratio) - overlaySize; RECT overlayRect = widgetRect; - overlayRect.left += dx; - overlayRect.right = overlayRect.left + overlayWidth; - nsUXThemeData::drawThemeBG(theme, hdc, - nsUXThemeData::sIsVistaOrLater ? PP_MOVEOVERLAY - : PP_CHUNK, - state, &overlayRect, &clipRect); + if (vertical) { + overlayRect.bottom -= dx; + overlayRect.top = overlayRect.bottom - overlaySize; + } else { + overlayRect.left += dx; + overlayRect.right = overlayRect.left + overlaySize; + } + + PRInt32 overlayPart; + if (vertical) { + if (nsUXThemeData::sIsVistaOrLater) { + overlayPart = indeterminate ? PP_MOVEOVERLAY : PP_MOVEOVERLAYVERT; + } else { + overlayPart = PP_CHUNKVERT; + } + } else { + overlayPart = nsUXThemeData::sIsVistaOrLater ? PP_MOVEOVERLAY : PP_CHUNK; + } + + nsUXThemeData::drawThemeBG(theme, hdc, overlayPart, state, &overlayRect, + &clipRect); } } diff --git a/widget/src/windows/nsUXThemeConstants.h b/widget/src/windows/nsUXThemeConstants.h index 28e2edc29f8f..afab8117ce60 100644 --- a/widget/src/windows/nsUXThemeConstants.h +++ b/widget/src/windows/nsUXThemeConstants.h @@ -117,7 +117,9 @@ #define PP_CHUNK 3 #define PP_CHUNKVERT 4 #define PP_FILL 5 +#define PP_FILLVERT 6 #define PP_MOVEOVERLAY 8 +#define PP_MOVEOVERLAYVERT 9 // Tab constants #define TABP_TAB 4 diff --git a/widget/src/windows/nsWindow.cpp b/widget/src/windows/nsWindow.cpp index 8dd2e2de26e6..c2271a30dd66 100644 --- a/widget/src/windows/nsWindow.cpp +++ b/widget/src/windows/nsWindow.cpp @@ -298,6 +298,19 @@ PRUint32 nsWindow::sOOPPPluginFocusEvent = MSG nsWindow::sRedirectedKeyDown; +PRBool nsWindow::sEnablePixelScrolling = PR_TRUE; +PRBool nsWindow::sNeedsToInitMouseWheelSettings = PR_TRUE; +ULONG nsWindow::sMouseWheelScrollLines = 0; +ULONG nsWindow::sMouseWheelScrollChars = 0; + +HWND nsWindow::sLastMouseWheelWnd = NULL; +PRInt32 nsWindow::sRemainingDeltaForScroll = 0; +PRInt32 nsWindow::sRemainingDeltaForPixel = 0; +PRBool nsWindow::sLastMouseWheelDeltaIsPositive = PR_FALSE; +PRBool nsWindow::sLastMouseWheelOrientationIsVertical = PR_FALSE; +PRBool nsWindow::sLastMouseWheelUnitIsPage = PR_FALSE; +PRUint32 nsWindow::sLastMouseWheelTime = 0; + /************************************************************** * * SECTION: globals variables @@ -655,6 +668,11 @@ nsWindow::Create(nsIWidget *aParent, if (NS_SUCCEEDED(prefBranch->GetBoolPref("mozilla.widget.disable-native-theme", &temp))) gDisableNativeTheme = temp; + + if (NS_SUCCEEDED(prefBranch->GetBoolPref("mousewheel.enable_pixel_scrolling", + &temp))) { + sEnablePixelScrolling = temp; + } } } } @@ -4524,8 +4542,6 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, PRBool result = PR_FALSE; // call the default nsWindow proc *aRetValue = 0; - static PRBool getWheelInfo = PR_TRUE; - #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN // Glass hit testing w/custom transparent margins LRESULT dwmHitResult; @@ -5187,7 +5203,12 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, break; case WM_SETTINGCHANGE: - getWheelInfo = PR_TRUE; + switch (wParam) { + case SPI_SETWHEELSCROLLLINES: + case SPI_SETWHEELSCROLLCHARS: + sNeedsToInitMouseWheelSettings = PR_TRUE; + break; + } break; case WM_INPUTLANGCHANGEREQUEST: @@ -5259,8 +5280,9 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, // If OnMouseWheel returns false, OnMouseWheel processed the event internally. // 'result' and 'aRetValue' will be set based on what we did with the event, so // we should fall through. - if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue)) + if (OnMouseWheel(msg, wParam, lParam, result, aRetValue)) { return result; + } } break; @@ -6281,118 +6303,158 @@ PRUint16 nsWindow::GetMouseInputSource() return inputSource; } +/* static */ void +nsWindow::InitMouseWheelScrollData() +{ + if (!sNeedsToInitMouseWheelSettings) { + return; + } + sNeedsToInitMouseWheelSettings = PR_FALSE; + ResetRemainingWheelDelta(); + + if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, + &sMouseWheelScrollLines, 0)) { + NS_WARNING("Failed to get SPI_GETWHEELSCROLLLINES"); + sMouseWheelScrollLines = 3; + } else if (sMouseWheelScrollLines > WHEEL_DELTA) { + // sMouseWheelScrollLines usually equals 3 or 0 (for no scrolling) + // However, if sMouseWheelScrollLines > WHEEL_DELTA, we assume that + // the mouse driver wants a page scroll. The docs state that + // sMouseWheelScrollLines should explicitly equal WHEEL_PAGESCROLL, but + // since some mouse drivers use an arbitrary large number instead, + // we have to handle that as well. + sMouseWheelScrollLines = WHEEL_PAGESCROLL; + } + + if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, + &sMouseWheelScrollChars, 0)) { + NS_ASSERTION(!nsUXThemeData::sIsVistaOrLater, + "Failed to get SPI_GETWHEELSCROLLCHARS"); + sMouseWheelScrollChars = 1; + } else if (sMouseWheelScrollChars > WHEEL_DELTA) { + // See the comments for the case sMouseWheelScrollLines > WHEEL_DELTA. + sMouseWheelScrollChars = WHEEL_PAGESCROLL; + } +} + +/* static */ +void +nsWindow::ResetRemainingWheelDelta() +{ + sRemainingDeltaForPixel = 0; + sRemainingDeltaForScroll = 0; + sLastMouseWheelWnd = NULL; +} + +static PRInt32 RoundDelta(double aDelta) +{ + return aDelta >= 0 ? (PRInt32)NS_floor(aDelta) : (PRInt32)NS_ceil(aDelta); +} + /* * OnMouseWheel - mouse wheel event processing. This was originally embedded * within the message case block. If returning true result should be returned * immediately (no more processing). */ -PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue) +PRBool +nsWindow::OnMouseWheel(UINT aMessage, WPARAM aWParam, LPARAM aLParam, + PRBool& aHandled, LRESULT *aRetValue) { - // Handle both flavors of mouse wheel events. - static int iDeltaPerLine, iDeltaPerChar; - static ULONG ulScrollLines, ulScrollChars = 1; - static int currentVDelta, currentHDelta; - static HWND currentWindow = 0; + InitMouseWheelScrollData(); - PRBool isVertical = msg == WM_MOUSEWHEEL; - - // Get mouse wheel metrics (but only once). - if (getWheelInfo) { - getWheelInfo = PR_FALSE; - - SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0); - - // ulScrollLines usually equals 3 or 0 (for no scrolling) - // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40. - - // However, if ulScrollLines > WHEEL_DELTA, we assume that - // the mouse driver wants a page scroll. The docs state that - // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but - // since some mouse drivers use an arbitrary large number instead, - // we have to handle that as well. - - iDeltaPerLine = 0; - if (ulScrollLines) { - if (ulScrollLines <= WHEEL_DELTA) { - iDeltaPerLine = WHEEL_DELTA / ulScrollLines; - } else { - ulScrollLines = WHEEL_PAGESCROLL; - } - } - - if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, - &ulScrollChars, 0)) { - // Note that we may always fail to get the value before Win Vista. - ulScrollChars = 1; - } - - iDeltaPerChar = 0; - if (ulScrollChars) { - if (ulScrollChars <= WHEEL_DELTA) { - iDeltaPerChar = WHEEL_DELTA / ulScrollChars; - } else { - ulScrollChars = WHEEL_PAGESCROLL; - } - } + PRBool isVertical = (aMessage == WM_MOUSEWHEEL); + if ((isVertical && sMouseWheelScrollLines == 0) || + (!isVertical && sMouseWheelScrollChars == 0)) { + // XXX I think that we should dispatch mouse wheel events even if the + // operation will not scroll because the wheel operation really happened + // and web application may want to handle the event for non-scroll action. + ResetRemainingWheelDelta(); + *aRetValue = isVertical ? TRUE : FALSE; // means we don't process it + aHandled = PR_FALSE; + return PR_FALSE; } - if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) || - (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar)) - return PR_FALSE; // break - // The mousewheel event will be dispatched to the toplevel // window. We need to give it to the child window. PRBool quit; - if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit)) + if (!HandleScrollingPlugins(aMessage, aWParam, aLParam, + aHandled, aRetValue, quit)) { + ResetRemainingWheelDelta(); return quit; // return immediately if it's not our window + } - // We should cancel the surplus delta if the current window is not - // same as previous. - if (currentWindow != mWnd) { - currentVDelta = 0; - currentHDelta = 0; - currentWindow = mWnd; - } - - nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this); - scrollEvent.delta = 0; - if (isVertical) { - scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical; - if (ulScrollLines == WHEEL_PAGESCROLL) { - scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage; - scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1; - } else { - currentVDelta -= (short) HIWORD (wParam); - if (PR_ABS(currentVDelta) >= iDeltaPerLine) { - scrollEvent.delta = currentVDelta / iDeltaPerLine; - currentVDelta %= iDeltaPerLine; - } - } - } else { - scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal; - if (ulScrollChars == WHEEL_PAGESCROLL) { - scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage; - scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1; - } else { - currentHDelta += (short) HIWORD (wParam); - if (PR_ABS(currentHDelta) >= iDeltaPerChar) { - scrollEvent.delta = currentHDelta / iDeltaPerChar; - currentHDelta %= iDeltaPerChar; - } - } - } - - if (!scrollEvent.delta) { - // We store the wheel delta, and it will be used next wheel message, so, - // we consume this message actually. We shouldn't call next wndproc. - result = PR_TRUE; - return PR_FALSE; // break + PRInt32 nativeDelta = (short)HIWORD(aWParam); + if (!nativeDelta) { + *aRetValue = isVertical ? TRUE : FALSE; // means we don't process it + aHandled = PR_FALSE; + ResetRemainingWheelDelta(); + return PR_FALSE; // We cannot process this message } // The event may go to a plug-in which already dispatched this message. // Then, the event can cause deadlock. We should unlock the sender here. ::ReplyMessage(isVertical ? 0 : TRUE); + PRBool isPageScroll = + ((isVertical && sMouseWheelScrollLines == WHEEL_PAGESCROLL) || + (!isVertical && sMouseWheelScrollChars == WHEEL_PAGESCROLL)); + + // Discard the remaining delta if current wheel message and last one are + // received by different window or to scroll different direction or + // different unit scroll. Furthermore, if the last event was too old. + PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow()); + if (sLastMouseWheelWnd && + (sLastMouseWheelWnd != mWnd || + sLastMouseWheelDeltaIsPositive != (nativeDelta > 0) || + sLastMouseWheelOrientationIsVertical != isVertical || + sLastMouseWheelUnitIsPage != isPageScroll || + now - sLastMouseWheelTime > 1500)) { + ResetRemainingWheelDelta(); + } + sLastMouseWheelWnd = mWnd; + sLastMouseWheelDeltaIsPositive = (nativeDelta > 0); + sLastMouseWheelOrientationIsVertical = isVertical; + sLastMouseWheelUnitIsPage = isPageScroll; + sLastMouseWheelTime = now; + + PRBool dispatchPixelScrollEvent = PR_FALSE; + PRInt32 pixelsPerUnit = 0; + + if (sEnablePixelScrolling) { + nsMouseScrollEvent testEvent(PR_TRUE, NS_MOUSE_SCROLL, this); + InitEvent(testEvent); + testEvent.scrollFlags = isPageScroll ? nsMouseScrollEvent::kIsFullPage : 0; + testEvent.scrollFlags |= isVertical ? nsMouseScrollEvent::kIsVertical : + nsMouseScrollEvent::kIsHorizontal; + testEvent.delta = sLastMouseWheelDeltaIsPositive ? -1 : 1; + nsQueryContentEvent queryEvent(PR_TRUE, NS_QUERY_SCROLL_TARGET_INFO, this); + InitEvent(queryEvent); + queryEvent.InitForQueryScrollTargetInfo(&testEvent); + DispatchWindowEvent(&queryEvent); + // If the necessary interger isn't larger than 0, we should assume that + // the event failed for us. + if (queryEvent.mSucceeded) { + if (isPageScroll) { + if (isVertical) { + pixelsPerUnit = queryEvent.mReply.mPageHeight; + } else { + pixelsPerUnit = queryEvent.mReply.mPageWidth; + } + } else { + pixelsPerUnit = queryEvent.mReply.mLineHeight; + } + dispatchPixelScrollEvent = (pixelsPerUnit > 0); + } + } + + *aRetValue = isVertical ? FALSE : TRUE; // means we process this message + nsModifierKeyState modKeyState; + + // Our positive delta value means to bottom or right. + // But positive nativeDelta value means to top or right. + // Use orienter for computing our delta value. + PRInt32 orienter = isVertical ? -1 : 1; + // Assume the Control key is down if the Elantech touchpad has sent the // mis-ordered WM_KEYDOWN/WM_MOUSEWHEEL messages. (See the comment in // OnKeyUp.) @@ -6401,25 +6463,92 @@ PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& ge static_cast(::GetMessageTime()) < mAssumeWheelIsZoomUntil) { isControl = PR_TRUE; } else { - isControl = IS_VK_DOWN(NS_VK_CONTROL); + isControl = modKeyState.mIsControlDown; } - scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT); - scrollEvent.isControl = isControl; - scrollEvent.isMeta = PR_FALSE; - scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT); + nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this); InitEvent(scrollEvent); - if (nsnull != mEventCallback) { - result = DispatchWindowEvent(&scrollEvent); - } - // Note that we should return zero if we process WM_MOUSEWHEEL. - // But if we process WM_MOUSEHWHEEL, we should return non-zero. + scrollEvent.scrollFlags = + dispatchPixelScrollEvent ? nsMouseScrollEvent::kHasPixels : 0; + scrollEvent.isShift = modKeyState.mIsShiftDown; + scrollEvent.isControl = isControl; + scrollEvent.isMeta = PR_FALSE; + scrollEvent.isAlt = modKeyState.mIsAltDown; - if (result) - *aRetValue = isVertical ? 0 : TRUE; - - return PR_FALSE; // break; -} + PRInt32 nativeDeltaForScroll = nativeDelta + sRemainingDeltaForScroll; + + if (isPageScroll) { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage; + if (isVertical) { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsVertical; + } else { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsHorizontal; + } + scrollEvent.delta = nativeDeltaForScroll * orienter / WHEEL_DELTA; + PRInt32 recomputedNativeDelta = scrollEvent.delta * orienter / WHEEL_DELTA; + sRemainingDeltaForScroll = nativeDeltaForScroll - recomputedNativeDelta; + } else { + double deltaPerUnit; + if (isVertical) { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsVertical; + deltaPerUnit = (double)WHEEL_DELTA / sMouseWheelScrollLines; + } else { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsHorizontal; + deltaPerUnit = (double)WHEEL_DELTA / sMouseWheelScrollChars; + } + scrollEvent.delta = + RoundDelta((double)nativeDeltaForScroll * orienter / deltaPerUnit); + PRInt32 recomputedNativeDelta = + (PRInt32)(scrollEvent.delta * orienter * deltaPerUnit); + sRemainingDeltaForScroll = nativeDeltaForScroll - recomputedNativeDelta; + } + + if (scrollEvent.delta) { + aHandled = DispatchWindowEvent(&scrollEvent); + if (mOnDestroyCalled) { + ResetRemainingWheelDelta(); + return PR_FALSE; + } + } + + // If the query event failed, we cannot send pixel events. + if (!dispatchPixelScrollEvent) { + sRemainingDeltaForPixel = 0; + return PR_FALSE; + } + + nsMouseScrollEvent pixelEvent(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this); + InitEvent(pixelEvent); + pixelEvent.scrollFlags = nsMouseScrollEvent::kAllowSmoothScroll | + (scrollEvent.scrollFlags & ~nsMouseScrollEvent::kHasPixels); + pixelEvent.isShift = modKeyState.mIsShiftDown; + pixelEvent.isControl = modKeyState.mIsControlDown; + pixelEvent.isMeta = PR_FALSE; + pixelEvent.isAlt = modKeyState.mIsAltDown; + + PRInt32 nativeDeltaForPixel = nativeDelta + sRemainingDeltaForPixel; + + double deltaPerPixel; + if (isPageScroll) { + deltaPerPixel = (double)WHEEL_DELTA / pixelsPerUnit; + } else { + if (isVertical) { + deltaPerPixel = (double)WHEEL_DELTA / sMouseWheelScrollLines; + } else { + deltaPerPixel = (double)WHEEL_DELTA / sMouseWheelScrollChars; + } + deltaPerPixel /= pixelsPerUnit; + } + pixelEvent.delta = + RoundDelta((double)nativeDeltaForPixel * orienter / deltaPerPixel); + PRInt32 recomputedNativeDelta = + (PRInt32)(pixelEvent.delta * orienter * deltaPerPixel); + sRemainingDeltaForPixel = nativeDeltaForPixel - recomputedNativeDelta; + if (pixelEvent.delta != 0) { + aHandled = DispatchWindowEvent(&pixelEvent); + } + return PR_FALSE; +} static PRBool StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1, diff --git a/widget/src/windows/nsWindow.h b/widget/src/windows/nsWindow.h index 75a2b4bb7831..3279ed2798fe 100644 --- a/widget/src/windows/nsWindow.h +++ b/widget/src/windows/nsWindow.h @@ -411,8 +411,8 @@ protected: BOOL OnInputLangChange(HKL aHKL); PRBool OnPaint(HDC aDC, PRUint32 aNestingLevel); void OnWindowPosChanged(WINDOWPOS *wp, PRBool& aResult); - PRBool OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, - PRBool& result, PRBool& getWheelInfo, + PRBool OnMouseWheel(UINT aMessage, WPARAM aWParam, + LPARAM aLParam, PRBool& aHandled, LRESULT *aRetValue); void OnWindowPosChanging(LPWINDOWPOS& info); @@ -616,6 +616,21 @@ protected: // was reirected to SendInput() API by OnKeyDown(). static MSG sRedirectedKeyDown; + static PRBool sEnablePixelScrolling; + static PRBool sNeedsToInitMouseWheelSettings; + static ULONG sMouseWheelScrollLines; + static ULONG sMouseWheelScrollChars; + static void InitMouseWheelScrollData(); + + static HWND sLastMouseWheelWnd; + static PRInt32 sRemainingDeltaForScroll; + static PRInt32 sRemainingDeltaForPixel; + static PRBool sLastMouseWheelDeltaIsPositive; + static PRBool sLastMouseWheelOrientationIsVertical; + static PRBool sLastMouseWheelUnitIsPage; + static PRUint32 sLastMouseWheelTime; // in milliseconds + static void ResetRemainingWheelDelta(); + // If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is // redirected message, OnKeyDowm() prevents to dispatch NS_KEY_DOWN event // because it has been dispatched before the message was redirected. @@ -649,7 +664,6 @@ protected: nsRefPtr mWindow; const MSG &mMsg; }; - }; /** diff --git a/widget/src/windows/nsWindowDefs.h b/widget/src/windows/nsWindowDefs.h index 3bd48bc2eb86..dfb593909c5c 100644 --- a/widget/src/windows/nsWindowDefs.h +++ b/widget/src/windows/nsWindowDefs.h @@ -90,6 +90,10 @@ #define SPI_GETWHEELSCROLLCHARS 0x006C #endif +#ifndef SPI_SETWHEELSCROLLCHARS +#define SPI_SETWHEELSCROLLCHARS 0x006D +#endif + #ifndef MAPVK_VSC_TO_VK #define MAPVK_VK_TO_VSC 0 #define MAPVK_VSC_TO_VK 1 diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index 867774b0ac1b..395c658bd8fa 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -151,8 +151,7 @@ nsBaseWidget::~nsBaseWidget() NS_IF_RELEASE(mToolkit); NS_IF_RELEASE(mContext); - if (mOriginalBounds) - delete mOriginalBounds; + delete mOriginalBounds; } diff --git a/widget/src/xpwidgets/nsNativeTheme.cpp b/widget/src/xpwidgets/nsNativeTheme.cpp index dce6db986940..05eeddd79e4a 100644 --- a/widget/src/xpwidgets/nsNativeTheme.cpp +++ b/widget/src/xpwidgets/nsNativeTheme.cpp @@ -472,6 +472,13 @@ nsNativeTheme::IsIndeterminateProgress(nsIFrame* aFrame, eCaseMatters); } +PRBool +nsNativeTheme::IsVerticalProgress(nsIFrame* aFrame) +{ + return aFrame && + aFrame->GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL; +} + // menupopup: PRBool nsNativeTheme::IsSubmenu(nsIFrame* aFrame, PRBool* aLeftOfParent) diff --git a/widget/src/xpwidgets/nsNativeTheme.h b/widget/src/xpwidgets/nsNativeTheme.h index 8b6cd28791c1..b91f75b66073 100644 --- a/widget/src/xpwidgets/nsNativeTheme.h +++ b/widget/src/xpwidgets/nsNativeTheme.h @@ -161,6 +161,7 @@ class nsNativeTheme : public nsITimerCallback // progressbar: PRBool IsIndeterminateProgress(nsIFrame* aFrame, nsEventStates aEventStates); + PRBool IsVerticalProgress(nsIFrame* aFrame); // textfield: PRBool IsReadOnly(nsIFrame* aFrame) { diff --git a/widget/tests/Makefile.in b/widget/tests/Makefile.in index a72a42f76a50..65885df7cf97 100644 --- a/widget/tests/Makefile.in +++ b/widget/tests/Makefile.in @@ -108,6 +108,8 @@ _CHROME_FILES += native_menus_window.xul \ test_bug586713.xul \ bug586713_window.xul \ test_key_event_counts.xul \ + test_bug596600.xul \ + window_bug596600.xul \ $(NULL) endif diff --git a/widget/tests/test_bug596600.xul b/widget/tests/test_bug596600.xul new file mode 100644 index 000000000000..64c8fc03929b --- /dev/null +++ b/widget/tests/test_bug596600.xul @@ -0,0 +1,153 @@ + + + + + + Test for bug 596600 + + + + diff --git a/widget/tests/unit/xpcshell.ini b/widget/tests/unit/xpcshell.ini new file mode 100644 index 000000000000..13b85c020df5 --- /dev/null +++ b/widget/tests/unit/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = +tail = + +[test_taskbar_jumplistitems.js] diff --git a/widget/tests/window_bug596600.xul b/widget/tests/window_bug596600.xul new file mode 100644 index 000000000000..28e96f68e00d --- /dev/null +++ b/widget/tests/window_bug596600.xul @@ -0,0 +1,4 @@ + + + diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in index 4e3ca15c9691..a1aa1bc91d02 100644 --- a/xpcom/base/Makefile.in +++ b/xpcom/base/Makefile.in @@ -70,7 +70,7 @@ CPPSRCS = \ nsStackWalk.cpp \ nsMemoryReporterManager.cpp \ FunctionTimer.cpp \ - nsTelemetry.cpp \ + Telemetry.cpp \ $(NULL) ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) diff --git a/xpcom/base/nsTelemetry.cpp b/xpcom/base/Telemetry.cpp similarity index 85% rename from xpcom/base/nsTelemetry.cpp rename to xpcom/base/Telemetry.cpp index d65977a7cdc6..eaf57d3a311f 100644 --- a/xpcom/base/nsTelemetry.cpp +++ b/xpcom/base/Telemetry.cpp @@ -48,22 +48,23 @@ #include "nsStringGlue.h" #include "nsITelemetry.h" +namespace { + using namespace base; -using namespace mozilla; class Telemetry : public nsITelemetry { NS_DECL_ISUPPORTS NS_DECL_NSITELEMETRY - public: +public: static Telemetry* GetSingleton(); }; -// A static initializer to initialize histogram collection -static StatisticsRecorder gStatisticsRecorder; +// A initializer to initialize histogram collection +StatisticsRecorder gStatisticsRecorder; -static bool +bool FillRanges(JSContext *cx, JSObject *array, Histogram *h) { for (size_t i = 0;i < h->bucket_count();i++) { @@ -73,7 +74,7 @@ FillRanges(JSContext *cx, JSObject *array, Histogram *h) return true; } -static JSBool +JSBool ReflectHistogramSnapshot(JSContext *cx, JSObject *obj, Histogram *h) { Histogram::SampleSet ss; @@ -101,7 +102,7 @@ ReflectHistogramSnapshot(JSContext *cx, JSObject *obj, Histogram *h) return JS_TRUE; } -static JSBool +JSBool JSHistogram_Add(JSContext *cx, uintN argc, jsval *vp) { jsval *argv = JS_ARGV(cx, vp); @@ -116,7 +117,7 @@ JSHistogram_Add(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; } -static JSBool +JSBool JSHistogram_Snapshot(JSContext *cx, uintN argc, jsval *vp) { JSObject *obj = JS_THIS_OBJECT(cx, vp); @@ -128,7 +129,7 @@ JSHistogram_Snapshot(JSContext *cx, uintN argc, jsval *vp) return ReflectHistogramSnapshot(cx, snapshot, h); } -static nsresult +nsresult WrapAndReturnHistogram(Histogram *h, JSContext *cx, jsval *ret) { static JSClass JSHistogram_class = { @@ -149,16 +150,24 @@ WrapAndReturnHistogram(Histogram *h, JSContext *cx, jsval *ret) } NS_IMETHODIMP -Telemetry::NewExponentialHistogram(const nsACString &name, PRInt32 min, PRInt32 max, PRUint32 size, JSContext *cx, jsval *ret) +Telemetry::NewHistogram(const nsACString &name, PRUint32 min, PRUint32 max, PRUint32 bucket_count, PRUint32 histogram_type, JSContext *cx, jsval *ret) { - Histogram *h = base::Histogram::FactoryGet(name.BeginReading(), min, max, size, base::Histogram::kNoFlags); - return WrapAndReturnHistogram(h, cx, ret); -} + // Sanity checks on histogram parameters. + if (min < 1) + return NS_ERROR_ILLEGAL_VALUE; -NS_IMETHODIMP -Telemetry::NewLinearHistogram(const nsACString &name, PRInt32 min, PRInt32 max, PRUint32 size, JSContext *cx, jsval *ret) -{ - Histogram *h = base::LinearHistogram::FactoryGet(name.BeginReading(), min, max, size, base::Histogram::kNoFlags); + if (min >= max) + return NS_ERROR_ILLEGAL_VALUE; + + if (bucket_count <= 2) + return NS_ERROR_ILLEGAL_VALUE; + + Histogram *h; + if (histogram_type == nsITelemetry::HISTOGRAM_EXPONENTIAL) { + h = Histogram::FactoryGet(name.BeginReading(), min, max, bucket_count, Histogram::kNoFlags); + } else { + h = LinearHistogram::FactoryGet(name.BeginReading(), min, max, bucket_count, Histogram::kNoFlags); + } return WrapAndReturnHistogram(h, cx, ret); } @@ -187,9 +196,9 @@ Telemetry::GetHistogramSnapshots(JSContext *cx, jsval *ret) NS_IMPL_THREADSAFE_ISUPPORTS1(Telemetry, nsITelemetry) -static Telemetry *gJarHandler = nsnull; +Telemetry *gJarHandler = nsnull; -static void ShutdownTelemetry() +void ShutdownTelemetry() { NS_IF_RELEASE(gJarHandler); } @@ -207,20 +216,20 @@ Telemetry* Telemetry::GetSingleton() NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(Telemetry, Telemetry::GetSingleton) #define NS_TELEMETRY_CID \ - {0xf880b792, 0xe6cd, 0x46e7, {0x9c, 0x22, 0x3e, 0x12, 0xc3, 0x8b, 0xc6, 0xca}} + {0xaea477f2, 0xb3a2, 0x469c, {0xaa, 0x29, 0x0a, 0x82, 0xd1, 0x32, 0xb8, 0x29}} NS_DEFINE_NAMED_CID(NS_TELEMETRY_CID); -static const mozilla::Module::CIDEntry kTelemetryCIDs[] = { +const mozilla::Module::CIDEntry kTelemetryCIDs[] = { { &kNS_TELEMETRY_CID, false, NULL, TelemetryConstructor }, { NULL } }; -static const mozilla::Module::ContractIDEntry kTelemetryContracts[] = { +const mozilla::Module::ContractIDEntry kTelemetryContracts[] = { { "@mozilla.org/base/telemetry;1", &kNS_TELEMETRY_CID }, { NULL } }; -static const mozilla::Module kTelemetryModule = { +const mozilla::Module kTelemetryModule = { mozilla::Module::kVersion, kTelemetryCIDs, kTelemetryContracts, @@ -230,4 +239,6 @@ static const mozilla::Module kTelemetryModule = { ShutdownTelemetry, }; +} // anonymous namespace + NSMODULE_DEFN(nsTelemetryModule) = &kTelemetryModule; diff --git a/xpcom/base/nsITelemetry.idl b/xpcom/base/nsITelemetry.idl index 2c6bb7614412..e9b7c0717ae4 100644 --- a/xpcom/base/nsITelemetry.idl +++ b/xpcom/base/nsITelemetry.idl @@ -38,16 +38,24 @@ #include "nsISupports.idl" -[scriptable, uuid(5c9afdb5-0532-47f3-be31-79e13a6db642)] +[scriptable, uuid(29464d3d-f838-4afb-a737-319fe0c6cc04)] interface nsITelemetry : nsISupports { + /** + * Histogram types: + * HISTOGRAM_EXPONENTIAL - buckets increase exponentially + * HISTOGRAM_LINEAR - buckets increase linearly + */ + const unsigned long HISTOGRAM_EXPONENTIAL = 0; + const unsigned long HISTOGRAM_LINEAR = 1; + /* * An object containing a snapshot from all of the currently registered histograms. * { name1: {data1}, name2:{data2}...} * where data is consists of the following properties: * min - Minimal bucket size * max - Maximum bucket size - * histogram_type - 0:Exponential, 1:Linear + * histogram_type - HISTOGRAM_EXPONENTIAL or HISTOGRAM_LINEAR * counts - array representing contents of the buckets in the histogram * ranges - an array with calculated bucket sizes * sum - sum of the bucket contents @@ -61,16 +69,11 @@ interface nsITelemetry : nsISupports * @param min - Minimal bucket size * @param max - Maximum bucket size * @param bucket_count - number of buckets in the histogram. + * @param type - HISTOGRAM_EXPONENTIAL or HISTOGRAM_LINEAR * The returned object has the following functions: * add(int) - Adds an int value to the appropriate bucket * snapshot() - Returns a snapshot of the histogram with the same data fields as in histogramSnapshots() */ [implicit_jscontext] - jsval newExponentialHistogram(in ACString name, in PRInt32 min, in PRInt32 max, in PRUint32 bucket_count); - - /* - Same as newExponentialHistogram, but for linear histograms - */ - [implicit_jscontext] - jsval newLinearHistogram(in ACString name, in PRInt32 min, in PRInt32 max, in PRUint32 bucket_count); + jsval newHistogram(in ACString name, in PRUint32 min, in PRUint32 max, in PRUint32 bucket_count, in unsigned long histogram_type); }; diff --git a/xpcom/build/Makefile.in b/xpcom/build/Makefile.in index 60121d12f8e8..61e760140a34 100644 --- a/xpcom/build/Makefile.in +++ b/xpcom/build/Makefile.in @@ -69,6 +69,7 @@ CPPSRCS = \ nsXPComInit.cpp \ nsXPCOMStrings.cpp \ Services.cpp \ + Omnijar.cpp \ $(NULL) ifndef MOZ_ENABLE_LIBXUL @@ -77,10 +78,6 @@ CPPSRCS += dlldeps.cpp endif endif -ifdef MOZ_OMNIJAR -CPPSRCS += Omnijar.cpp -endif - SHARED_LIBRARY_LIBS = \ $(DEPTH)/chrome/src/$(LIB_PREFIX)chrome_s.$(LIB_SUFFIX) \ ../ds/$(LIB_PREFIX)xpcomds_s.$(LIB_SUFFIX) \ diff --git a/xpcom/build/Omnijar.cpp b/xpcom/build/Omnijar.cpp index 14a0dcf8d332..592218260c2c 100644 --- a/xpcom/build/Omnijar.cpp +++ b/xpcom/build/Omnijar.cpp @@ -21,6 +21,7 @@ * * Contributor(s): * Michael Wu + * Mike Hommey * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -38,64 +39,152 @@ #include "Omnijar.h" -#include "nsILocalFile.h" -#include "nsXULAppAPI.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsIFile.h" #include "nsZipArchive.h" +#include "nsNetUtil.h" -static nsILocalFile* sOmnijarPath = nsnull; -static nsZipArchive* sOmnijarReader = nsnull; +namespace mozilla { -static void -SetupReader() +nsIFile *Omnijar::sPath[2] = { nsnull, nsnull }; +nsZipArchive *Omnijar::sReader[2] = { nsnull, nsnull }; +PRPackedBool Omnijar::sInitialized = PR_FALSE; +static PRPackedBool sIsUnified = PR_FALSE; + +static const char *sProp[2] = + { NS_GRE_DIR, NS_XPCOM_CURRENT_PROCESS_DIR }; + +#define SPROP(Type) ((Type == mozilla::Omnijar::GRE) ? sProp[GRE] : sProp[APP]) + +void +Omnijar::CleanUpOne(Type aType) { - if (!sOmnijarPath) { + if (sReader[aType]) { + sReader[aType]->CloseArchive(); + delete sReader[aType]; + } + sReader[aType] = nsnull; + NS_IF_RELEASE(sPath[aType]); +} + +void +Omnijar::InitOne(nsIFile *aPath, Type aType) +{ + nsCOMPtr file; + if (aPath) { + file = aPath; + } else { + nsCOMPtr dir; + nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile), getter_AddRefs(dir)); + if (NS_FAILED(dir->Clone(getter_AddRefs(file))) || + NS_FAILED(file->AppendNative(NS_LITERAL_CSTRING("omni.jar")))) + return; + } + PRBool isFile; + if (NS_FAILED(file->IsFile(&isFile)) || !isFile) { + // If we're not using an omni.jar for GRE, and we don't have an + // omni.jar for APP, check if both directories are the same. + if ((aType == APP) && (!sPath[GRE])) { + nsCOMPtr greDir, appDir; + PRBool equals; + nsDirectoryService::gService->Get(SPROP(GRE), NS_GET_IID(nsIFile), getter_AddRefs(greDir)); + nsDirectoryService::gService->Get(SPROP(APP), NS_GET_IID(nsIFile), getter_AddRefs(appDir)); + if (NS_SUCCEEDED(greDir->Equals(appDir, &equals)) && equals) + sIsUnified = PR_TRUE; + } + return; + } + + PRBool equals; + if ((aType == APP) && (sPath[GRE]) && + NS_SUCCEEDED(sPath[GRE]->Equals(file, &equals)) && equals) { + // If we're using omni.jar on both GRE and APP and their path + // is the same, we're in the unified case. + sIsUnified = PR_TRUE; return; } nsZipArchive* zipReader = new nsZipArchive(); - if (!zipReader) { - NS_IF_RELEASE(sOmnijarPath); + if (!zipReader) return; - } - if (NS_FAILED(zipReader->OpenArchive(sOmnijarPath))) { + if (NS_FAILED(zipReader->OpenArchive(file))) { delete zipReader; - NS_IF_RELEASE(sOmnijarPath); return; } - sOmnijarReader = zipReader; -} - -nsILocalFile* -mozilla::OmnijarPath() -{ - if (!sOmnijarReader) - SetupReader(); - - return sOmnijarPath; -} - -nsZipArchive* -mozilla::OmnijarReader() -{ - if (!sOmnijarReader) - SetupReader(); - - return sOmnijarReader; + CleanUpOne(aType); + sReader[aType] = zipReader; + sPath[aType] = file; + NS_IF_ADDREF(file); } void -mozilla::SetOmnijar(nsILocalFile* aPath) +Omnijar::Init(nsIFile *aGrePath, nsIFile *aAppPath) { - NS_IF_RELEASE(sOmnijarPath); - if (sOmnijarReader) { - sOmnijarReader->CloseArchive(); - delete sOmnijarReader; - sOmnijarReader = nsnull; - } - - sOmnijarPath = aPath; - NS_IF_ADDREF(sOmnijarPath); + InitOne(aGrePath, GRE); + InitOne(aAppPath, APP); + sInitialized = PR_TRUE; } +void +Omnijar::CleanUp() +{ + CleanUpOne(GRE); + CleanUpOne(APP); + sInitialized = PR_FALSE; +} + +nsZipArchive * +Omnijar::GetReader(nsIFile *aPath) +{ + NS_ABORT_IF_FALSE(IsInitialized(), "Omnijar not initialized"); + + PRBool equals; + nsresult rv; + + if (sPath[GRE]) { + rv = sPath[GRE]->Equals(aPath, &equals); + if (NS_SUCCEEDED(rv) && equals) + return sReader[GRE]; + } + if (sPath[APP]) { + rv = sPath[APP]->Equals(aPath, &equals); + if (NS_SUCCEEDED(rv) && equals) + return sReader[APP]; + } + return nsnull; +} + +nsresult +Omnijar::GetURIString(Type aType, nsACString &result) +{ + NS_ABORT_IF_FALSE(IsInitialized(), "Omnijar not initialized"); + + result.Truncate(); + + // Return an empty string for APP in the unified case. + if ((aType == APP) && sIsUnified) { + return NS_OK; + } + + nsCAutoString omniJarSpec; + if (sPath[aType]) { + nsresult rv = NS_GetURLSpecFromActualFile(sPath[aType], omniJarSpec); + NS_ENSURE_SUCCESS(rv, rv); + + result = "jar:"; + result += omniJarSpec; + result += "!"; + } else { + nsCOMPtr dir; + nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile), getter_AddRefs(dir)); + nsresult rv = NS_GetURLSpecFromActualFile(dir, result); + NS_ENSURE_SUCCESS(rv, rv); + } + result += "/"; + return NS_OK; +} + +} /* namespace mozilla */ diff --git a/xpcom/build/Omnijar.h b/xpcom/build/Omnijar.h index 33a2b4a69f53..64c1c4367635 100644 --- a/xpcom/build/Omnijar.h +++ b/xpcom/build/Omnijar.h @@ -21,6 +21,7 @@ * * Contributor(s): * Michael Wu + * Mike Hommey * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -39,24 +40,125 @@ #ifndef mozilla_Omnijar_h #define mozilla_Omnijar_h -class nsILocalFile; -class nsZipArchive; +#include "nscore.h" +#include "nsCOMPtr.h" +#include "nsString.h" -#ifdef MOZ_OMNIJAR +class nsIFile; +class nsZipArchive; +class nsIURI; namespace mozilla { +class Omnijar { +private: /** - * This returns the path to the omnijar. - * If the omnijar isn't available, this function will return null. - * Callers should fallback to flat packaging if null. + * Store an nsIFile for an omni.jar. We can store two paths here, one + * for GRE (corresponding to resource://gre/) and one for APP + * (corresponding to resource:/// and resource://app/), but only + * store one when both point to the same location (unified). */ -nsILocalFile *OmnijarPath(); -nsZipArchive *OmnijarReader(); -void SetOmnijar(nsILocalFile* aPath); +static nsIFile *sPath[2]; + +/** + * Cached nsZipArchives for the corresponding sPath + */ +static nsZipArchive *sReader[2]; + +/** + * Has Omnijar::Init() been called? + */ +static PRPackedBool sInitialized; + +public: +enum Type { + GRE = 0, + APP = 1 +}; + +/** + * Returns whether SetBase has been called at least once with + * a valid nsIFile + */ +static inline PRPackedBool +IsInitialized() +{ + return sInitialized; +} + +/** + * Initializes the Omnijar API with the given directory or file for GRE and + * APP. Each of the paths given can be: + * - a file path, pointing to the omnijar file, + * - a directory path, pointing to a directory containing an "omni.jar" file, + * - nsnull for autodetection of an "omni.jar" file. + */ +static void Init(nsIFile *aGrePath = nsnull, nsIFile *aAppPath = nsnull); + +/** + * Cleans up the Omnijar API + */ +static void CleanUp(); + +/** + * Returns an nsIFile pointing to the omni.jar file for GRE or APP. + * Returns nsnull when there is no corresponding omni.jar. + * Also returns nsnull for APP in the unified case. + */ +static inline already_AddRefed +GetPath(Type aType) +{ + NS_ABORT_IF_FALSE(IsInitialized(), "Omnijar not initialized"); + NS_IF_ADDREF(sPath[aType]); + return sPath[aType]; +} + +/** + * Returns whether GRE or APP use an omni.jar. Returns PR_False for + * APP when using an omni.jar in the unified case. + */ +static inline PRBool +HasOmnijar(Type aType) +{ + NS_ABORT_IF_FALSE(IsInitialized(), "Omnijar not initialized"); + return !!sPath[aType]; +} + +/** + * Returns a nsZipArchive pointer for the omni.jar file for GRE or + * APP. Returns nsnull in the same cases GetPath() would. + */ +static inline nsZipArchive * +GetReader(Type aType) +{ + NS_ABORT_IF_FALSE(IsInitialized(), "Omnijar not initialized"); + return sReader[aType]; +} + +/** + * Returns a nsZipArchive pointer for the given path IAOI the given + * path is the omni.jar for either GRE or APP. + */ +static nsZipArchive *GetReader(nsIFile *aPath); + +/** + * Returns the URI string corresponding to the omni.jar or directory + * for GRE or APP. i.e. jar:/path/to/omni.jar!/ for omni.jar and + * /path/to/base/dir/ otherwise. Returns an empty string for APP in + * the unified case. + * The returned URI is guaranteed to end with a slash. + */ +static nsresult GetURIString(Type aType, nsACString &result); + +private: +/** + * Used internally, respectively by Init() and CleanUp() + */ +static void InitOne(nsIFile *aPath, Type aType); +static void CleanUpOne(Type aType); + +}; /* class Omnijar */ } /* namespace mozilla */ -#endif /* MOZ_OMNIJAR */ - #endif /* mozilla_Omnijar_h */ diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index b2b1482ff13f..2d6dbb4c989b 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -457,25 +457,11 @@ NS_InitXPCOM2(nsIServiceManager* *result, if (NS_FAILED(rv)) return rv; } -#ifdef MOZ_OMNIJAR NS_TIME_FUNCTION_MARK("Next: Omnijar init"); - if (!mozilla::OmnijarPath()) { - nsCOMPtr omnijar; - nsCOMPtr file; - - rv = NS_ERROR_FAILURE; - nsDirectoryService::gService->Get(NS_GRE_DIR, - NS_GET_IID(nsIFile), - getter_AddRefs(file)); - if (file) - rv = file->Append(NS_LITERAL_STRING("omni.jar")); - if (NS_SUCCEEDED(rv)) - omnijar = do_QueryInterface(file); - if (NS_SUCCEEDED(rv)) - mozilla::SetOmnijar(omnijar); + if (!mozilla::Omnijar::IsInitialized()) { + mozilla::Omnijar::Init(); } -#endif if ((sCommandLineWasInitialized = !CommandLine::IsInitialized())) { NS_TIME_FUNCTION_MARK("Next: IPC command line init"); @@ -755,9 +741,7 @@ ShutdownXPCOM(nsIServiceManager* servMgr) sExitManager = nsnull; } -#ifdef MOZ_OMNIJAR - mozilla::SetOmnijar(nsnull); -#endif + mozilla::Omnijar::CleanUp(); NS_LogTerm(); diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index e9dda293e764..51ee884ec2e9 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -174,8 +174,6 @@ NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID); #define COMPMGR_TIME_FUNCTION_CONTRACTID(cid) do {} while (0) #endif -#define kOMNIJAR_PREFIX NS_LITERAL_CSTRING("resource:///") - nsresult nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const { @@ -385,14 +383,20 @@ nsresult nsComponentManagerImpl::Init() for (PRUint32 i = 0; i < sStaticModules->Length(); ++i) RegisterModule((*sStaticModules)[i], NULL); -#ifdef MOZ_OMNIJAR - if (mozilla::OmnijarPath()) { - nsCOMPtr omnijarReader = new nsJAR(); - rv = omnijarReader->Open(mozilla::OmnijarPath()); - if (NS_SUCCEEDED(rv)) - RegisterJarManifest(omnijarReader, "chrome.manifest", false); + nsCOMPtr appOmnijar = mozilla::Omnijar::GetPath(mozilla::Omnijar::APP); + if (appOmnijar) { + cl = sModuleLocations->InsertElementAt(1); // Insert after greDir + cl->type = NS_COMPONENT_LOCATION; + cl->location = do_QueryInterface(appOmnijar); + cl->jar = true; + } + nsCOMPtr greOmnijar = mozilla::Omnijar::GetPath(mozilla::Omnijar::GRE); + if (greOmnijar) { + cl = sModuleLocations->InsertElementAt(0); + cl->type = NS_COMPONENT_LOCATION; + cl->location = do_QueryInterface(greOmnijar); + cl->jar = true; } -#endif for (PRUint32 i = 0; i < sModuleLocations->Length(); ++i) { ComponentLocation& l = sModuleLocations->ElementAt(i); @@ -407,15 +411,6 @@ nsresult nsComponentManagerImpl::Init() RegisterJarManifest(reader, "chrome.manifest", false); } -#ifdef MOZ_OMNIJAR - if (mozilla::OmnijarPath()) { - cl = sModuleLocations->InsertElementAt(0); - cl->type = NS_COMPONENT_LOCATION; - cl->location = mozilla::OmnijarPath(); - cl->jar = true; - } -#endif - nsCategoryManager::GetSingleton()->SuppressNotifications(false); mStatus = NORMAL; diff --git a/xpcom/ds/nsMathUtils.h b/xpcom/ds/nsMathUtils.h index a3aaeeba2206..e6cb0a0e2cfe 100644 --- a/xpcom/ds/nsMathUtils.h +++ b/xpcom/ds/nsMathUtils.h @@ -44,6 +44,10 @@ #include #include +#ifdef SOLARIS +#include +#endif + /* * round */ diff --git a/xpcom/glue/nsDeque.cpp b/xpcom/glue/nsDeque.cpp index f61324850ef0..62bb96ebe8e5 100644 --- a/xpcom/glue/nsDeque.cpp +++ b/xpcom/glue/nsDeque.cpp @@ -129,9 +129,7 @@ nsDeque::~nsDeque() { * @param aDeallocator functor object for use by Erase() */ void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){ - if (mDeallocator) { - delete mDeallocator; - } + delete mDeallocator; mDeallocator=aDeallocator; } diff --git a/xpcom/glue/nsID.h b/xpcom/glue/nsID.h index de80a333312b..2abb34c2c7c5 100644 --- a/xpcom/glue/nsID.h +++ b/xpcom/glue/nsID.h @@ -73,18 +73,9 @@ struct nsID { */ inline PRBool Equals(const nsID& other) const { - // One would think that this could be done faster with a really - // efficient implementation of memcmp(), but evidently no - // memcmp()'s out there are better than this code. - // - // See bug http://bugzilla.mozilla.org/show_bug.cgi?id=164580 for - // details. - return - ((((PRUint32*) &m0)[0] == ((PRUint32*) &other.m0)[0]) && - (((PRUint32*) &m0)[1] == ((PRUint32*) &other.m0)[1]) && - (((PRUint32*) &m0)[2] == ((PRUint32*) &other.m0)[2]) && - (((PRUint32*) &m0)[3] == ((PRUint32*) &other.m0)[3])); + ((PRUint64*) &m0)[0] == ((PRUint64*) &other.m0)[0] && + ((PRUint64*) &m0)[1] == ((PRUint64*) &other.m0)[1]; } /** diff --git a/xpcom/io/nsStorageStream.cpp b/xpcom/io/nsStorageStream.cpp index 95e085a7f7f9..4202a6f23696 100644 --- a/xpcom/io/nsStorageStream.cpp +++ b/xpcom/io/nsStorageStream.cpp @@ -80,8 +80,7 @@ nsStorageStream::nsStorageStream() nsStorageStream::~nsStorageStream() { - if (mSegmentedBuffer) - delete mSegmentedBuffer; + delete mSegmentedBuffer; } NS_IMPL_THREADSAFE_ISUPPORTS2(nsStorageStream, diff --git a/xpcom/tests/TestTimers.cpp b/xpcom/tests/TestTimers.cpp index 1117e8b49d92..5cd39fa03017 100644 --- a/xpcom/tests/TestTimers.cpp +++ b/xpcom/tests/TestTimers.cpp @@ -89,9 +89,7 @@ public: } ~AutoCreateAndDestroyReentrantMonitor() { - if (mReentrantMonitor) { - delete mReentrantMonitor; - } + delete mReentrantMonitor; } operator ReentrantMonitor* () { diff --git a/xpcom/tests/unit/test_nsITelemetry.js b/xpcom/tests/unit/test_nsITelemetry.js index 8de4edaf7be6..cbcdb7ba4fca 100644 --- a/xpcom/tests/unit/test_nsITelemetry.js +++ b/xpcom/tests/unit/test_nsITelemetry.js @@ -6,8 +6,8 @@ const Ci = Components.interfaces; const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry); -function test_histogram(histogram_constructor, name, min, max, bucket_count) { - var h = histogram_constructor(name, min, max, bucket_count); +function test_histogram(histogram_type, name, min, max, bucket_count) { + var h = Telemetry.newHistogram(name, min, max, bucket_count, histogram_type); var r = h.snapshot().ranges; var sum = 0; @@ -25,14 +25,32 @@ function test_histogram(histogram_constructor, name, min, max, bucket_count) { } var hgrams = Telemetry.histogramSnapshots gh = hgrams[name] - do_check_eq(gh.histogram_type, - histogram_constructor == Telemetry.newExponentialHistogram ? 0 : 1); + do_check_eq(gh.histogram_type, histogram_type); + do_check_eq(gh.min, min) do_check_eq(gh.max, max) } +function expect_fail(f) { + let failed = false; + try { + f(); + failed = false; + } catch (e) { + failed = true; + } + do_check_true(failed); +} + function run_test() { - test_histogram(Telemetry.newExponentialHistogram, "test::Exponential", 1, 10000, 10); - test_histogram(Telemetry.newLinearHistogram, "test::Linear", 1, 10000, 10); + let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR] + for each (let histogram_type in kinds) { + let [min, max, bucket_count] = [1, 10000, 10] + test_histogram(histogram_type, "test::"+histogram_type, min, max, bucket_count); + + const nh = Telemetry.newHistogram; + expect_fail(function () nh("test::min", 0, max, bucket_count, histogram_type)); + expect_fail(function () nh("test::bucket_count", min, max, 1, histogram_type)); + } } diff --git a/xpcom/tests/unit/xpcshell.ini b/xpcom/tests/unit/xpcshell.ini new file mode 100644 index 000000000000..749a3ea6197e --- /dev/null +++ b/xpcom/tests/unit/xpcshell.ini @@ -0,0 +1,31 @@ +[DEFAULT] +head = +tail = + +[test_bug121341.js] +[test_bug332389.js] +[test_bug333505.js] +[test_bug364285-1.js] +[test_bug374754.js] +[test_bug476919.js] +[test_bug478086.js] +[test_bug656331.js] +[test_compmgr_warnings.js] +[test_file_createUnique.js] +[test_file_equality.js] +[test_hidden_files.js] +[test_home.js] +[test_iniProcessor.js] +[test_ioutil.js] +[test_localfile.js] +[test_mac_bundle.js] +[test_nsIMutableArray.js] +[test_nsIProcess.js] +[test_nsITelemetry.js] +[test_pipe.js] +[test_storagestream.js] +[test_streams.js] +[test_stringstream.js] +[test_symlinks.js] +[test_systemInfo.js] +[test_versioncomparator.js] diff --git a/xpcom/typelib/xpt/tools/runtests.py b/xpcom/typelib/xpt/tools/runtests.py index b4ac9b1742cc..79025a87b826 100644 --- a/xpcom/typelib/xpt/tools/runtests.py +++ b/xpcom/typelib/xpt/tools/runtests.py @@ -32,6 +32,7 @@ import difflib import os +import shutil from StringIO import StringIO import subprocess import sys @@ -746,5 +747,65 @@ class TestTypelibMerge(unittest.TestCase): self.assertEqual(t1.interfaces[1], t1.interfaces[0].methods[0].params[0].type.element_type.iface) +class TestXPTLink(unittest.TestCase): + def setUp(self): + self.tempdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.tempdir, True) + + def gettempfile(self): + fd, f = tempfile.mkstemp(dir=self.tempdir) + os.close(fd) + return f + + def test_xpt_link(self): + """ + Test the xpt_link method. + + """ + t1 = xpt.Typelib() + # add an unresolved interface + t1.interfaces.append(xpt.Interface("IFoo")) + f1 = self.gettempfile() + t1.write(f1) + + t2 = xpt.Typelib() + # add an unresolved interface + t2.interfaces.append(xpt.Interface("IBar")) + f2 = self.gettempfile() + t2.write(f2) + + f3 = self.gettempfile() + xpt.xpt_link(f3, [f1, f2]) + t3 = xpt.Typelib.read(f3) + + self.assertEqual(2, len(t3.interfaces)) + # Interfaces should wind up sorted + self.assertEqual("IBar", t3.interfaces[0].name) + self.assertEqual("IFoo", t3.interfaces[1].name) + + # Add some IID values + t1 = xpt.Typelib() + # add an unresolved interface + t1.interfaces.append(xpt.Interface("IFoo", iid="11223344-5566-7788-9900-aabbccddeeff")) + f1 = self.gettempfile() + t1.write(f1) + + t2 = xpt.Typelib() + # add an unresolved interface + t2.interfaces.append(xpt.Interface("IBar", iid="44332211-6655-8877-0099-aabbccddeeff")) + f2 = self.gettempfile() + t2.write(f2) + + f3 = self.gettempfile() + xpt.xpt_link(f3, [f1, f2]) + t3 = xpt.Typelib.read(f3) + + self.assertEqual(2, len(t3.interfaces)) + # Interfaces should wind up sorted + self.assertEqual("IFoo", t3.interfaces[0].name) + self.assertEqual("IBar", t3.interfaces[1].name) + if __name__ == '__main__': unittest.main() diff --git a/xpcom/typelib/xpt/tools/xpt.py b/xpcom/typelib/xpt/tools/xpt.py index cea8ab1274a0..7859bc463378 100644 --- a/xpcom/typelib/xpt/tools/xpt.py +++ b/xpcom/typelib/xpt/tools/xpt.py @@ -1155,9 +1155,11 @@ class Typelib(object): for i in self.interfaces: i.write_directory_entry(f) - def merge(self, other): + def merge(self, other, sanitycheck=True): """ Merge the contents of Typelib |other| into this typelib. + If |sanitycheck| is False, don't sort the interface table + after merging. """ # This will be a list of (replaced interface, replaced with) @@ -1229,7 +1231,8 @@ class Typelib(object): checkType(m.result.type, replaced_from, replaced_to) for p in m.params: checkType(p.type, replaced_from, replaced_to) - self._sanityCheck() + if sanitycheck: + self._sanityCheck() #TODO: do we care about annotations? probably not def dump(self, out): @@ -1303,7 +1306,8 @@ def xpt_link(dest, inputs): t1 = Typelib.read(inputs[0]) for f in inputs[1:]: t2 = Typelib.read(f) - t1.merge(t2) + # write will call sanitycheck, so skip it here. + t1.merge(t2, sanitycheck=False) t1.write(dest) if __name__ == '__main__': diff --git a/xpinstall/src/nsXPITriggerInfo.cpp b/xpinstall/src/nsXPITriggerInfo.cpp index 59002d1538fb..81710460601b 100644 --- a/xpinstall/src/nsXPITriggerInfo.cpp +++ b/xpinstall/src/nsXPITriggerInfo.cpp @@ -188,8 +188,7 @@ nsXPITriggerInfo::~nsXPITriggerInfo() for(PRUint32 i=0; i < Size(); i++) { item = Get(i); - if (item) - delete item; + delete item; } mItems.Clear(); diff --git a/xulrunner/app/Makefile.in b/xulrunner/app/Makefile.in index 55fa9eea6d71..5efc305b2fa1 100644 --- a/xulrunner/app/Makefile.in +++ b/xulrunner/app/Makefile.in @@ -212,7 +212,7 @@ endif # XXX applications would need to supply this file #export:: brand.dtd.in -# $(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) $^ > brand.dtd +# $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $^ > brand.dtd export:: $(NSINSTALL) -D $(DIST)/branding diff --git a/xulrunner/confvars.sh b/xulrunner/confvars.sh index 937da9ca5e0e..20896cb7350c 100755 --- a/xulrunner/confvars.sh +++ b/xulrunner/confvars.sh @@ -41,6 +41,7 @@ MOZ_APP_DISPLAYNAME=XULRunner MOZ_UPDATER=1 MOZ_XULRUNNER=1 MOZ_ENABLE_LIBXUL=1 +MOZ_CHROME_FILE_FORMAT=omni MOZ_STATIC_BUILD_UNSUPPORTED=1 MOZ_APP_VERSION=$MOZILLA_VERSION if test "$MOZ_STORAGE"; then diff --git a/xulrunner/installer/mac/Makefile.in b/xulrunner/installer/mac/Makefile.in index 6f2d1918bdc5..b9dfe41b0c1c 100644 --- a/xulrunner/installer/mac/Makefile.in +++ b/xulrunner/installer/mac/Makefile.in @@ -61,7 +61,7 @@ include $(topsrcdir)/config/rules.mk libs:: stage-package %.plist: %.plist.in - $(PERL) $(topsrcdir)/config/preprocessor.pl $(DEFINES) $(ACDEFINES) $< > $@ + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@ PACKAGER_NO_LIBS=1 _APPNAME = XUL.framework