Merge mozilla-central
authorBen Turner <bent.mozilla@gmail.com>
Mon, 05 Oct 2009 16:08:52 -0700
changeset 35960 0c395cb51007404994377292fac9cae32244490e
parent 35959 04562dce2157a537962100c25c0e7fb64e04e876 (current diff)
parent 33479 4c58fd598abb3e2cd14cffd4d36ec915be1efa8e (diff)
child 35961 86bc67405573b8df93c44c5fd6c13865d900c878
push id10694
push userbsmedberg@mozilla.com
push dateMon, 14 Dec 2009 15:23:10 +0000
treeherdermozilla-central@683dfdc4adf0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.3a1pre
Merge mozilla-central
browser/app/profile/firefox.js
browser/themes/pinstripe/browser/places/back-forward.png
browser/themes/pinstripe/browser/places/menubutton-end-pressed-rtl.png
browser/themes/pinstripe/browser/places/menubutton-end-pressed.png
browser/themes/pinstripe/browser/places/menubutton-end-rtl.png
browser/themes/pinstripe/browser/places/menubutton-end.png
browser/themes/pinstripe/browser/places/menubutton-mid-pressed.png
browser/themes/pinstripe/browser/places/menubutton-start-pressed-rtl.png
browser/themes/pinstripe/browser/places/menubutton-start-pressed.png
browser/themes/pinstripe/browser/places/menubutton-start-rtl.png
browser/themes/pinstripe/browser/places/menubutton-start.png
browser/themes/pinstripe/browser/places/toolbar-button-backup.png
browser/themes/pinstripe/browser/places/toolbar-button-organize.png
browser/themes/pinstripe/browser/places/toolbar-button-view.png
build/automation.py.in
config/autoconf.mk.in
configure.in
content/base/src/Makefile.in
content/base/src/nsFrameLoader.cpp
docshell/base/nsDocShell.cpp
dom/locales/en-US/chrome/printdialog.properties
embedding/browser/activex/src/install/README.txt
embedding/browser/activex/src/install/build.pl
embedding/browser/activex/src/install/client-win
embedding/browser/activex/src/install/control.nsi
embedding/browser/activex/src/install/mozconfig.txt
embedding/browser/activex/src/install/smoketest.html
embedding/config/GenerateManifest.pm
embedding/config/Makefile.in
embedding/config/basebrowser-installer-win.pkg
embedding/config/basebrowser-mac-macho
embedding/config/basebrowser-qnx
embedding/config/basebrowser-unix
embedding/config/basebrowser-win
embedding/config/basebrowser-win-supp
embedding/config/embed-jar.mn
embedding/config/gen_mn.pl
embedding/config/gre-installer-win.pkg
embedding/config/gre-win
embedding/config/gre-win-supp
embedding/config/gre.pl
embedding/config/installed-chrome.txt
embedding/config/minimo-qnx
embedding/config/minimo-unix
embedding/config/mk_sdk_hdr_lst.pl
embedding/config/xulsecurity.mn
embedding/tests/MSDotNETCSEmbed/App.ico
embedding/tests/MSDotNETCSEmbed/AssemblyInfo.cs
embedding/tests/MSDotNETCSEmbed/MSDotNETCSEmbed.csproj
embedding/tests/MSDotNETCSEmbed/MSDotNETCSEmbed.csproj.user
embedding/tests/MSDotNETCSEmbed/MSDotNETCSEmbed.sln
embedding/tests/MSDotNETCSEmbed/MSDotNETCSEmbed.suo
embedding/tests/MSDotNETCSEmbed/MSDotNETCSEmbedForm.cs
embedding/tests/MSDotNETCSEmbed/MSDotNETCSEmbedForm.resx
embedding/tests/wxEmbed/BrowserFrame.cpp
embedding/tests/wxEmbed/BrowserFrame.h
embedding/tests/wxEmbed/ChatFrame.cpp
embedding/tests/wxEmbed/ChatFrame.h
embedding/tests/wxEmbed/EditorFrame.cpp
embedding/tests/wxEmbed/EditorFrame.h
embedding/tests/wxEmbed/EmbedApp.cpp
embedding/tests/wxEmbed/GeckoContainer.cpp
embedding/tests/wxEmbed/GeckoContainer.h
embedding/tests/wxEmbed/GeckoContainerUI.cpp
embedding/tests/wxEmbed/GeckoFrame.cpp
embedding/tests/wxEmbed/GeckoFrame.h
embedding/tests/wxEmbed/GeckoProtocolHandler.cpp
embedding/tests/wxEmbed/GeckoProtocolHandler.h
embedding/tests/wxEmbed/GeckoWindow.cpp
embedding/tests/wxEmbed/GeckoWindow.h
embedding/tests/wxEmbed/GeckoWindowCreator.cpp
embedding/tests/wxEmbed/GeckoWindowCreator.h
embedding/tests/wxEmbed/MailFrame.cpp
embedding/tests/wxEmbed/MailFrame.h
embedding/tests/wxEmbed/README.txt
embedding/tests/wxEmbed/global.h
embedding/tests/wxEmbed/makefile.vc
embedding/tests/wxEmbed/rc/aligncenter.gif
embedding/tests/wxEmbed/rc/alignleft.gif
embedding/tests/wxEmbed/rc/alignright.gif
embedding/tests/wxEmbed/rc/anchor.gif
embedding/tests/wxEmbed/rc/back.gif
embedding/tests/wxEmbed/rc/background.gif
embedding/tests/wxEmbed/rc/bold.gif
embedding/tests/wxEmbed/rc/browser.xrc
embedding/tests/wxEmbed/rc/chat.xrc
embedding/tests/wxEmbed/rc/decreasefont.gif
embedding/tests/wxEmbed/rc/editor.xrc
embedding/tests/wxEmbed/rc/forward.gif
embedding/tests/wxEmbed/rc/help.gif
embedding/tests/wxEmbed/rc/home.gif
embedding/tests/wxEmbed/rc/increasefont.gif
embedding/tests/wxEmbed/rc/indent.gif
embedding/tests/wxEmbed/rc/italic.gif
embedding/tests/wxEmbed/rc/mail.xrc
embedding/tests/wxEmbed/rc/outdent.gif
embedding/tests/wxEmbed/rc/pen.gif
embedding/tests/wxEmbed/rc/reload.gif
embedding/tests/wxEmbed/rc/stop.gif
embedding/tests/wxEmbed/rc/underline.gif
embedding/tests/wxEmbed/wxEmbed.def
embedding/tests/wxEmbed/wxEmbed.dsp
embedding/tests/wxEmbed/wxEmbed.rc
embedding/wrappers/DotNETEmbed/AssemblyInfo.cpp
embedding/wrappers/DotNETEmbed/DotNETEmbed.cpp
embedding/wrappers/DotNETEmbed/DotNETEmbed.h
embedding/wrappers/DotNETEmbed/DotNETEmbed.snk
embedding/wrappers/DotNETEmbed/DotNETNetworking.cpp
embedding/wrappers/DotNETEmbed/DotNETNetworking.h
embedding/wrappers/DotNETEmbed/DotNETProfileManager.cpp
embedding/wrappers/DotNETEmbed/DotNETProfileManager.h
embedding/wrappers/DotNETEmbed/DotNETWebBrowser.h
embedding/wrappers/DotNETEmbed/DotNETXPCOM_IO.h
embedding/wrappers/DotNETEmbed/Makefile
embedding/wrappers/DotNETEmbed/ManagedGecko.html
embedding/wrappers/DotNETEmbed/WebChrome.cpp
embedding/wrappers/DotNETEmbed/umWebChrome.h
embedding/wrappers/Makefile.in
embedding/wrappers/readme.txt
gfx/cairo/qpainter-type.patch
js/src/xpconnect/shell/xpcshell.cpp
layout/build/nsLayoutStatics.cpp
layout/generic/nsFrameFrame.cpp
layout/reftests/svg/smil/anim-fillopacity-1.svg
layout/reftests/svg/smil/anim-strokewidth-1.svg
layout/reftests/svg/smil/style/anim-css-fontsize-pt-1-ref.svg
layout/reftests/svg/smil/style/anim-css-fontsize-pt-1.svg
layout/reftests/svg/smil/style/anim-css-fontsize-px-1-ref.svg
layout/reftests/svg/smil/style/anim-css-fontsize-px-1a.svg
layout/reftests/svg/smil/style/anim-css-fontsize-px-1b.svg
layout/reftests/svg/smil/style/anim-css-fontsize-px-1c.svg
layout/reftests/svg/smil/style/fill-1-ref.svg
layout/reftests/svg/smil/style/fill-1.svg
layout/reftests/svg/smil/style/font-size-1-ref.svg
layout/reftests/svg/smil/style/font-size-1.svg
media/liboggplay/bug488951.patch
media/liboggplay/bug488951_yuv_fix.patch
media/liboggplay/bug488951_yuv_fix_2.patch
media/liboggplay/bug492436.patch
media/liboggplay/bug493140.patch
media/liboggplay/bug493224.patch
media/liboggplay/bug495129a.patch
media/liboggplay/bug495129b.patch
media/liboggplay/bug498815.patch
media/liboggplay/bug498824.patch
media/liboggplay/bug499519.patch
media/liboggplay/trac466.patch
media/libtheora/455357_wince_local_variable_macro_clash_patch
media/libtheora/bug498770.patch
media/libtheora/bug498815.patch
media/libtheora/bug498824.patch
media/libtheora/bug504613.patch
media/libtheora/lib/dec/apiwrapper.c
media/libtheora/lib/dec/apiwrapper.h
media/libtheora/lib/dec/bitpack.c
media/libtheora/lib/dec/bitpack.h
media/libtheora/lib/dec/dct.h
media/libtheora/lib/dec/decapiwrapper.c
media/libtheora/lib/dec/decinfo.c
media/libtheora/lib/dec/decint.h
media/libtheora/lib/dec/decode.c
media/libtheora/lib/dec/dequant.c
media/libtheora/lib/dec/dequant.h
media/libtheora/lib/dec/fragment.c
media/libtheora/lib/dec/huffdec.c
media/libtheora/lib/dec/huffdec.h
media/libtheora/lib/dec/huffman.h
media/libtheora/lib/dec/idct.c
media/libtheora/lib/dec/idct.h
media/libtheora/lib/dec/info.c
media/libtheora/lib/dec/internal.c
media/libtheora/lib/dec/ocintrin.h
media/libtheora/lib/dec/quant.c
media/libtheora/lib/dec/quant.h
media/libtheora/lib/dec/state.c
media/libtheora/lib/dec/x86/mmxfrag.c
media/libtheora/lib/dec/x86/mmxidct.c
media/libtheora/lib/dec/x86/mmxstate.c
media/libtheora/lib/dec/x86/x86int.h
media/libtheora/lib/dec/x86/x86state.c
media/libtheora/lib/dec/x86_vc/mmxfrag.c
media/libtheora/lib/dec/x86_vc/mmxidct.c
media/libtheora/lib/dec/x86_vc/mmxloopfilter.c
media/libtheora/lib/dec/x86_vc/mmxstate.c
media/libtheora/lib/dec/x86_vc/x86int.h
media/libtheora/lib/dec/x86_vc/x86state.c
media/libvorbis/bug481601.patch
modules/plugin/base/src/nsNPAPIPlugin.cpp
modules/plugin/base/src/nsNPAPIPluginInstance.cpp
modules/plugin/base/src/nsPluginHost.cpp
modules/plugin/test/testplugin/nptest.cpp
modules/plugin/test/testplugin/nptest_gtk2.cpp
modules/plugin/test/testplugin/nptest_windows.cpp
netwerk/protocol/http/src/nsHttpHandler.cpp
parser/html/java/htmlparser/Makefile
parser/html/java/javaparser/Makefile
parser/html/java/sync-files.sh
parser/html/java/sync-src.sh
parser/html/java/translator/Makefile
parser/html/java/translator/manifest.txt
parser/html/java/translator/named-character-references.html
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/AnnotationHelperVisitor.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/CppTypes.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/CppVisitor.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/GkAtomParser.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/HVisitor.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/LabelVisitor.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/LicenseExtractor.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/LocalSymbolTable.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/Main.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/NoCppInputStream.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/StringLiteralParser.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/StringPair.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/SymbolTable.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/SymbolTableVisitor.java
parser/html/java/translator/src/nu/validator/htmlparser/cpptranslate/Type.java
parser/html/java/translator/src/nu/validator/htmlparser/generator/GenerateNamedCharacters.java
parser/html/java/translator/src/nu/validator/htmlparser/generator/GenerateNamedCharactersCpp.java
storage/test/unit/test_storage_combined_sharing.js
toolkit/components/places/tests/unit/test_nodes_propertyBag.js
toolkit/components/places/tests/unit/test_utils_archiveBookmarksFile.js
toolkit/library/libxul-config.mk
toolkit/locales/en-US/chrome/global/gnomeprintdialog.properties
toolkit/themes/pinstripe/global/globalBindings.xml
toolkit/toolkit-makefiles.sh
toolkit/toolkit-tiers.mk
toolkit/xre/nsAppRunner.cpp
tools/codesighs/basesummary.unix.bash
tools/codesighs/basesummary.win.bash
xpcom/build/Makefile.in
xpcom/build/nsXPComInit.cpp
--- a/.hgignore
+++ b/.hgignore
@@ -24,9 +24,9 @@
 _DBG\.OBJ/
 _OPT\.OBJ/
 
 # SpiderMonkey configury
 ^js/src/configure$
 ^js/src/autom4te.cache$
 
 # Java HTML5 parser classes
-^parser/html/java/.*\.class$
+^parser/html/java/(html|java)parser/
--- a/Makefile.in
+++ b/Makefile.in
@@ -100,16 +100,19 @@ default alldep all::
 export::
 	$(RM) -rf $(DIST)/sdk
 	$(MAKE) -C config export
 	$(MAKE) tier_nspr
 
 ifdef ENABLE_TESTS
 # Additional makefile targets to call automated test suites
 include $(topsrcdir)/testing/testsuite-targets.mk
+else
+# OS X Universal builds will want to call this, so stub it out
+package-tests:
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 # After we build tier toolkit, go back and build the tools from previous dirs
 tier_toolkit::
 	$(MAKE) tools_tier_js
 	$(MAKE) tools_tier_xpcom
--- a/accessible/build/Makefile.in
+++ b/accessible/build/Makefile.in
@@ -41,25 +41,22 @@ topsrcdir	= @top_srcdir@
 srcdir	= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= accessibility
 LIBRARY_NAME	= accessibility
 EXPORT_LIBRARY = 1
-ifneq ($(OS_ARCH),WINNT)
 SHORT_LIBNAME	= access
-endif
 IS_COMPONENT	= 1
 MODULE_NAME	= nsAccessibilityModule
 GRE_MODULE	= 1
 LIBXUL_LIBRARY	= 1
 
-
 CPPSRCS		= nsAccessibilityFactory.cpp
 
 LOCAL_INCLUDES	= -I$(srcdir)/../src
 
 SHARED_LIBRARY_LIBS = \
 	../src/base/$(LIB_PREFIX)accessibility_base_s.$(LIB_SUFFIX) \
 	../src/html/$(LIB_PREFIX)accessibility_html_s.$(LIB_SUFFIX) \
 	../src/$(LIB_PREFIX)accessibility_toolkit_s.$(LIB_SUFFIX) \
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1448,17 +1448,17 @@ NS_IMETHODIMP nsAccessibilityService::Ge
         *aIsHidden = PR_TRUE;
         return NS_OK;
       }
     }
     frame->GetAccessible(getter_AddRefs(newAcc));
     return InitAccessible(newAcc, aAccessible, nsnull);
   }
 
-  PRBool isHTML = content->IsNodeOfType(nsINode::eHTML);
+  PRBool isHTML = content->IsHTML();
   if (isHTML && content->Tag() == nsAccessibilityAtoms::map) {
     // Create hyper text accessible for HTML map if it is used to group links
     // (see http://www.w3.org/TR/WCAG10-HTML-TECHS/#group-bypass). If the HTML
     // map doesn't have 'name' attribute (or has empty name attribute) then we
     // suppose it is used for links grouping. Otherwise we think it is used in
     // conjuction with HTML image element and in this case we don't create any
     // accessible for it and don't walk into it. The accessibles for HTML area
     // (nsHTMLAreaAccessible) the map contains are attached as children of the
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -293,19 +293,19 @@ nsAccessible::GetName(nsAString& aName)
 
   // In the end get the name from tooltip.
   nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
   if (!content)
     return NS_OK;
 
   nsIAtom *tooltipAttr = nsnull;
 
-  if (content->IsNodeOfType(nsINode::eHTML))
+  if (content->IsHTML())
     tooltipAttr = nsAccessibilityAtoms::title;
-  else if (content->IsNodeOfType(nsINode::eXUL))
+  else if (content->IsXUL())
     tooltipAttr = nsAccessibilityAtoms::tooltiptext;
   else
     return NS_OK;
 
   // XXX: if CompressWhiteSpace worked on nsAString we could avoid a copy.
   nsAutoString name;
   if (content->GetAttr(kNameSpaceID_None, tooltipAttr, name)) {
     name.CompressWhitespace();
@@ -337,17 +337,17 @@ NS_IMETHODIMP nsAccessible::GetDescripti
   if (!content->IsNodeOfType(nsINode::eTEXT)) {
     nsAutoString description;
     nsresult rv = nsTextEquivUtils::
       GetTextEquivFromIDRefs(this, nsAccessibilityAtoms::aria_describedby,
                              description);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (description.IsEmpty()) {
-      PRBool isXUL = content->IsNodeOfType(nsINode::eXUL);
+      PRBool isXUL = content->IsXUL();
       if (isXUL) {
         // Try XUL <description control="[id]">description text</description>
         nsIContent *descriptionContent =
           nsCoreUtils::FindNeighbourPointingToNode(content,
                                                    nsAccessibilityAtoms::control,
                                                    nsAccessibilityAtoms::description);
 
         if (descriptionContent) {
@@ -1004,17 +1004,17 @@ nsAccessible::GetStateInternal(PRUint32 
     return NS_OK;  // On document, this is not an error
   }
 
   // Set STATE_UNAVAILABLE state based on disabled attribute
   // The disabled attribute is mostly used in XUL elements and HTML forms, but
   // if someone sets it on another attribute, 
   // it seems reasonable to consider it unavailable
   PRBool isDisabled;
-  if (content->IsNodeOfType(nsINode::eHTML)) {
+  if (content->IsHTML()) {
     // In HTML, just the presence of the disabled attribute means it is disabled,
     // therefore disabled="false" indicates disabled!
     isDisabled = content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::disabled);
   }
   else {
     isDisabled = content->AttrValueIs(kNameSpaceID_None,
                                       nsAccessibilityAtoms::disabled,
                                       nsAccessibilityAtoms::_true,
@@ -1044,17 +1044,17 @@ nsAccessible::GetStateInternal(PRUint32 
     *aState |= nsIAccessibleStates::STATE_OFFSCREEN;
   }
 
   nsIFrame *frame = GetFrame();
   if (frame && (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW))
     *aState |= nsIAccessibleStates::STATE_FLOATING;
 
   // Check if a XUL element has the popup attribute (an attached popup menu).
-  if (content->IsNodeOfType(nsINode::eXUL))
+  if (content->IsXUL())
     if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::popup))
       *aState |= nsIAccessibleStates::STATE_HASPOPUP;
 
   // Add 'linked' state for simple xlink.
   if (nsCoreUtils::IsXLink(content))
     *aState |= nsIAccessibleStates::STATE_LINKED;
 
   return NS_OK;
@@ -2408,17 +2408,17 @@ nsAccessible::GetRelationByType(PRUint32
 
   nsresult rv;
 
   switch (aRelationType)
   {
   case nsIAccessibleRelation::RELATION_LABEL_FOR:
     {
       if (content->Tag() == nsAccessibilityAtoms::label) {
-        nsIAtom *IDAttr = content->IsNodeOfType(nsINode::eHTML) ?
+        nsIAtom *IDAttr = content->IsHTML() ?
           nsAccessibilityAtoms::_for : nsAccessibilityAtoms::control;
         rv = nsRelUtils::
           AddTargetFromIDRefAttr(aRelationType, aRelation, content, IDAttr);
         NS_ENSURE_SUCCESS(rv, rv);
 
         if (rv != NS_OK_NO_RELATION_TARGET)
           return NS_OK; // XXX bug 381599, avoid performance problems
       }
@@ -2465,17 +2465,17 @@ nsAccessible::GetRelationByType(PRUint32
         AddTargetFromNeighbour(aRelationType, aRelation, content,
                                nsAccessibilityAtoms::aria_describedby);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (rv != NS_OK_NO_RELATION_TARGET)
         return NS_OK; // XXX bug 381599, avoid performance problems
 
       if (content->Tag() == nsAccessibilityAtoms::description &&
-          content->IsNodeOfType(nsINode::eXUL)) {
+          content->IsXUL()) {
         // This affectively adds an optional control attribute to xul:description,
         // which only affects accessibility, by allowing the description to be
         // tied to a control.
         return nsRelUtils::
           AddTargetFromIDRefAttr(aRelationType, aRelation, content,
                                  nsAccessibilityAtoms::control);
       }
 
@@ -2549,17 +2549,17 @@ nsAccessible::GetRelationByType(PRUint32
     {
       return nsRelUtils::
         AddTargetFromNeighbour(aRelationType, aRelation, content,
                                nsAccessibilityAtoms::aria_flowto);
     }
 
   case nsIAccessibleRelation::RELATION_DEFAULT_BUTTON:
     {
-      if (content->IsNodeOfType(nsINode::eHTML)) {
+      if (content->IsHTML()) {
         // HTML form controls implements nsIFormControl interface.
         nsCOMPtr<nsIFormControl> control(do_QueryInterface(content));
         if (control) {
           nsCOMPtr<nsIDOMHTMLFormElement> htmlform;
           control->GetForm(getter_AddRefs(htmlform));
           nsCOMPtr<nsIForm> form(do_QueryInterface(htmlform));
           if (form) {
             nsCOMPtr<nsIContent> formContent =
@@ -3096,20 +3096,20 @@ nsAccessible::GetARIAName(nsAString& aNa
 
 nsresult
 nsAccessible::GetNameInternal(nsAString& aName)
 {
   nsCOMPtr<nsIContent> content = nsCoreUtils::GetRoleContent(mDOMNode);
   if (!content)
     return NS_OK;
 
-  if (content->IsNodeOfType(nsINode::eHTML))
+  if (content->IsHTML())
     return GetHTMLName(aName);
 
-  if (content->IsNodeOfType(nsINode::eXUL))
+  if (content->IsXUL())
     return GetXULName(aName);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessible private methods
 
@@ -3226,17 +3226,17 @@ nsAccessible::GetActionRule(PRUint32 aSt
   if (!content)
     return eNoAction;
   
   // Check if it's simple xlink.
   if (nsCoreUtils::IsXLink(content))
     return eJumpAction;
 
   // Return "click" action on elements that have an attached popup menu.
-  if (content->IsNodeOfType(nsINode::eXUL))
+  if (content->IsXUL())
     if (content->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::popup))
       return eClickAction;
 
   // Has registered 'click' event handler.
   PRBool isOnclick = nsCoreUtils::HasListener(content,
                                               NS_LITERAL_STRING("click"));
 
   if (isOnclick)
--- a/accessible/src/base/nsAccessibleTreeWalker.cpp
+++ b/accessible/src/base/nsAccessibleTreeWalker.cpp
@@ -70,17 +70,17 @@ nsAccessibleTreeWalker::~nsAccessibleTre
   while (NS_SUCCEEDED(PopState()))
     /* do nothing */ ;
    MOZ_COUNT_DTOR(nsAccessibleTreeWalker);
 }
 
 void nsAccessibleTreeWalker::GetKids(nsIDOMNode *aParentNode)
 {
   nsCOMPtr<nsIContent> parentContent(do_QueryInterface(aParentNode));
-  if (!parentContent || !parentContent->IsNodeOfType(nsINode::eHTML)) {
+  if (!parentContent || !parentContent->IsHTML()) {
     mState.frame = nsnull;  // Don't walk frames in non-HTML content, just walk the DOM.
   }
 
   UpdateFrame(PR_TRUE);
 
   // Walk frames? UpdateFrame() sets this when it sees anonymous frames
   if (mState.siblingIndex == eSiblingsWalkFrames) {
     return;
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -755,17 +755,17 @@ nsCoreUtils::FindDescendantPointingToIDI
     }
   }
   return nsnull;
 }
 
 nsIContent*
 nsCoreUtils::GetLabelContent(nsIContent *aForNode)
 {
-  if (aForNode->IsNodeOfType(nsINode::eXUL))
+  if (aForNode->IsXUL())
     return FindNeighbourPointingToNode(aForNode, nsAccessibilityAtoms::control,
                                        nsAccessibilityAtoms::label);
 
   return GetHTMLLabelContent(aForNode);
 }
 
 nsIContent*
 nsCoreUtils::GetHTMLLabelContent(nsIContent *aForNode)
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -378,18 +378,17 @@ NS_IMETHODIMP nsDocAccessible::TakeFocus
   PRUint32 state;
   GetStateInternal(&state, nsnull);
   if (0 == (state & nsIAccessibleStates::STATE_FOCUSABLE)) {
     return NS_ERROR_FAILURE; // Not focusable
   }
 
   nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
   if (fm) {
-    nsCOMPtr<nsIDOMDocument> domDocument;
-    mDOMNode->GetOwnerDocument(getter_AddRefs(domDocument));
+    nsCOMPtr<nsIDOMDocument> domDocument(do_QueryInterface(mDOMNode));
     nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
     if (document) {
       // focus the document
       nsCOMPtr<nsIDOMElement> newFocus;
       return fm->MoveFocus(document->GetWindow(), nsnull,
                            nsIFocusManager::MOVEFOCUS_ROOT, 0,
                            getter_AddRefs(newFocus));
     }
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -214,17 +214,17 @@ nsTextEquivUtils::AppendTextEquivFromTex
       if (isHTMLBlock && !aString->IsEmpty()) {
         aString->Append(PRUnichar(' '));
       }
     }
     
     return NS_OK;
   }
   
-  if (aContent->IsNodeOfType(nsINode::eHTML) &&
+  if (aContent->IsHTML() &&
       aContent->NodeInfo()->Equals(nsAccessibilityAtoms::br)) {
     aString->AppendLiteral("\r\n");
     return NS_OK;
   }
   
   return NS_OK_NO_NAME_CLAUSE_HANDLED;
 }
 
@@ -388,17 +388,17 @@ nsresult
 nsTextEquivUtils::AppendFromDOMNode(nsIContent *aContent, nsAString *aString)
 {
   nsresult rv = AppendTextEquivFromTextContent(aContent, aString);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (rv != NS_OK_NO_NAME_CLAUSE_HANDLED)
     return NS_OK;
 
-  if (aContent->IsNodeOfType(nsINode::eXUL)) {
+  if (aContent->IsXUL()) {
     nsAutoString textEquivalent;
     nsCOMPtr<nsIDOMXULLabeledControlElement> labeledEl =
       do_QueryInterface(aContent);
 
     if (labeledEl) {
       labeledEl->GetLabel(textEquivalent);
     } else {
       if (aContent->NodeInfo()->Equals(nsAccessibilityAtoms::label,
--- a/accessible/src/html/nsHTMLSelectAccessible.cpp
+++ b/accessible/src/html/nsHTMLSelectAccessible.cpp
@@ -403,17 +403,17 @@ nsHTMLSelectListAccessible::CacheOptSibl
   // Recursive helper for CacheChildren()
 
   PRUint32 numChildren = aParentContent->GetChildCount();
   nsCOMPtr<nsIAccessible> lastGoodAccessible(aLastGoodAccessible);
   nsCOMPtr<nsIAccessible> newAccessible;
 
   for (PRUint32 count = 0; count < numChildren; count ++) {
     nsIContent *childContent = aParentContent->GetChildAt(count);
-    if (!childContent->IsNodeOfType(nsINode::eHTML)) {
+    if (!childContent->IsHTML()) {
       continue;
     }
     nsCOMPtr<nsIAtom> tag = childContent->Tag();
     if (tag == nsAccessibilityAtoms::option || tag == nsAccessibilityAtoms::optgroup) {
       newAccessible = AccessibleForOption(aAccService,
                                            childContent,
                                            lastGoodAccessible,
                                            aChildCount);
@@ -830,17 +830,17 @@ nsresult nsHTMLSelectOptionAccessible::G
   }
 
   return rv;
 }
 
 void nsHTMLSelectOptionAccessible::SelectionChangedIfOption(nsIContent *aPossibleOption)
 {
   if (!aPossibleOption || aPossibleOption->Tag() != nsAccessibilityAtoms::option ||
-      !aPossibleOption->IsNodeOfType(nsINode::eHTML)) {
+      !aPossibleOption->IsHTML()) {
     return;
   }
 
   nsCOMPtr<nsIDOMNode> optionNode(do_QueryInterface(aPossibleOption));
   NS_ASSERTION(optionNode, "No option node for nsIContent with option tag!");
 
   nsCOMPtr<nsIAccessible> multiSelect =
     nsAccUtils::GetMultiSelectFor(optionNode);
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -628,17 +628,17 @@ nsresult nsHyperTextAccessible::DOMPoint
     }
   }
 
   // Get accessible for this findNode, or if that node isn't accessible, use the
   // accessible for the next DOM node which has one (based on forward depth first search)
   nsCOMPtr<nsIAccessible> descendantAccessible;
   if (findNode) {
     nsCOMPtr<nsIContent> findContent = do_QueryInterface(findNode);
-    if (findContent->IsNodeOfType(nsINode::eHTML) && 
+    if (findContent->IsHTML() && 
         findContent->NodeInfo()->Equals(nsAccessibilityAtoms::br)) {
       nsIContent *parent = findContent->GetParent();
       if (parent &&
           parent->IsRootOfNativeAnonymousSubtree() &&
           parent->GetChildCount() == 1) {
         // This <br> is the only node in a text control, therefore it is the hacky
         // "bogus node" used when there is no text in a control
         *aHyperTextOffset = 0;
--- a/accessible/src/msaa/nsWinUtils.cpp
+++ b/accessible/src/msaa/nsWinUtils.cpp
@@ -46,21 +46,27 @@
 
 HRESULT
 nsWinUtils::ConvertToIA2Array(nsIArray *aGeckoArray, IUnknown ***aIA2Array,
                               long *aIA2ArrayLen)
 {
   *aIA2Array = NULL;
   *aIA2ArrayLen = 0;
 
+  if (!aGeckoArray)
+    return S_FALSE;
+
   PRUint32 length = 0;
   nsresult rv = aGeckoArray->GetLength(&length);
   if (NS_FAILED(rv))
     return GetHRESULT(rv);
 
+  if (length == 0)
+    return S_FALSE;
+
   *aIA2Array =
     static_cast<IUnknown**>(nsMemory::Alloc((length) * sizeof(IUnknown*)));
   if (!*aIA2Array)
     return E_OUTOFMEMORY;
 
   PRUint32 idx = 0;
   for (; idx < length; ++idx) {
     nsCOMPtr<nsIWinAccessNode> winAccessNode =
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -81,23 +81,22 @@ endif
 
 LIBS += $(JEMALLOC_LIBS)
 
 ifdef LIBXUL_SDK
 include $(topsrcdir)/config/rules.mk
 else
 # Build a binary bootstrapping with XRE_main
 
-ifeq ($(USE_SHORT_LIBNAME), 1)
+ifneq (,$(filter OS2 WINCE WINNT,$(OS_ARCH)))
 PROGRAM = $(MOZ_APP_NAME)$(BIN_SUFFIX)
 else
 PROGRAM = $(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
 endif
 
-
 CPPSRCS = nsBrowserApp.cpp
 
 LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/xre
 
 ifdef BUILD_STATIC_LIBS
 ifdef _MSC_VER
 STATIC_COMPONENTS_LINKER_PATH = -LIBPATH:$(DEPTH)/staticlib
 else
@@ -339,18 +338,20 @@ libs repackage:: $(PROGRAM) application.
 	rsync -a $(DIST)/bin/ $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
 	$(RM) $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/mangle $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)/shlibsign
 ifdef LIBXUL_SDK
 	cp $(LIBXUL_DIST)/bin/$(XR_STUB_NAME) $(DIST)/$(APP_NAME).app/Contents/MacOS/firefox-bin
 else
 	rm -f $(DIST)/$(APP_NAME).app/Contents/MacOS/$(PROGRAM)
 	rsync -aL $(PROGRAM) $(DIST)/$(APP_NAME).app/Contents/MacOS
 endif
+ifndef MOZ_COCOA_PRINTING
 	mkdir -p $(DIST)/$(APP_NAME).app/Contents/Plug-Ins
 	rsync -a --copy-unsafe-links $(LIBXUL_DIST)/package/PrintPDE.plugin $(DIST)/$(APP_NAME).app/Contents/Plug-Ins
+endif
 	-cp -L $(DIST)/bin/mangle $(DIST)/bin/shlibsign $(DIST)/$(APP_NAME).app/Contents/$(APPFILES)
 	cp -RL $(DIST)/branding/firefox.icns $(DIST)/$(APP_NAME).app/Contents/Resources/firefox.icns
 	cp -RL $(DIST)/branding/document.icns $(DIST)/$(APP_NAME).app/Contents/Resources/document.icns
 	printf APPLMOZB > $(DIST)/$(APP_NAME).app/Contents/PkgInfo
 #       remove CVS dirs from packaged app
 	find $(DIST)/$(APP_NAME).app -type d -name "CVS" -prune -exec rm -rf {} \;
 
 else
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -563,18 +563,22 @@ pref("accessibility.typeaheadfind.linkso
 pref("accessibility.typeaheadfind.flashBar", 1);
 
 // Disable the default plugin for firefox
 pref("plugin.default_plugin_disabled", true);
 
 // plugin finder service url
 pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.php?mimetype=%PLUGIN_MIMETYPE%&appID=%APP_ID%&appVersion=%APP_VERSION%&clientOS=%CLIENT_OS%&chromeLocale=%CHROME_LOCALE%&appRelease=%APP_RELEASE%");
 
-// by default we show an infobar message when pages require plugins the user has not installed
+// by default we show an infobar message when pages require plugins the user has not installed, or are outdated
 pref("plugins.hide_infobar_for_missing_plugin", false);
+pref("plugins.hide_infobar_for_outdated_plugin", false);
+
+pref("plugins.update.url", "https://www.mozilla.com/%LOCALE%/plugins/");
+pref("plugins.update.notifyUser", false);
 
 #ifdef XP_WIN
 pref("browser.preferences.instantApply", false);
 #else
 pref("browser.preferences.instantApply", true);
 #endif
 #ifdef XP_MACOSX
 pref("browser.preferences.animateFadeIn", true);
new file mode 100644
--- /dev/null
+++ b/browser/base/content/aboutSupport.xhtml
@@ -0,0 +1,452 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is aboutSupport.xhtml.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Corporation
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Curtis Bartley <cbartley@mozilla.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+<!DOCTYPE html [
+  <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
+  <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
+  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
+  <!ENTITY % aboutSupportDTD SYSTEM "chrome://browser/locale/aboutSupport.dtd"> %aboutSupportDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <title>&aboutSupport.pageTitle;</title>
+
+    <style type="text/css"><![CDATA[
+
+html {
+  background-color: -moz-Field;
+  color: -moz-FieldText;
+  font: message-box;
+}
+
+body {
+  text-align: justify;
+  width: 90%;
+  margin-left: 5%;
+  margin-right: 5%;
+}
+
+.page-subtitle {
+  margin-bottom: 3em; 
+}
+
+.major-section {
+  margin-top: 2em;
+  margin-bottom: 1em;
+  font-size: large;
+  text-align: start;
+  font-weight: bold;
+}
+
+table {
+  background-color: -moz-Dialog;
+  color: -moz-DialogText;
+  font: message-box;
+  text-align: start;
+  width: 100%;
+  border: 1px solid ThreeDShadow;
+  border-spacing: 0px;
+}
+
+th, td {
+  border: 1px dotted ThreeDShadow;
+  padding: 3px;
+}
+
+thead th {
+  text-align: center;
+}
+
+th {
+  text-align: start;
+  background-color: Highlight;
+  color: HighlightText;
+}
+
+th.column {
+  white-space: nowrap;
+  width: 0px; 
+}
+
+td {
+  text-align: start;
+  border-top: 1px dotted ThreeDShadow;
+}
+
+.prefs-table {
+  width: 100%;
+  table-layout: fixed;
+}
+
+.pref-name {
+  width: 70%;
+  white-space: nowrap;
+  overflow: hidden;
+}
+
+.pref-value {
+  width: 30%;
+  white-space: nowrap;
+  overflow: hidden;
+}
+
+    ]]></style>
+
+    <script type="application/javascript;version=1.7"><![CDATA[
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+window.onload = function () {
+  // Get the FUEL Application object.
+  let Application = Cc["@mozilla.org/fuel/application;1"]
+                      .getService(Ci.fuelIApplication);
+
+  // Get the support URL.
+  let urlFormatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
+                       .getService(Ci.nsIURLFormatter);
+  let supportUrl = urlFormatter.formatURLPref("app.support.baseURL");
+
+  // Get the profile directory.
+  let propertiesService = Cc["@mozilla.org/file/directory_service;1"]
+                            .getService(Ci.nsIProperties);
+  let currProfD = propertiesService.get("ProfD", Ci.nsIFile);
+  let profileDir = currProfD.path;
+
+  // Update the application basics section.
+  document.getElementById("application-box").textContent = Application.name;
+  document.getElementById("version-box").textContent = Application.version;
+  document.getElementById("profile-box").textContent = profileDir;
+  document.getElementById("supportLink").href = supportUrl;
+
+  // Update the other sections.
+  populateExtensionsSection();
+  populatePreferencesSection();
+}
+
+function populateExtensionsSection() {
+  let extensions = Application.extensions.all;
+  let trExtensions = [];
+  for (let i = 0; i < extensions.length; i++) {
+    let extension = extensions[i];
+    let tr = createParentElement("tr", [
+      createElement("td", extension.name),
+      createElement("td", extension.version),
+      createElement("td", extension.enabled),
+      createElement("td", extension.id),
+    ]);
+    trExtensions.push(tr);
+  }
+  appendChildren(document.getElementById("extensions-tbody"), trExtensions);
+}
+
+function populatePreferencesSection() {
+  let modifiedPrefs = getModifiedPrefs();
+
+  function comparePrefs(pref1, pref2) {
+    if (pref1.name < pref2.name)
+      return -1;
+    if (pref1.name > pref2.name)
+      return 1;
+    return 0;
+  }
+
+  let sortedPrefs = modifiedPrefs.sort(comparePrefs);
+
+  let trPrefs = [];
+  for each (let pref in sortedPrefs) {
+    let tdName = createElement("td", pref.name, "pref-name");
+    let tdValue = createElement("td", pref.value, "pref-value");
+    let tr = createParentElement("tr", [tdName, tdValue]);
+    trPrefs.push(tr);
+  }
+
+  appendChildren(document.getElementById("prefs-tbody"), trPrefs);
+}
+
+function getModifiedPrefs() {
+  // We use the low-level prefs API to identify prefs that have been
+  // modified, rather that Application.prefs.all since the latter is
+  // much, much slower.  Application.prefs.all also gets slower each
+  // time it's called.  See bug 517312.
+  let prefService = Cc["@mozilla.org/preferences-service;1"]
+                      .getService(Ci.nsIPrefService);
+  let prefRootBranch = prefService.getBranch("");
+  let prefNames = prefRootBranch.getChildList("", { value: 0 });
+  let prefs = [Application.prefs.get(prefName)
+                      for each (prefName in prefNames)
+                          if (prefRootBranch.prefHasUserValue(prefName))];        
+  return prefs;
+}
+
+function createParentElement(tagName, childElems) {
+  let elem = document.createElement(tagName);
+  appendChildren(elem, childElems);
+  return elem;
+}
+
+function createElement(tagName, textContent, opt_class) {
+  let elem = document.createElement(tagName);
+  elem.textContent = textContent;
+  elem.className = opt_class || "";
+  return elem; 
+}
+
+function appendChildren(parentElem, childNodes) {
+  for (let i = 0; i < childNodes.length; i++)
+    parentElem.appendChild(childNodes[i]);
+}
+
+function copyContentsToClipboard() {
+  // Get the HTML and text representations for the important part of the page.
+  let contentsDiv = document.getElementById("contents");
+  let dataHtml = contentsDiv.innerHTML;
+  let dataText = createTextForElement(contentsDiv);
+
+  // We can't use plain strings, we have to use nsSupportsString.
+  let supportsStringClass = Cc["@mozilla.org/supports-string;1"];
+  let ssHtml = supportsStringClass.createInstance(Ci.nsISupportsString);
+  let ssText = supportsStringClass.createInstance(Ci.nsISupportsString);
+
+  let transferable = Cc["@mozilla.org/widget/transferable;1"]
+                       .createInstance(Ci.nsITransferable);  
+
+  // Add the HTML flavor.
+  transferable.addDataFlavor("text/html");
+  ssHtml.data = dataHtml;
+  transferable.setTransferData("text/html", ssHtml, dataHtml.length * 2);
+
+  // Add the plain text flavor.
+  transferable.addDataFlavor("text/unicode");
+  ssText.data = dataText;
+  transferable.setTransferData("text/unicode", ssText, dataText.length * 2);
+
+  // Store the data into the clipboard.
+  let clipboard = Cc["@mozilla.org/widget/clipboard;1"]
+                    .getService(Ci.nsIClipboard);
+  clipboard.setData(transferable, null, clipboard.kGlobalClipboard);        
+}
+
+// Return the plain text representation of an element.  Do a little bit
+// of pretty-printing to make it human-readable.
+function createTextForElement(elem) {
+  // Generate the initial text.
+  let textFragmentAccumulator = [];
+  generateTextForElement(elem, "", textFragmentAccumulator);
+  let text = textFragmentAccumulator.join("");
+
+  // Trim extraneous whitespace before newlines, then squash extraneous
+  // blank lines.
+  text = text.replace(/[ \t]+\n/g, "\n");
+  text = text.replace(/\n\n\n*/g, "\n\n");
+
+  return text;
+}
+
+function generateTextForElement(elem, indent, textFragmentAccumulator) {
+  // Add a little extra spacing around most elements.
+  if (elem.tagName != "td")
+    textFragmentAccumulator.push("\n"); 
+
+  // Generate the text representation for each child node.
+  let node = elem.firstChild;
+  while (node) {
+
+    if (node.nodeType == Node.TEXT_NODE) {
+      // Text belonging to this element uses its indentation level.
+      generateTextForTextNode(node, indent, textFragmentAccumulator);
+    }
+    else if (node.nodeType == Node.ELEMENT_NODE) {
+      // Recurse on the child element with an extra level of indentation.
+      generateTextForElement(node, indent + "  ", textFragmentAccumulator); 
+    }
+
+    // Advance!
+    node = node.nextSibling;
+  }
+}
+
+function generateTextForTextNode(node, indent, textFragmentAccumulator) {
+  // If the text node is the first of a run of text nodes, then start
+  // a new line and add the initial indentation.
+  let prevNode = node.previousSibling;
+  if (!prevNode || prevNode.nodeType == Node.TEXT_NODE)
+    textFragmentAccumulator.push("\n" + indent);
+
+  // Trim the text node's text content and add proper indentation after 
+  // any internal line breaks.  
+  let text = node.textContent.trim().replace("\n[ \t]*", "\n" + indent);
+  textFragmentAccumulator.push(text);
+}
+
+    ]]></script>
+
+  </head>
+
+  <body dir="&locale.dir;">
+
+    <h1>
+      &aboutSupport.pageTitle;
+    </h1>
+
+    <div class="page-subtitle">
+        &aboutSupport.pageSubtitle;
+    </div>
+
+    <div>
+      <button onclick="copyContentsToClipboard()">
+        &aboutSupport.copyToClipboard.label;
+      </button>
+    </div>
+
+    <div id="contents">
+
+      <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+      <h2 class="major-section">
+        &aboutSupport.appBasicsTitle;
+      </h2>
+      
+      <table>
+        <tbody>
+          <tr>
+            <th class="column">
+              &aboutSupport.appBasicsName;
+            </th>
+
+            <td id="application-box">
+            </td>
+          </tr>
+            
+          <tr>
+            <th class="column">
+              &aboutSupport.appBasicsVersion;
+            </th>
+
+            <td id="version-box">
+            </td>
+          </tr>
+            
+          <tr>
+            <th class="column">
+              &aboutSupport.appBasicsProfileDir;
+            </th>
+
+            <td id="profile-box">
+            </td>
+          </tr>
+            
+          <tr>
+            <th class="column">
+              &aboutSupport.appBasicsPlugins;
+            </th>
+
+            <td>
+              <a href="about:plugins">about:plugins</a>
+            </td>
+          </tr>
+            
+          <tr>
+            <th class="column">
+              &aboutSupport.appBasicsBuildConfig;
+            </th>
+
+            <td>
+              <a href="about:buildconfig">about:buildconfig</a>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+
+      <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+      <h2 class="major-section">
+        &aboutSupport.extensionsTitle;
+      </h2>
+
+      <table>
+        <thead>
+          <tr>
+            <th>
+              &aboutSupport.extensionName;
+            </th>
+            <th>
+              &aboutSupport.extensionVersion;
+            </th>
+            <th>
+              &aboutSupport.extensionEnabled;
+            </th>
+            <th>
+              &aboutSupport.extensionId;
+            </th>
+          </tr>
+        </thead>
+        <tbody id="extensions-tbody">
+        </tbody>
+      </table>
+
+      <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+      <h2 class="major-section">
+        &aboutSupport.modifiedPrefsTitle;
+      </h2>
+
+      <table class="prefs-table">
+        <thead>
+          <th class="name">
+            &aboutSupport.modifiedPrefsName;
+          </th>
+          
+          <th class="value">
+            &aboutSupport.modifiedPrefsValue;
+          </th>
+        </thead>
+
+        <tbody id="prefs-tbody">
+        </tbody>
+      </table>
+
+      <!-- - - - - - - - - - - - - - - - - - - - - -->
+
+    </div>
+
+  </body>
+
+</html>
--- a/browser/base/content/baseMenuOverlay.xul
+++ b/browser/base/content/baseMenuOverlay.xul
@@ -86,32 +86,37 @@
                   key="key_openHelp"/>
 #endif
 # Show IE Users menu item on Windows only
 #ifdef XP_WIN
         <menuitem label="&helpForIEUsers.label;"
                   accesskey="&helpForIEUsers.accesskey;"
                   oncommand="openHelpLink('ieusers');"/>
 #endif
+        <menuitem id="troubleShooting"
+                  accesskey="&helpTroubleshooting.accesskey;"
+                  label="&helpTroubleshooting.label;"
+                  oncommand="openTroubleshootingPage()"
+                  onclick="checkForMiddleClick(this, event);"/>
         <menuitem id="releaseNotes"
                   accesskey="&helpReleaseNotes.accesskey;"
                   label="&helpReleaseNotes.label;"
                   oncommand="openReleaseNotes()"
                   onclick="checkForMiddleClick(this, event);"/>
         <menuseparator id="updateSeparator"/>
 #ifdef MOZ_UPDATER
         <menuitem id="checkForUpdates"
                   label="&updateCmd.label;"
                   class="menuitem-iconic"
                   oncommand="checkForUpdates();"/>
 #endif
         <menuseparator id="aboutSeparator"/>
         <menuitem id="aboutName"
-                  accesskey="&aboutCmd.accesskey;"
-                  label="&aboutCmd.label;"
+                  accesskey="&aboutProduct.accesskey;"
+                  label="&aboutProduct.label;"
                   oncommand="openAboutDialog();"/>
       </menupopup>
     </menu>
 
     <keyset id="baseMenuKeyset">
 #ifdef XP_MACOSX
         <key id="key_openHelpMac"
              oncommand="openHelpLink('firefox-osxkey');"
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -97,16 +97,20 @@
       <menuitem id="context-media-showcontrols"
                 label="&mediaShowControls.label;"
                 accesskey="&mediaShowControls.accesskey;"
                 oncommand="gContextMenu.mediaCommand('showcontrols');"/>
       <menuitem id="context-media-hidecontrols"
                 label="&mediaHideControls.label;"
                 accesskey="&mediaHideControls.accesskey;"
                 oncommand="gContextMenu.mediaCommand('hidecontrols');"/>
+      <menuitem id="context-video-fullscreen"
+                accesskey="&videoFullScreen.accesskey;"
+                label="&videoFullScreen.label;"
+                oncommand="gContextMenu.fullScreenVideo();"/>
       <menuseparator id="context-media-sep-commands"/>
       <menuitem id="context-reloadimage"
                 label="&reloadImageCmd.label;"
                 accesskey="&reloadImageCmd.accesskey;"
                 oncommand="gContextMenu.reloadImage();"/>
       <menuitem id="context-viewimage"
                 label="&viewImageCmd.label;"
                 accesskey="&viewImageCmd.accesskey;"
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -35,17 +35,17 @@
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
        <menubar id="main-menubar"
                 style="border:0px;padding:0px;margin:0px;-moz-appearance:none">
             <menu id="file-menu" label="&fileMenu.label;"
                   accesskey="&fileMenu.accesskey;">
-              <menupopup id="menu_FilePopup" onpopupshowing="getContentAreaFrameCount();">
+              <menupopup id="menu_FilePopup">
                 <menuitem id="menu_newNavigator"
                           label="&newNavigatorCmd.label;"
                           accesskey="&newNavigatorCmd.accesskey;"
                           key="key_newNavigator"
                           command="cmd_newNavigator"/>
                 <menuitem id="menu_newNavigatorTab"
                           label="&tabCmd.label;"
                           command="cmd_newNavigatorTab"
@@ -73,21 +73,16 @@
                           accesskey="&closeCmd.accesskey;"
                           command="cmd_close"/>
                 <menuseparator/>
                 <menuitem id="menu_savePage"
                           label="&savePageCmd.label;"
                           accesskey="&savePageCmd.accesskey;"
                           key="key_savePage"
                           command="Browser:SavePage"/>
-                <menuitem id="menu_saveFrame"
-                          label="&saveFrameCmd.label;"
-                          accesskey="&saveFrameCmd.accesskey;"
-                          command="Browser:SaveFrame"
-                          hidden="true"/>
                 <menuitem id="menu_sendLink"
                           label="&sendPageCmd.label;"
                           accesskey="&sendPageCmd.accesskey;"
                           command="Browser:SendLink"/>
                 <menuseparator/>
 #ifndef WINCE
                 <menuitem id="menu_printSetup"
                           label="&printSetupCmd.label;"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1191,30 +1191,31 @@ var PlacesStarButton = {
     this._batching = true;
   },
 
   onEndUpdateBatch: function PSB_onEndUpdateBatch() {
     this.updateState();
     this._batching = false;
   },
   
-  onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex) {
+  onItemAdded: function PSB_onItemAdded(aItemId, aFolder, aIndex, aItemType) {
     if (!this._batching && !this._starred)
       this.updateState();
   },
 
-  onBeforeItemRemoved: function PSB_onBeforeItemRemoved(aItemId) {
-  },
+  onBeforeItemRemoved: function() {},
 
-  onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex) {
+  onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex,
+                                            aItemType) {
     if (!this._batching)
       this.updateState();
   },
 
   onItemChanged: function PSB_onItemChanged(aItemId, aProperty,
-                                            aIsAnnotationProperty, aValue) {
+                                            aIsAnnotationProperty, aNewValue,
+                                            aLastModified, aItemType) {
     if (!this._batching && aProperty == "uri")
       this.updateState();
   },
 
   onItemVisited: function() { },
   onItemMoved: function() { }
 };
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -54,17 +54,16 @@
   <commandset id="mainCommandSet">
     <command id="cmd_newNavigator"                 oncommand="OpenBrowserWindow()"/>
     <command id="cmd_handleBackspace" oncommand="BrowserHandleBackspace();" />
     <command id="cmd_handleShiftBackspace" oncommand="BrowserHandleShiftBackspace();" />
 
     <command id="cmd_newNavigatorTab" oncommand="BrowserOpenTab();"/>
     <command id="Browser:OpenFile"  oncommand="BrowserOpenFileWindow();"/>
     <command id="Browser:SavePage" oncommand="saveDocument(window.content.document);"/>
-    <command id="Browser:SaveFrame" oncommand="saveFrameDocument();"/>
 
     <command id="Browser:SendLink"
              oncommand="MailIntegration.sendLinkForWindow(window.content);"/>
 
     <command id="cmd_pageSetup" oncommand="PrintUtils.showPageSetup();"/>
     <command id="cmd_print" oncommand="PrintUtils.print();"/>
     <command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
     <command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -12,17 +12,17 @@ tabbrowser {
 toolbar[printpreview="true"] {
   -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
 }
 
 toolbarpaletteitem[place="palette"] > toolbaritem > hbox[type="places"] {
   display: none;
 }
 
-#main-window[lwtheme="true"] {
+#main-window:-moz-lwtheme {
   background-repeat: no-repeat;
   background-position: top right;
 }
 
 #browser-bottombox[lwthemefooter="true"] {
   background-repeat: no-repeat;
   background-position: bottom left;
 }
@@ -66,16 +66,18 @@ toolbarpaletteitem[place="palette"] > to
 }
 
 #identity-box > hbox {
   max-width: 22em;
   min-width: 1px;
 }
 
 /* ::::: Unified Back-/Forward Button ::::: */
+#back-button > dropmarker,
+#forward-button > dropmarker,
 #back-forward-dropmarker > image ,
 #back-forward-dropmarker > label {
   display: none;
 }
 .unified-nav-current {
   font-weight: bold;
 }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -78,20 +78,16 @@ var gInPrintPreviewMode = false;
 let gDownloadMgr = null;
 
 // Global variable that holds the nsContextMenu instance.
 var gContextMenu = null;
 
 var gAutoHideTabbarPrefListener = null;
 var gBookmarkAllTabsHandler = null;
 
-#ifdef XP_MACOSX
-var gClickAndHoldTimer = null;
-#endif
-
 #ifndef XP_MACOSX
 var gEditUIVisible = true;
 #endif
 
 [
   ["gBrowser",            "content"],
   ["gNavToolbox",         "navigator-toolbox"],
   ["gURLBar",             "urlbar"],
@@ -146,29 +142,16 @@ let gInitialPages = [
 function pageShowEventHandlers(event) {
   // Filter out events that are not about the document load we are interested in
   if (event.originalTarget == content.document) {
     charsetLoadListener(event);
     XULBrowserWindow.asyncUpdateUI();
   }
 }
 
-/**
- * Determine whether or not the content area is displaying a page with frames,
- * and if so, toggle the display of the 'save frame as' menu item.
- **/
-function getContentAreaFrameCount()
-{
-  var saveFrameItem = document.getElementById("menu_saveFrame");
-  if (!content || !content.frames.length || !isContentFrame(document.commandDispatcher.focusedWindow))
-    saveFrameItem.setAttribute("hidden", "true");
-  else
-    saveFrameItem.removeAttribute("hidden");
-}
-
 function UpdateBackForwardCommands(aWebNavigation) {
   var backBroadcaster = document.getElementById("Browser:Back");
   var forwardBroadcaster = document.getElementById("Browser:Forward");
 
   // Avoid setting attributes on broadcasters if the value hasn't changed!
   // Remember, guys, setting attributes on elements is expensive!  They
   // get inherited into anonymous content, broadcast to other widgets, etc.!
   // Don't do it if the value hasn't changed! - dwh
@@ -190,75 +173,72 @@ function UpdateBackForwardCommands(aWebN
   }
 }
 
 #ifdef XP_MACOSX
 /**
  * Click-and-Hold implementation for the Back and Forward buttons
  * XXXmano: should this live in toolbarbutton.xml?
  */
-function ClickAndHoldMouseDownCallback(aButton) {
-  aButton.open = true;
-  gClickAndHoldTimer = null;
-}
-
-function ClickAndHoldMouseDown(aEvent) {
-  /**
-   * 1. Only left click starts the click and hold timer.
-   * 2. Exclude the dropmarker area. This is done by excluding
-   *    elements which target their events directly to the toolbarbutton
-   *    element, i.e. when the nearest-parent-element which allows-events
-   *    is the toolbarbutton element itself.
-   * 3. Do not start the click-and-hold timer if the toolbarbutton is disabled.
-   */
-  if (aEvent.button != 0 ||
-      aEvent.originalTarget == aEvent.currentTarget ||
-      aEvent.currentTarget.disabled)
-    return;
-
-  gClickAndHoldTimer =
-    setTimeout(ClickAndHoldMouseDownCallback, 500, aEvent.currentTarget);
-}
-
-function MayStopClickAndHoldTimer(aEvent) {
-  // Note passing null here is a no-op
-  clearTimeout(gClickAndHoldTimer);
-}
-
-function ClickAndHoldStopEvent(aEvent) {
-  if (aEvent.originalTarget.localName != "menuitem" &&
-      aEvent.currentTarget.open)
-    aEvent.stopPropagation();
-}
-
 function SetClickAndHoldHandlers() {
+  var timer;
+
+  function timerCallback(aButton) {
+    aButton.firstChild.hidden = false;
+    aButton.open = true;
+    timer = null;
+  }
+
+  function mousedownHandler(aEvent) {
+    if (aEvent.button != 0 ||
+        aEvent.currentTarget.open ||
+        aEvent.currentTarget.disabled)
+      return;
+
+    // Prevent the menupopup from opening immediately
+    aEvent.currentTarget.firstChild.hidden = true;
+
+    timer = setTimeout(timerCallback, 500, aEvent.currentTarget);
+  }
+
+  function clickHandler(aEvent) {
+    if (aEvent.button == 0 &&
+        aEvent.target == aEvent.currentTarget &&
+        !aEvent.currentTarget.open &&
+        !aEvent.currentTarget.disabled)
+      aEvent.currentTarget.doCommand();
+  }
+
+  function stopTimer(aEvent) {
+    if (timer) {
+      clearTimeout(timer);
+      timer = null;
+    }
+  }
+
   function _addClickAndHoldListenersOnElement(aElm) {
-    aElm.addEventListener("mousedown", ClickAndHoldMouseDown, false);
-    aElm.addEventListener("mouseup", MayStopClickAndHoldTimer, false);
-    aElm.addEventListener("mouseout", MayStopClickAndHoldTimer, false);
-
-    // don't propagate onclick and oncommand events after
-    // click-and-hold opened the drop-down menu
-    aElm.addEventListener("command", ClickAndHoldStopEvent, true);
-    aElm.addEventListener("click", ClickAndHoldStopEvent, true);
+    aElm.addEventListener("mousedown", mousedownHandler, true);
+    aElm.addEventListener("mouseup", stopTimer, false);
+    aElm.addEventListener("mouseout", stopTimer, false);
+    aElm.addEventListener("click", clickHandler, true);
   }
 
   // Bug 414797: Clone the dropmarker's 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("back-forward-dropmarker")
                         .firstChild.cloneNode(true);
     var backButton = document.getElementById("back-button");
-    backButton.setAttribute("type", "menu-button");
+    backButton.setAttribute("type", "menu");
     backButton.appendChild(popup);
     _addClickAndHoldListenersOnElement(backButton);
     var forwardButton = document.getElementById("forward-button");
     popup = popup.cloneNode(true);
-    forwardButton.setAttribute("type", "menu-button");
+    forwardButton.setAttribute("type", "menu");
     forwardButton.appendChild(popup);    
     _addClickAndHoldListenersOnElement(forwardButton);
     unifiedButton._clickHandlersAttached = true;
   }
 }
 #endif
 
 function BookmarkThisTab() {
@@ -1089,16 +1069,17 @@ function HandleAppCommandEvent(evt) {
 }
 
 function prepareForStartup() {
   gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver.onUpdatePageReport, false);
   // Note: we need to listen to untrusted events, because the pluginfinder XBL
   // binding can't fire trusted ones (runs with page privileges).
   gBrowser.addEventListener("PluginNotFound", gMissingPluginInstaller.newMissingPlugin, true, true);
   gBrowser.addEventListener("PluginBlocklisted", gMissingPluginInstaller.newMissingPlugin, true, true);
+  gBrowser.addEventListener("PluginOutdated", gMissingPluginInstaller.newMissingPlugin, true, true);
   gBrowser.addEventListener("PluginDisabled", gMissingPluginInstaller.newDisabledPlugin, true, true);
   gBrowser.addEventListener("NewPluginInstalled", gMissingPluginInstaller.refreshBrowser, false);
   gBrowser.addEventListener("NewTab", BrowserOpenTab, false);
   window.addEventListener("AppCommand", HandleAppCommandEvent, true);
 
   var webNavigation;
   try {
     webNavigation = getWebNavigation();
@@ -1752,25 +1733,32 @@ function loadOneOrMoreURIs(aURIString)
   // so that we don't disrupt startup
   try {
     gBrowser.loadTabs(aURIString.split("|"), false, true);
   } 
   catch (e) {
   }
 }
 
+function focusAndSelectUrlBar() {
+  if (gURLBar && !gURLBar.readOnly) {
+    if (window.fullScreen)
+      FullScreen.mouseoverToggle(true);
+    if (isElementVisible(gURLBar)) {
+      gURLBar.focus();
+      gURLBar.select();
+      return true;
+    }
+  }
+  return false;
+}
+
 function openLocation() {
-  if (window.fullScreen)
-    FullScreen.mouseoverToggle(true);
-
-  if (gURLBar && isElementVisible(gURLBar) && !gURLBar.readOnly) {
-    gURLBar.focus();
-    gURLBar.select();
+  if (focusAndSelectUrlBar())
     return;
-  }
 
 #ifdef XP_MACOSX
   if (window.location.href != getBrowserURL()) {
     var win = getTopWin();
     if (win) {
       // If there's an open browser window, it should handle this command
       win.focus()
       win.openLocation();
@@ -1798,18 +1786,17 @@ function BrowserOpenTab()
 {
   if (!gBrowser) {
     // If there are no open browser windows, open a new one
     window.openDialog("chrome://browser/content/", "_blank",
                       "chrome,all,dialog=no", "about:blank");
     return;
   }
   gBrowser.loadOneTab("about:blank", {inBackground: false});
-  if (gURLBar)
-    gURLBar.focus();
+  focusAndSelectUrlBar();
 }
 
 /* Called from the openLocation dialog. This allows that dialog to instruct
    its opener to open a new window and then step completely out of the way.
    Anything less byzantine is causing horrible crashes, rather believably,
    though oddly only on Linux. */
 function delayedOpenWindow(chrome, flags, href, postData)
 {
@@ -2376,33 +2363,31 @@ function BrowserOnCommand(event) {
       
       if (ot == errorDoc.getElementById('getMeOutButton')) {
         getMeOutOfHere();
       }
       else if (ot == errorDoc.getElementById('reportButton')) {
         // This is the "Why is this site blocked" button.  For malware,
         // we can fetch a site-specific report, for phishing, we redirect
         // to the generic page describing phishing protection.
-        var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
-                       .getService(Components.interfaces.nsIURLFormatter);
-        
+
         if (isMalware) {
           // Get the stop badware "why is this blocked" report url,
           // append the current url, and go there.
           try {
-            var reportURL = formatter.formatURLPref("browser.safebrowsing.malware.reportURL");
+            let reportURL = formatURL("browser.safebrowsing.malware.reportURL", true);
             reportURL += errorDoc.location.href;
             content.location = reportURL;
           } catch (e) {
             Components.utils.reportError("Couldn't get malware report URL: " + e);
           }
         }
         else { // It's a phishing site, not malware
           try {
-            content.location = formatter.formatURLPref("browser.safebrowsing.warning.infoURL");
+            content.location = formatURL("browser.safebrowsing.warning.infoURL", true);
           } catch (e) {
             Components.utils.reportError("Couldn't get phishing info URL: " + e);
           }
         }
       }
       else if (ot == errorDoc.getElementById('ignoreWarningButton')) {
         // Allow users to override and continue through to the site,
         // but add a notify bar as a reminder, so that they don't lose
@@ -5765,24 +5750,16 @@ function BrowserOpenAddonsMgr(aPane)
   const EMURL = "chrome://mozapps/content/extensions/extensions.xul";
   const EMFEATURES = "chrome,menubar,extra-chrome,toolbar,dialog=no,resizable";
   if (aPane)
     window.openDialog(EMURL, "", EMFEATURES, aPane);
   else
     window.openDialog(EMURL, "", EMFEATURES);
 }
 
-function escapeNameValuePair(aName, aValue, aIsFormUrlEncoded)
-{
-  if (aIsFormUrlEncoded)
-    return escape(aName + "=" + aValue);
-  else
-    return escape(aName) + "=" + escape(aValue);
-}
-
 function AddKeywordForSearchField()
 {
   var node = document.popupNode;
 
   var charset = node.ownerDocument.characterSet;
 
   var docURI = makeURI(node.ownerDocument.URL,
                        charset);
@@ -5800,16 +5777,23 @@ function AddKeywordForSearchField()
 
   var title = gNavigatorBundle.getFormattedString("addKeywordTitleAutoFill",
                                                   [node.ownerDocument.title]);
   var description = PlacesUIUtils.getDescriptionFromDocument(node.ownerDocument);
 
   var el, type;
   var formData = [];
 
+  function escapeNameValuePair(aName, aValue, aIsFormUrlEncoded) {
+    if (aIsFormUrlEncoded)
+      return escape(aName + "=" + aValue);
+    else
+      return escape(aName) + "=" + escape(aValue);
+  }
+
   for (var i=0; i < node.form.elements.length; i++) {
     el = node.form.elements[i];
 
     if (!el.type) // happens with fieldsets
       continue;
 
     if (el == node) {
       formData.push((isURLEncoded) ? escapeNameValuePair(el.name, "%s", true) :
@@ -5914,77 +5898,127 @@ missingPluginInstaller.prototype.newMiss
     return;
 
   // For broken non-object plugin tags, register a click handler so
   // that the user can click the plugin replacement to get the new
   // plugin. Object tags can, and often do, deal with that themselves,
   // so don't stomp on the page developers toes.
 
   if (aEvent.type != "PluginBlocklisted" &&
+      aEvent.type != "PluginOutdated" &&
       !(aEvent.target instanceof HTMLObjectElement)) {
     aEvent.target.addEventListener("click",
                                    gMissingPluginInstaller.installSinglePlugin,
                                    true);
   }
 
-  try {
-    if (gPrefService.getBoolPref("plugins.hide_infobar_for_missing_plugin"))
-      return;
-  } catch (ex) {} // if the pref is missing, treat it as false, which shows the infobar
+  let hideBarPrefName = aEvent.type == "PluginOutdated" ?
+                  "plugins.hide_infobar_for_outdated_plugin" :
+                  "plugins.hide_infobar_for_missing_plugin";
+  if (gPrefService.getBoolPref(hideBarPrefName))
+    return;
 
   var browser = gBrowser.getBrowserForDocument(aEvent.target.ownerDocument
                                                      .defaultView.top.document);
   if (!browser.missingPlugins)
     browser.missingPlugins = {};
 
   var pluginInfo = getPluginInfo(aEvent.target);
 
   browser.missingPlugins[pluginInfo.mimetype] = pluginInfo;
 
   var notificationBox = gBrowser.getNotificationBox(browser);
 
-  // If there is already a missing plugin notification then do nothing
-  if (notificationBox.getNotificationWithValue("missing-plugins"))
+  // Should only display one of these warnings per page.
+  // In order of priority, they are: outdated > missing > blocklisted
+
+  // If there is already an outdated plugin notification then do nothing
+  if (notificationBox.getNotificationWithValue("outdated-plugins"))
     return;
   var blockedNotification = notificationBox.getNotificationWithValue("blocked-plugins");
+  var missingNotification = notificationBox.getNotificationWithValue("missing-plugins");
   var priority = notificationBox.PRIORITY_WARNING_MEDIUM;
 
+  function showBlocklistInfo() {
+    var url = formatURL("extensions.blocklist.detailsURL", true);
+    gBrowser.loadOneTab(url, {inBackground: false});
+    return true;
+  }
+
+  function showOutdatedPluginsInfo() {
+    var url = formatURL("plugins.update.url", true);
+    gBrowser.loadOneTab(url, {inBackground: false});
+    return true;
+  }
+
+  function showPluginsMissing() {
+    // get the urls of missing plugins
+    var missingPluginsArray = gBrowser.selectedBrowser.missingPlugins;
+    if (missingPluginsArray) {
+      window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
+                        "PFSWindow", "chrome,centerscreen,resizable=yes",
+                        {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
+    }
+  }
+
   if (aEvent.type == "PluginBlocklisted") {
-    if (blockedNotification)
+    if (blockedNotification || missingNotification)
       return;
 
     let iconURL = "chrome://mozapps/skin/plugins/pluginBlocked-16.png";
     let messageString = gNavigatorBundle.getString("blockedpluginsMessage.title");
     let buttons = [{
       label: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.label"),
       accessKey: gNavigatorBundle.getString("blockedpluginsMessage.infoButton.accesskey"),
       popup: null,
-      callback: blocklistInfo
+      callback: showBlocklistInfo
     }, {
       label: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.label"),
       accessKey: gNavigatorBundle.getString("blockedpluginsMessage.searchButton.accesskey"),
       popup: null,
-      callback: pluginsMissing
+      callback: showOutdatedPluginsInfo
     }];
 
     notificationBox.appendNotification(messageString, "blocked-plugins",
                                        iconURL, priority, buttons);
   }
+  else if (aEvent.type == "PluginOutdated") {
+    // Cancel any notification about blocklisting/missing plugins
+    if (blockedNotification)
+      blockedNotification.close();
+    if (missingNotification)
+      missingNotification.close();
+
+    let iconURL = "chrome://mozapps/skin/plugins/pluginOutdated-16.png";
+    let messageString = gNavigatorBundle.getString("outdatedpluginsMessage.title");
+    let buttons = [{
+      label: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.label"),
+      accessKey: gNavigatorBundle.getString("outdatedpluginsMessage.updateButton.accesskey"),
+      popup: null,
+      callback: showOutdatedPluginsInfo
+    }];
+
+    notificationBox.appendNotification(messageString, "outdated-plugins",
+                                       iconURL, priority, buttons);
+  }
   else if (aEvent.type == "PluginNotFound") {
-    // Cancel any notification about blocklisting
+    if (missingNotification)
+      return;
+
+    // Cancel any notification about blocklisting plugins
     if (blockedNotification)
       blockedNotification.close();
 
     let iconURL = "chrome://mozapps/skin/plugins/pluginGeneric-16.png";
     let messageString = gNavigatorBundle.getString("missingpluginsMessage.title");
     let buttons = [{
       label: gNavigatorBundle.getString("missingpluginsMessage.button.label"),
       accessKey: gNavigatorBundle.getString("missingpluginsMessage.button.accesskey"),
       popup: null,
-      callback: pluginsMissing
+      callback: showPluginsMissing
     }];
   
     notificationBox.appendNotification(messageString, "missing-plugins",
                                        iconURL, priority, buttons);
   }
 }
 
 missingPluginInstaller.prototype.newDisabledPlugin = function(aEvent){
@@ -6009,36 +6043,16 @@ missingPluginInstaller.prototype.refresh
   if (notification) {
     // reset UI
     notificationBox.removeNotification(notification);
   }
   // reload the browser to make the new plugin show.
   browser.reload();
 }
 
-function blocklistInfo()
-{
-  var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
-                            .getService(Components.interfaces.nsIURLFormatter);
-  var url = formatter.formatURLPref("extensions.blocklist.detailsURL");
-  gBrowser.loadOneTab(url, {inBackground: false});
-  return true;
-}
-
-function pluginsMissing()
-{
-  // get the urls of missing plugins
-  var missingPluginsArray = gBrowser.selectedBrowser.missingPlugins;
-  if (missingPluginsArray) {
-    window.openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
-                      "PFSWindow", "chrome,centerscreen,resizable=yes",
-                      {plugins: missingPluginsArray, browser: gBrowser.selectedBrowser});
-  }
-}
-
 var gMissingPluginInstaller = new missingPluginInstaller();
 
 function convertFromUnicode(charset, str)
 {
   try {
     var unicodeConverter = Components
        .classes["@mozilla.org/intl/scriptableunicodeconverter"]
        .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -291,16 +291,17 @@
 #ifdef WINCE
            defaulticonsize="small" iconsize="small"
 #endif
            defaultmode="icons">
     <!-- Menu -->
     <toolbar type="menubar" id="toolbar-menubar" class="chromeclass-menubar" customizable="true"
              defaultset="menubar-items"
              mode="icons" iconsize="small" defaulticonsize="small"
+             lockiconsize="true"
 #ifdef XP_WIN
              toolbarname="&menubarCmd.label;"
              accesskey="&menubarCmd.accesskey;"
 #endif
              context="toolbar-context-menu">
       <toolbaritem id="menubar-items" align="center">
 # The entire main menubar is placed into browser-menubar.inc, so that it can be shared by 
 # hiddenWindow.xul.
@@ -544,16 +545,17 @@
                        oncommand="BrowserTryToCloseWindow();"/>
       </hbox>
     </toolbar>
 
     <toolbarset id="customToolbars" context="toolbar-context-menu"/>
 
     <toolbar id="PersonalToolbar"
              mode="icons" iconsize="small" defaulticonsize="small"
+             lockiconsize="true"
              class="chromeclass-directories"
              context="toolbar-context-menu"
              defaultset="personal-bookmarks"
              toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
 #ifdef WINCE
              collapsed="true"
 #endif
              customizable="true"/>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/fullscreen-video.xhtml
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<!--
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is mozilla.org code.
+#
+# The Initial Developer of the Original Code is the Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Dão Gottwald <dao@mozilla.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+  <style type="text/css"><![CDATA[
+
+html,
+body,
+video {
+  height: 100%;
+}
+body {
+  margin: 0;
+  background: black;
+  overflow: -moz-hidden-unscrollable;
+}
+body.userIdle {
+  cursor: none;
+}
+video {
+  width: 100%;
+  max-height: 100%;
+}
+body.loadingdata > video,
+body.loadingdata > #close,
+body.userIdle > #close {
+  visibility: hidden;
+}
+
+  ]]></style>
+  <link href="chrome://browser/skin/fullscreen-video.css"
+        rel="stylesheet" type="text/css"/>
+  <script type="application/javascript"><![CDATA[
+
+var contentVideo = window.arguments[0];
+var video;
+
+var title = (contentVideo.currentSrc || contentVideo.src).replace(/^.*\//, "");
+try {
+  title = decodeURI(title);
+} catch (e) {}
+document.title = title;
+
+window.addEventListener("focus", function () {
+  window.removeEventListener("focus", arguments.callee, false);
+
+  window.fullScreen = true;
+
+  video = document.querySelector("video");
+
+  video.addEventListener("loadeddata", function () {
+    video.removeEventListener("loadeddata", arguments.callee, false);
+    video.volume = contentVideo.volume;
+    video.muted = contentVideo.muted;
+    video.poster = contentVideo.poster;
+
+    if (contentVideo.currentTime && !contentVideo.ended) {
+      video.addEventListener("seeked", function () {
+        video.removeEventListener("seeked", arguments.callee, false);
+        playbackStarts();
+      }, false);
+
+      video.currentTime = contentVideo.currentTime;
+    } else {
+      playbackStarts();
+    }
+
+    video.controls = true;
+    video.play();
+  }, false);
+
+  // Automatically close this window when the playback ended, unless the user
+  // interacted with it.
+  video.addEventListener("ended", autoClose, false);
+  window.addEventListener("click", cancelAutoClose, false);
+  window.addEventListener("keypress", cancelAutoClose, false);
+
+  video.addEventListener("playing", hideUI, false);
+  video.addEventListener("seeked", hideUI, false);
+  video.addEventListener("seeking", showUI, false);
+  video.addEventListener("pause", showUI, false);
+  video.addEventListener("ended", showUI, false);
+
+  window.addEventListener("mousemove", function () {
+    showUI();
+    resetIdleTimer();
+  }, false);
+
+  video.mozLoadFrom(contentVideo);
+}, false);
+
+window.addEventListener("unload", function () {
+  if (video.currentSrc) {
+    contentVideo.currentTime = video.currentTime;
+    contentVideo.volume = video.volume;
+    contentVideo.muted = video.muted;
+    if (!video.paused && !video.ended) {
+      video.pause();
+      contentVideo.play();
+    }
+  }
+}, false);
+
+window.addEventListener("keypress", function (event) {
+  if (event.keyCode == event.DOM_VK_ESCAPE) {
+    window.close();
+    return;
+  }
+
+  resetIdleTimer();
+
+  if (!video.controls &&
+      String.fromCharCode(event.charCode) == " ")
+    video.pause();
+}, false);
+
+function playbackStarts() {
+  // Loading the data from the content video may take a second or two. We hide
+  // the video during that period.
+  document.body.classList.remove("loadingdata");
+  video.focus();
+}
+
+function autoClose() {
+  window.close();
+}
+
+function cancelAutoClose() {
+  video.removeEventListener("ended", autoClose, false);
+  window.removeEventListener("click", cancelAutoClose, false);
+  window.removeEventListener("keypress", cancelAutoClose, false);
+}
+
+var idleTimer;
+function resetIdleTimer() {
+  if (idleTimer) {
+    clearTimeout(idleTimer);
+    idleTimer = 0;
+  }
+  idleTimer = setTimeout(function () {
+    idleTimer = 0;
+    hideUI();
+  }, 2000);
+}
+
+function showUI() {
+  if (!video.controls) {
+    document.body.classList.remove("userIdle");
+    video.controls = true;
+  }
+}
+
+function hideUI() {
+  if (!video.paused && !video.ended && !video.seeking && !video.error) {
+    document.body.classList.add("userIdle");
+    video.controls = false;
+  }
+}
+
+  ]]></script>
+</head>
+<body class="loadingdata">
+  <span id="close" onclick="window.close();"/>
+  <video/>
+</body>
+</html>
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -409,27 +409,30 @@ nsContextMenu.prototype = {
 
   initMediaPlayerItems: function() {
     var onMedia = (this.onVideo || this.onAudio);
     // Several mutually exclusive items... play/pause, mute/unmute, show/hide
     this.showItem("context-media-play",  onMedia && (this.target.paused || this.target.ended));
     this.showItem("context-media-pause", onMedia && !this.target.paused && !this.target.ended);
     this.showItem("context-media-mute",   onMedia && !this.target.muted);
     this.showItem("context-media-unmute", onMedia && this.target.muted);
-    this.showItem("context-media-showcontrols", onMedia && !this.target.controls)
-    this.showItem("context-media-hidecontrols", onMedia && this.target.controls)
+    this.showItem("context-media-showcontrols", onMedia && !this.target.controls);
+    this.showItem("context-media-hidecontrols", onMedia && this.target.controls);
+    this.showItem("context-video-fullscreen", this.onVideo);
     // Disable them when there isn't a valid media source loaded.
     if (onMedia) {
       var hasError = (this.target.error != null);
       this.setItemAttr("context-media-play",  "disabled", hasError);
       this.setItemAttr("context-media-pause", "disabled", hasError);
       this.setItemAttr("context-media-mute",   "disabled", hasError);
       this.setItemAttr("context-media-unmute", "disabled", hasError);
       this.setItemAttr("context-media-showcontrols", "disabled", hasError);
       this.setItemAttr("context-media-hidecontrols", "disabled", hasError);
+      if (this.onVideo)
+        this.setItemAttr("context-video-fullscreen",  "disabled", hasError);
     }
     this.showItem("context-media-sep-commands",  onMedia);
   },
 
   // Set various context menu attributes based on the state of the world.
   setTarget: function (aNode, aRangeParent, aRangeOffset) {
     const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     if (aNode.namespaceURI == xulNS ||
@@ -798,16 +801,23 @@ nsContextMenu.prototype = {
                        this.browser.contentPrincipal,
                        Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
     }
 
     var doc = this.target.ownerDocument;
     openUILink(viewURL, e, null, null, null, null, doc.documentURIObject );
   },
 
+  fullScreenVideo: function () {
+    this.target.pause();
+
+    openDialog("chrome://browser/content/fullscreen-video.xhtml",
+               "", "chrome,dialog=no", this.target);
+  },
+
   // Change current window to the URL of the background image.
   viewBGImage: function(e) {
     urlSecurityCheck(this.bgImageURL,
                      this.browser.contentPrincipal,
                      Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
     var doc = this.target.ownerDocument;
     openUILink(this.bgImageURL, e, null, null, null, null, doc.documentURIObject );
   },
@@ -1365,27 +1375,21 @@ nsContextMenu.prototype = {
   addBookmarkForFrame: function CM_addBookmarkForFrame() {
     var doc = this.target.ownerDocument;
     var uri = doc.documentURIObject;
 
     var itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
     if (itemId == -1) {
       var title = doc.title;
       var description = PlacesUIUtils.getDescriptionFromDocument(doc);
-
-      var descAnno = { name: DESCRIPTION_ANNO, value: description };
-      var txn = PlacesUIUtils.ptm.createItem(uri, 
-                                           PlacesUtils.bookmarksMenuFolderId,
-                                           -1, title, null, [descAnno]);
-      PlacesUIUtils.ptm.doTransaction(txn);
-      itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
-      StarUI.beginBatch();
+      PlacesUIUtils.showMinimalAddBookmarkUI(uri, title, description);
     }
-
-    window.top.StarUI.showEditBookmarkPopup(itemId, this.browser, "overlap");
+    else
+      PlacesUIUtils.showItemProperties(itemId,
+                                       PlacesUtils.bookmarks.TYPE_BOOKMARK);
   },
 
   savePageAs: function CM_savePageAs() {
     saveDocument(this.browser.contentDocument);
   },
 
   sendPage: function CM_sendPage() {
     MailIntegration.sendLinkForWindow(this.browser.contentWindow);  
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -300,25 +300,43 @@
             mStateFlags: 0,
             mStatus: 0,
             mMessage: "",
             mTotalProgress: 0,
 
             // count of open requests (should always be 0 or 1)
             mRequestCount: 0,
 
+            destroy: function () {
+              this._cancelStalledTimer();
+              this.mTab.removeAttribute("stalled");
+              delete this.mTab;
+              delete this.mBrowser;
+              delete this.mTabBrowser;
+            },
+
             onProgressChange : function (aWebProgress, aRequest,
                                          aCurSelfProgress, aMaxSelfProgress,
                                          aCurTotalProgress, aMaxTotalProgress)
             {
               this.mTotalProgress = aMaxTotalProgress ? aCurTotalProgress / aMaxTotalProgress : 0;
 
               if (this.mBlank)
                 return;
 
+              if (this.mTotalProgress) {
+                const STATES = 8;
+                let state = Math.ceil(STATES * this.mTotalProgress);
+                if (state != this.mTab.getAttribute("progress")) {
+                  this.mTab.setAttribute("progress", state);
+                  this.mTab.removeAttribute("stalled");
+                  this._startStalledTimer();
+                }
+              }
+
               if (this.mTabBrowser.mCurrentTab == this.mTab) {
                 for (let i = 0; i < this.mTabBrowser.mProgressListeners.length; i++) {
                   let p = this.mTabBrowser.mProgressListeners[i];
                   if (p)
                     try {
                       p.onProgressChange(aWebProgress, aRequest,
                                          aCurSelfProgress, aMaxSelfProgress,
                                          aCurTotalProgress, aMaxTotalProgress);
@@ -388,16 +406,17 @@
                 // cancelled a pending load which would have cleared
                 // its anchor scroll detection temporary increment.
                 if (aWebProgress.DOMWindow == this.mBrowser.contentWindow)
                   this.mBrowser.userTypedClear += 2;
 
                 if (!this.mBlank) {
                   if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
                     this.mTab.setAttribute("busy", "true");
+                    this._startStalledTimer();
                     this.mTabBrowser.updateIcon(this.mTab);
                     this.mTabBrowser.setTabTitleLoading(this.mTab);
                   }
 
                   if (this.mTabBrowser.mCurrentTab == this.mTab)
                     this.mTabBrowser.mIsBusy = true;
                 }
               }
@@ -414,16 +433,19 @@
                   if (!this.mBrowser.mIconURL)
                     this.mTabBrowser.useDefaultIcon(this.mTab);
                 }
 
                 if (this.mBlank)
                   this.mBlank = false;
 
                 this.mTab.removeAttribute("busy");
+                this.mTab.removeAttribute("progress");
+                this.mTab.removeAttribute("stalled");
+                this._cancelStalledTimer();
                 this.mTabBrowser.updateIcon(this.mTab);
 
                 var location = aRequest.QueryInterface(nsIChannel).URI;
 
                 // For keyword URIs clear the user typed value since they will be changed into real URIs
                 if (location.scheme == "keyword")
                   this.mBrowser.userTypedValue = null;
 
@@ -608,16 +630,30 @@
             QueryInterface : function(aIID)
             {
               if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
                   aIID.equals(Components.interfaces.nsIWebProgressListener2) ||
                   aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
                   aIID.equals(Components.interfaces.nsISupports))
                 return this;
               throw Components.results.NS_NOINTERFACE;
+            },
+
+            _startStalledTimer: function () {
+              this._cancelStalledTimer();
+              this._stalledTimer = setTimeout(function (self) { 
+                self.mTab.setAttribute("stalled", "true");
+              }, 700, this);
+            },
+
+            _cancelStalledTimer: function () {
+              if (this._stalledTimer) {
+                clearTimeout(this._stalledTimer);
+                this._stalledTimer = 0;
+              }
             }
           });
         ]]>
         </body>
       </method>
 
       <method name="setIcon">
         <parameter name="aTab"/>
@@ -1491,16 +1527,17 @@
             var evt = document.createEvent("UIEvent");
             evt.initUIEvent("TabClose", true, false, window, aTabWillBeMoved ? 1 : 0);
             aTab.dispatchEvent(evt);
 
             // Remove the tab's filter and progress listener.
             const filter = this.mTabFilters[aTab._tPos];
             browser.webProgress.removeProgressListener(filter);
             filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
+            this.mTabListeners[aTab._tPos].destroy();
 
             // Remove our title change and blocking listeners
             browser.removeEventListener("DOMTitleChanged", this.onTitleChanged, true);
 
             // We are no longer the primary content area.
             browser.setAttribute("type", "content-targetable");
 
             // Remove this tab as the owner of any other tabs, since it's going away.
@@ -1534,18 +1571,18 @@
 
             this._removingTabs.splice(this._removingTabs.indexOf(aTab), 1);
 
             if (aCloseWindow) {
               this._windowIsClosing = true;
               while (this._removingTabs.length)
                 this._endRemoveTab([this._removingTabs[0], false]);
             } else if (!this._windowIsClosing) {
-              if (aNewTab && gURLBar)
-                gURLBar.focus();
+              if (aNewTab)
+                focusAndSelectUrlBar();
 
               // workaround for bug 345399
               this.tabContainer.mTabstrip._updateScrollButtonsDisabledState();
             }
 
             // We're going to remove the tab and the browser now.
             // Clean up mTabFilters and mTabListeners now rather than in
             // _beginRemoveTab, so that their size is always in sync with the
@@ -2731,16 +2768,17 @@
       </constructor>
 
       <destructor>
         <![CDATA[
           for (var i = 0; i < this.mTabListeners.length; ++i) {
             this.getBrowserAtIndex(i).webProgress.removeProgressListener(this.mTabFilters[i]);
             this.mTabFilters[i].removeProgressListener(this.mTabListeners[i]);
             this.mTabFilters[i] = null;
+            this.mTabListeners[i].destroy();
             this.mTabListeners[i] = null;
             this.getBrowserAtIndex(i).removeEventListener("DOMTitleChanged", this.onTitleChanged, true);
           }
           document.removeEventListener("keypress", this._keyEventHandler, false);
         ]]>
       </destructor>
     </implementation>
 
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -133,16 +133,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_scope.js \
                  browser_overflowScroll.js \
                  browser_sanitizeDialog.js \
                  browser_tabs_owner.js \
                  browser_bug491431.js \
                  browser_bug304198.js \
                  browser_drag.js \
                  browser_relatedTabs.js \
+                 browser_contextSearchTabPosition.js \
     $(NULL)
 
 ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _BROWSER_FILES += browser_bug462289.js
 else
 _BROWSER_FILES += browser_customize.js
 endif
 
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_contextSearchTabPosition.js
@@ -0,0 +1,58 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is browser test code.
+ *
+ * The Initial Developer of the Original Code is
+ * John Morkel <jmorkel@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+function test() {
+  function tabAdded(event) {
+    let tab = event.target;
+    tabs.push(tab);
+  }
+
+  let tabs = [];
+
+  let container = gBrowser.tabContainer;
+  container.addEventListener("TabOpen", tabAdded, false);
+
+  gBrowser.addTab("about:blank");
+  BrowserSearch.loadSearch("mozilla", true);
+  BrowserSearch.loadSearch("firefox", true);
+  
+  is(tabs[0], gBrowser.mTabs[3], "blank tab has been pushed to the end");
+  is(tabs[1], gBrowser.mTabs[1], "first search tab opens next to the current tab");
+  is(tabs[2], gBrowser.mTabs[2], "second search tab opens next to the first search tab");
+
+  container.removeEventListener("TabOpen", tabAdded, false);
+  tabs.forEach(gBrowser.removeTab, gBrowser);
+}
--- a/browser/base/content/test/browser_sanitize-download-history.js
+++ b/browser/base/content/test/browser_sanitize-download-history.js
@@ -84,31 +84,28 @@ function test()
       target: testPath,
       startTime: 1180493839859230,
       endTime: 1180493839859239,
       state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
       currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
     };
     let db = Cc["@mozilla.org/download-manager;1"].
              getService(Ci.nsIDownloadManager).DBConnection;
-    let rawStmt = db.createStatement(
+    let stmt = db.createStatement(
       "INSERT INTO moz_downloads (name, source, target, startTime, endTime, " +
         "state, currBytes, maxBytes, preferredAction, autoResume) " +
       "VALUES (:name, :source, :target, :startTime, :endTime, :state, " +
         ":currBytes, :maxBytes, :preferredAction, :autoResume)");
-    let stmt = Cc["@mozilla.org/storage/statement-wrapper;1"].
-               createInstance(Ci.mozIStorageStatementWrapper);
-    stmt.initialize(rawStmt);
     try {
       for (let prop in data)
         stmt.params[prop] = data[prop];
       stmt.execute();
     }
     finally {
-      stmt.statement.finalize();
+      stmt.finalize();
     }
 
     // Toggle history to get everything to update
     EventUtils.synthesizeMouse(history, 0, 0, {}, aWin);
     EventUtils.synthesizeMouse(history, 0, 0, {}, aWin);
 
     ok(!history.checked, "history checkbox is not checked");
     ok(!downloads.disabled, "downloads checkbox is not disabled");
--- a/browser/base/content/test/browser_sanitize-timespans.js
+++ b/browser/base/content/test/browser_sanitize-timespans.js
@@ -586,12 +586,12 @@ function downloadExists(aID)
 {
   let db = dm.DBConnection;
   let stmt = db.createStatement(
     "SELECT * " +
     "FROM moz_downloads " +
     "WHERE id = :id"
   );
   stmt.params.id = aID;
-  var rows = stmt.step();
+  var rows = stmt.executeStep();
   stmt.finalize();
   return rows;
 }
--- a/browser/base/content/test/browser_sanitizeDialog.js
+++ b/browser/base/content/test/browser_sanitizeDialog.js
@@ -737,17 +737,17 @@ function downloadExists(aID)
 {
   let db = dm.DBConnection;
   let stmt = db.createStatement(
     "SELECT * " +
     "FROM moz_downloads " +
     "WHERE id = :id"
   );
   stmt.params.id = aID;
-  let rows = stmt.step();
+  let rows = stmt.executeStep();
   stmt.finalize();
   return !!rows;
 }
 
 /**
  * Runs the next test in the gAllTests array.  If all tests have been run,
  * finishes the entire suite.
  */
--- a/browser/base/content/test/browser_sanitizeDialog_treeView.js
+++ b/browser/base/content/test/browser_sanitizeDialog_treeView.js
@@ -537,17 +537,17 @@ function downloadExists(aID)
 {
   let db = dm.DBConnection;
   let stmt = db.createStatement(
     "SELECT * " +
     "FROM moz_downloads " +
     "WHERE id = :id"
   );
   stmt.params.id = aID;
-  let rows = stmt.step();
+  let rows = stmt.executeStep();
   stmt.finalize();
   return !!rows;
 }
 
 /**
  * Runs the next test in the gAllTests array.  If all tests have been run,
  * finishes the entire suite.
  */
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -23,17 +23,17 @@ netscape.security.PrivilegeManager.enabl
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 function openContextMenuFor(element) {
     // Context menu should be closed before we open it again.
     is(contextMenu.state, "closed", "checking if popup is closed");
 
-    var eventDetails = { type : "contextmenu", button : 2 }
+    var eventDetails = { type : "contextmenu", button : 2 };
     synthesizeMouse(element, 2, 2, eventDetails, element.ownerDocument.defaultView);
 }
 
 function closeContextMenu() {
     contextMenu.hidePopup();
 }
 
 function getVisibleMenuItems(aMenu) {
@@ -49,30 +49,30 @@ function getVisibleMenuItems(aMenu) {
             key = key.toLowerCase();
 
         if (item.nodeName == "menuitem") {
             ok(item.id, "child menuitem #" + i + " has an ID");
             ok(key, "menuitem has an access key");
             if (accessKeys[key])
                 ok(false, "menuitem " + item.id + " has same accesskey as " + accessKeys[key]);
             else
-                accessKeys[key] = item.id
+                accessKeys[key] = item.id;
             items.push(item.id);
             items.push(!item.disabled);
         } else if (item.nodeName == "menuseparator") {
             ok(true, "--- seperator id is " + item.id);
             items.push("---");
             items.push(null);
         } else if (item.nodeName == "menu") {
             ok(item.id, "child menu #" + i + " has an ID");
             ok(key, "menu has an access key");
             if (accessKeys[key])
                 ok(false, "menu " + item.id + " has same accesskey as " + accessKeys[key]);
             else
-                accessKeys[key] = item.id
+                accessKeys[key] = item.id;
             items.push(item.id);
             items.push(!item.disabled);
             // Add a dummy item to that the indexes in checkMenu are the same
             // for expectedItems and actualItems.
             items.push([]);
             items.push(null);
         } else {
             ok(false, "child #" + i + " of menu ID " + aMenu.id +
@@ -156,53 +156,53 @@ function runTest(testNum) {
                           "context-savepage",     true,
                           "context-sendpage",     true,
                           "---",                  null,
                           "context-viewbgimage",  false,
                           "context-selectall",    true,
                           "---",                  null,
                           "context-viewsource",   true,
                           "context-viewinfo",     true]);
-        closeContextMenu()
+        closeContextMenu();
         openContextMenuFor(link); // Invoke context menu for next test.
         break;
 
     case 3:
         // Context menu for text link
         checkContextMenu(["context-openlink",      true,
                           "context-openlinkintab", true,
                           "---",                   null,
                           "context-bookmarklink",  true,
                           "context-savelink",      true,
                           "context-sendlink",      true,
                           "context-copylink",      true]);
-        closeContextMenu()
+        closeContextMenu();
         openContextMenuFor(mailto); // Invoke context menu for next test.
         break;
 
     case 4:
         // Context menu for text mailto-link
         checkContextMenu(["context-copyemail", true]);
-        closeContextMenu()
+        closeContextMenu();
         openContextMenuFor(input); // Invoke context menu for next test.
         break;
 
     case 5:
         // Context menu for text input field
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
                           "context-cut",         false,
                           "context-copy",        false,
                           "context-paste",       null, // ignore clipboard state
                           "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true]);
-        closeContextMenu()
+        closeContextMenu();
         openContextMenuFor(img); // Invoke context menu for next test.
         break;
 
     case 6:
         // Context menu for an image
         checkContextMenu(["context-viewimage",            true,
                           "context-copyimage-contents",   true,
                           "context-copyimage",            true,
@@ -225,46 +225,49 @@ function runTest(testNum) {
         openContextMenuFor(video_ok); // Invoke context menu for next test.
         break;
 
     case 8:
         // Context menu for a video (with a VALID media source)
         checkContextMenu(["context-media-play",         true,
                           "context-media-mute",         true,
                           "context-media-showcontrols", true,
+                          "context-video-fullscreen",   true,
                           "---",                        null,
                           "context-viewvideo",          true,
                           "context-copyvideourl",       true,
                           "---",                        null,
                           "context-savevideo",          true,
                           "context-sendvideo",          true]);
         closeContextMenu();
         openContextMenuFor(video_bad); // Invoke context menu for next test.
         break;
 
     case 9:
         // Context menu for a video (with a INVALID media source)
         checkContextMenu(["context-media-play",         false,
                           "context-media-mute",         false,
                           "context-media-showcontrols", false,
+                          "context-video-fullscreen",   false,
                           "---",                        null,
                           "context-viewvideo",          true,
                           "context-copyvideourl",       true,
                           "---",                        null,
                           "context-savevideo",          true,
                           "context-sendvideo",          true]);
         closeContextMenu();
         openContextMenuFor(video_bad2); // Invoke context menu for next test.
         break;
 
     case 10:
         // Context menu for a video (with a INVALID media source)
         checkContextMenu(["context-media-play",         false,
                           "context-media-mute",         false,
                           "context-media-showcontrols", false,
+                          "context-video-fullscreen",   false,
                           "---",                        null,
                           "context-viewvideo",          false,
                           "context-copyvideourl",       false,
                           "---",                        null,
                           "context-savevideo",          false,
                           "context-sendvideo",          false]);
         closeContextMenu();
         openContextMenuFor(iframe); // Invoke context menu for next test.
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -426,16 +426,25 @@ function openReleaseNotes()
 {
   var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
                             .getService(Components.interfaces.nsIURLFormatter);
   var relnotesURL = formatter.formatURLPref("app.releaseNotesURL");
   
   openUILinkIn(relnotesURL, "tab");
 }
 
+/**
+ * Opens the troubleshooting information (about:support) page for this version
+ * of the application.
+ */
+function openTroubleshootingPage()
+{
+  openUILinkIn("about:support", "tab");
+}
+
 #ifdef MOZ_UPDATER
 /**
  * Opens the update manager and checks for updates to the application.
  */
 function checkForUpdates()
 {
   var um = 
       Components.classes["@mozilla.org/updates/update-manager;1"].
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -13,21 +13,23 @@ browser.jar:
 *       content/browser/aboutDialog.xul               (content/aboutDialog.xul)
 *       content/browser/aboutDialog.js                (content/aboutDialog.js)
         content/browser/aboutDialog.css               (content/aboutDialog.css)
 *       content/browser/aboutRobots.xhtml             (content/aboutRobots.xhtml)
         content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
         content/browser/aboutRobots-icon-rtl.png      (content/aboutRobots-icon-rtl.png)
         content/browser/aboutRobots-widget-left.png   (content/aboutRobots-widget-left.png)
         content/browser/aboutRobots-widget-right.png  (content/aboutRobots-widget-right.png)
+*       content/browser/aboutSupport.xhtml            (content/aboutSupport.xhtml)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
 *       content/browser/credits.xhtml                 (content/credits.xhtml)
+*       content/browser/fullscreen-video.xhtml        (content/fullscreen-video.xhtml)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
 *       content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
 *       content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
 *       content/browser/pageinfo/feeds.js             (content/pageinfo/feeds.js)
 *       content/browser/pageinfo/feeds.xml            (content/pageinfo/feeds.xml)
 *       content/browser/pageinfo/permissions.js       (content/pageinfo/permissions.js)
 *       content/browser/pageinfo/security.js          (content/pageinfo/security.js)
 *       content/browser/openLocation.js               (content/openLocation.js)
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -76,28 +76,30 @@ static RedirEntry kRedirMap[] = {
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT },
   { "feeds", "chrome://browser/content/feeds/subscribe.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT },
   { "privatebrowsing", "chrome://browser/content/aboutPrivateBrowsing.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
   { "rights",
-#ifdef OFFICIAL_BUILD
+#ifdef MOZ_OFFICIAL_BRANDING
     "chrome://global/content/aboutRights.xhtml",
 #else
     "chrome://global/content/aboutRights-unbranded.xhtml",
 #endif
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT },
   { "robots", "chrome://browser/content/aboutRobots.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT },
   { "sessionrestore", "chrome://browser/content/aboutSessionRestore.xhtml",
-    nsIAboutModule::ALLOW_SCRIPT }
+    nsIAboutModule::ALLOW_SCRIPT },
+  { "support", "chrome://browser/content/aboutSupport.xhtml",
+    nsIAboutModule::ALLOW_SCRIPT },
 };
 static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap);
 
 static nsCAutoString
 GetAboutModuleName(nsIURI *aURI)
 {
   nsCAutoString path;
   aURI->GetPath(path);
--- a/browser/components/about/Makefile.in
+++ b/browser/components/about/Makefile.in
@@ -53,13 +53,9 @@ endif
 EXPORTS_NAMESPACES = mozilla/browser
 
 EXPORTS_mozilla/browser = AboutRedirector.h
 
 CPPSRCS = AboutRedirector.cpp
 
 LOCAL_INCLUDES = -I$(srcdir)/../build
 
-ifdef MOZILLA_OFFICIAL
-DEFINES += -DOFFICIAL_BUILD=1
-endif
-
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -182,16 +182,21 @@ static const nsModuleComponentInfo compo
     NS_ABOUT_MODULE_CONTRACTID_PREFIX "robots",
     AboutRedirector::Create },
 
   { "about:sessionrestore",
     NS_BROWSER_ABOUT_REDIRECTOR_CID,
     NS_ABOUT_MODULE_CONTRACTID_PREFIX "sessionrestore",
     AboutRedirector::Create },
 
+  { "about:support",
+    NS_BROWSER_ABOUT_REDIRECTOR_CID,
+    NS_ABOUT_MODULE_CONTRACTID_PREFIX "support",
+    AboutRedirector::Create },
+
 #ifndef WINCE
 
   { "Profile Migrator",
     NS_FIREFOX_PROFILEMIGRATOR_CID,
     NS_PROFILEMIGRATOR_CONTRACTID,
     nsProfileMigratorConstructor },
 
 #if defined(XP_WIN) && !defined(__MINGW32__)
--- a/browser/components/dirprovider/Makefile.in
+++ b/browser/components/dirprovider/Makefile.in
@@ -39,30 +39,27 @@ DEPTH     = ../../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE               = browsercomps
 LIBRARY_NAME         = browserdirprovider
-ifeq (,$(filter WINNT WINCE,$(OS_ARCH)))
 SHORT_LIBNAME        = brwsrdir
-endif
 IS_COMPONENT         = 1
 MODULE_NAME          = BrowserDirProvider
 FORCE_SHARED_LIB     = 1
 
 # Because we are an application component, link against the CRT statically
 # (on Windows, but only if we're not building our own CRT for jemalloc)
 ifndef MOZ_MEMORY
 USE_STATIC_LIBS      = 1
 endif
 
-
 CPPSRCS = nsBrowserDirectoryProvider.cpp
 
 EXTRA_DSO_LDOPTS = \
 	$(XPCOM_GLUE_LDOPTS) \
 	$(NSPR_LIBS) \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/components/distribution.js
+++ b/browser/components/distribution.js
@@ -14,16 +14,17 @@
  * The Original Code is the Firefox Distribution Customizations.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Dan Mills <thunder@mozilla.com>
+ *   Marco Bonardo <mak77@bonardo.net>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -36,97 +37,104 @@
 
 EXPORTED_SYMBOLS = [ "DistributionCustomizer" ];
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 const Cu = Components.utils;
 
-function DistributionCustomizer() {
-  this._distroDir = this._dirSvc.get("XCurProcD", Ci.nsIFile);
-  this._distroDir.append("distribution");
-
-  let iniFile = this._distroDir.clone();
-  iniFile.append("distribution.ini");
-  this._iniExists = iniFile.exists();
-
-  if (!this._iniExists)
-    return;
+const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC =
+  "distribution-customization-complete";
 
-  this._ini = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
-    getService(Ci.nsIINIParserFactory).createINIParser(iniFile);
-
-  this._prefs = this._prefSvc.getBranch(null);
-  this._locale = this._prefs.getCharPref("general.useragent.locale");
-
+function DistributionCustomizer() {
+  let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
+               getService(Ci.nsIProperties);
+  let iniFile = dirSvc.get("XCurProcD", Ci.nsIFile);
+  iniFile.append("distribution");
+  iniFile.append("distribution.ini");
+  if (iniFile.exists())
+    this._iniFile = iniFile;
 }
+
 DistributionCustomizer.prototype = {
-  __bmSvc: null,
-  get _bmSvc() {
-    if (!this.__bmSvc)
-      this.__bmSvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
-                   getService(Ci.nsINavBookmarksService);
-    return this.__bmSvc;
+  _iniFile: null,
+
+  get _ini() {
+    let ini = Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
+              getService(Ci.nsIINIParserFactory).
+              createINIParser(this._iniFile);
+    this.__defineGetter__("_ini", function() ini);
+    return this._ini;
   },
 
-  __annoSvc: null,
-  get _annoSvc() {
-    if (!this.__annoSvc)
-      this.__annoSvc = Cc["@mozilla.org/browser/annotation-service;1"].
-                   getService(Ci.nsIAnnotationService);
-    return this.__annoSvc;
+  get _locale() {
+    let locale;
+    try {
+      locale = this._prefs.getCharPref("general.useragent.locale");
+    }
+    catch (e) {
+      locale = "en-US";
+    }
+    this.__defineGetter__("_locale", function() locale);
+    return this._locale;
   },
 
-  __livemarkSvc: null,
-  get _livemarkSvc() {
-    if (!this.__livemarkSvc)
-      this.__livemarkSvc = Cc["@mozilla.org/browser/livemark-service;2"].
-                   getService(Ci.nsILivemarkService);
-    return this.__livemarkSvc;
+  get _bmSvc() {
+    let svc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
+              getService(Ci.nsINavBookmarksService);
+    this.__defineGetter__("_bmSvc", function() svc);
+    return this._bmSvc;
   },
 
-  __dirSvc: null,
-  get _dirSvc() {
-    if (!this.__dirSvc)
-      this.__dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-        getService(Ci.nsIProperties);
-    return this.__dirSvc;
+  get _annoSvc() {
+    let svc = Cc["@mozilla.org/browser/annotation-service;1"].
+              getService(Ci.nsIAnnotationService);
+    this.__defineGetter__("_annoSvc", function() svc);
+    return this._annoSvc;
+  },
+
+  get _livemarkSvc() {
+    let svc = Cc["@mozilla.org/browser/livemark-service;2"].
+              getService(Ci.nsILivemarkService);
+    this.__defineGetter__("_livemarkSvc", function() svc);
+    return this._livemarkSvc;
   },
 
-  __prefSvc: null,
   get _prefSvc() {
-    if (!this.__prefSvc)
-      this.__prefSvc = Cc["@mozilla.org/preferences-service;1"].
-        getService(Ci.nsIPrefService);
-    return this.__prefSvc;
+    let svc = Cc["@mozilla.org/preferences-service;1"].
+              getService(Ci.nsIPrefService);
+    this.__defineGetter__("_prefSvc", function() svc);
+    return this._prefSvc;
+  },
+
+  get _prefs() {
+    let branch = this._prefSvc.getBranch(null);
+    this.__defineGetter__("_prefs", function() branch);
+    return this._prefs;
   },
 
-  __iosvc: null,
-  get _iosvc() {
-    if (!this.__iosvc)
-      this.__iosvc = Cc["@mozilla.org/network/io-service;1"].
-                   getService(Ci.nsIIOService);
-    return this.__iosvc;
+  get _ioSvc() {
+    let svc = Cc["@mozilla.org/network/io-service;1"].
+              getService(Ci.nsIIOService);
+    this.__defineGetter__("_ioSvc", function() svc);
+    return this._ioSvc;
   },
 
-  _locale: "en-US",
-  _distroDir: null,
-  _iniExists: false,
-  _ini: null,
+  _makeURI: function DIST__makeURI(spec) {
+    return this._ioSvc.newURI(spec, null, null);
+  },
 
-
-  _makeURI: function DIST__makeURI(spec) {
-    return this._iosvc.newURI(spec, null, null);
-  },
-  _parseBookmarksSection: function DIST_parseBookmarksSection(parentId, section) {
+  _parseBookmarksSection:
+  function DIST_parseBookmarksSection(parentId, section) {
     let keys = [];
     for (let i in enumerate(this._ini.getKeys(section)))
       keys.push(i);
     keys.sort();
+
     let items = {};
     let defaultItemId = -1;
     let maxItemId = -1;
 
     for (let i = 0; i < keys.length; i++) {
       let m = /^item\.(\d+)\.(\w+)\.?(\w*)/.exec(keys[i]);
       if (m) {
         let [foo, iid, iprop, ilocale] = m;
@@ -153,132 +161,151 @@ DistributionCustomizer.prototype = {
       }
     }
 
     let prependIndex = 0;
     for (let iid = 0; iid <= maxItemId; iid++) {
       if (!items[iid])
         continue;
 
-      let index = -1;
+      let index = this._bmSvc.DEFAULT_INDEX;
       let newId;
 
       switch (items[iid]["type"]) {
       case "default":
         break;
 
       case "folder":
         if (iid < defaultItemId)
           index = prependIndex++;
 
         newId = this._bmSvc.createFolder(parentId, items[iid]["title"], index);
 
         this._parseBookmarksSection(newId, "BookmarksFolder-" +
                                     items[iid]["folderId"]);
 
         if (items[iid]["description"])
-          this._annoSvc.setItemAnnotation(newId, "bookmarkProperties/description",
+          this._annoSvc.setItemAnnotation(newId,
+                                          "bookmarkProperties/description",
                                           items[iid]["description"], 0,
                                           this._annoSvc.EXPIRE_NEVER);
 
         break;
 
       case "separator":
         if (iid < defaultItemId)
           index = prependIndex++;
         this._bmSvc.insertSeparator(parentId, index);
         break;
 
       case "livemark":
         if (iid < defaultItemId)
           index = prependIndex++;
 
+        // Don't bother updating the livemark contents on creation.
         newId = this._livemarkSvc.
-          createLivemark(parentId,
-                         items[iid]["title"],
-                         this._makeURI(items[iid]["siteLink"]),
-                         this._makeURI(items[iid]["feedLink"]),
-                         index);
+          createLivemarkFolderOnly(parentId,
+                                   items[iid]["title"],
+                                   this._makeURI(items[iid]["siteLink"]),
+                                   this._makeURI(items[iid]["feedLink"]),
+                                   index);
         break;
 
       case "bookmark":
       default:
         if (iid < defaultItemId)
           index = prependIndex++;
 
         newId = this._bmSvc.insertBookmark(parentId,
                                            this._makeURI(items[iid]["link"]),
                                            index, items[iid]["title"]);
 
         if (items[iid]["description"])
-          this._annoSvc.setItemAnnotation(newId, "bookmarkProperties/description",
+          this._annoSvc.setItemAnnotation(newId,
+                                          "bookmarkProperties/description",
                                           items[iid]["description"], 0,
                                           this._annoSvc.EXPIRE_NEVER);
 
         break;
       }
     }
+    return this._checkCustomizationComplete();
   },
+
+  _customizationsApplied: false,
   applyCustomizations: function DIST_applyCustomizations() {
-    if (!this._iniExists)
-      return;
+    this._customizationsApplied = true;
+    if (!this._iniFile)
+      return this._checkCustomizationComplete();
 
     // nsPrefService loads very early.  Reload prefs so we can set
     // distribution defaults during the prefservice:after-app-defaults
     // notification (see applyPrefDefaults below)
     this._prefSvc.QueryInterface(Ci.nsIObserver);
     this._prefSvc.observe(null, "reload-default-prefs", null);
+  },
+
+  _bookmarksApplied: false,
+  applyBookmarks: function DIST_applyBookarks() {
+    this._bookmarksApplied = true;
+    if (!this._iniFile)
+      return this._checkCustomizationComplete();
 
     let sections = enumToObject(this._ini.getSections());
 
     // The global section, and several of its fields, is required
     // (we also check here to be consistent with applyPrefDefaults below)
     if (!sections["Global"])
-      return;
+      return this._checkCustomizationComplete();
     let globalPrefs = enumToObject(this._ini.getKeys("Global"));
     if (!(globalPrefs["id"] && globalPrefs["version"] && globalPrefs["about"]))
-      return;
-
-    let bmProcessed = false;
-    let bmProcessedPref;
+      return this._checkCustomizationComplete();
 
+    let bmProcessedPref;
     try {
-        bmProcessedPref = this._ini.getString("Global",
-                                              "bookmarks.initialized.pref");
-    } catch (e) {
+      bmProcessedPref = this._ini.getString("Global",
+                                            "bookmarks.initialized.pref");
+    }
+    catch (e) {
       bmProcessedPref = "distribution." +
         this._ini.getString("Global", "id") + ".bookmarksProcessed";
     }
 
+    let bmProcessed = false;
     try {
       bmProcessed = this._prefs.getBoolPref(bmProcessedPref);
-    } catch (e) {}
+    }
+    catch (e) {}
 
     if (!bmProcessed) {
       if (sections["BookmarksMenu"])
         this._parseBookmarksSection(this._bmSvc.bookmarksMenuFolder,
                                     "BookmarksMenu");
       if (sections["BookmarksToolbar"])
         this._parseBookmarksSection(this._bmSvc.toolbarFolder,
                                     "BookmarksToolbar");
       this._prefs.setBoolPref(bmProcessedPref, true);
     }
+    return this._checkCustomizationComplete();
   },
+
+  _prefDefaultsApplied: false,
   applyPrefDefaults: function DIST_applyPrefDefaults() {
-    if (!this._iniExists)
-      return;
+    this._prefDefaultsApplied = true;
+    if (!this._iniFile)
+      return this._checkCustomizationComplete();
 
     let sections = enumToObject(this._ini.getSections());
 
     // The global section, and several of its fields, is required
     if (!sections["Global"])
-      return;
+      return this._checkCustomizationComplete();
     let globalPrefs = enumToObject(this._ini.getKeys("Global"));
     if (!(globalPrefs["id"] && globalPrefs["version"] && globalPrefs["about"]))
-      return;
+      return this._checkCustomizationComplete();
 
     let defaults = this._prefSvc.getDefaultBranch(null);
 
     // Global really contains info we set as prefs.  They're only
     // separate because they are "special" (read: required)
 
     defaults.setCharPref("distribution.id", this._ini.getString("Global", "id"));
     defaults.setCharPref("distribution.version",
@@ -338,16 +365,28 @@ DistributionCustomizer.prototype = {
       for (let key in enumerate(this._ini.getKeys("LocalizablePreferences-" + this._locale))) {
         try {
           let value = eval(this._ini.getString("LocalizablePreferences-" + this._locale, key));
           localizedStr.data = "data:text/plain," + key + "=" + value;
           defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
         } catch (e) { /* ignore bad prefs and move on */ }
       }
     }
+
+    return this._checkCustomizationComplete();
+  },
+
+  _checkCustomizationComplete: function DIST__checkCustomizationComplete() {
+    let prefDefaultsApplied = this._prefDefaultsApplied || !this._iniFile;
+    if (this._customizationsApplied && this._bookmarksApplied &&
+        prefDefaultsApplied) {
+      let os = Cc["@mozilla.org/observer-service;1"].
+               getService(Ci.nsIObserverService);
+      os.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, null);
+    }
   }
 };
 
 function enumerate(UTF8Enumerator) {
   while (UTF8Enumerator.hasMore())
     yield UTF8Enumerator.getNext();
 }
 
--- a/browser/components/feeds/src/FeedConverter.js
+++ b/browser/components/feeds/src/FeedConverter.js
@@ -32,16 +32,18 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK ***** */
 
+Components.utils.import("resource://gre/modules/debug.js");
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 function LOG(str) {
   dump("*** " + str + "\n");
 }
 
@@ -679,10 +681,9 @@ var Module = {
     return true;
   }
 };
 
 function NSGetModule(cm, file) {
   return Module;
 }
 
-#include ../../../../toolkit/content/debug.js
 #include GenericFactory.js
--- a/browser/components/feeds/src/WebContentConverter.js
+++ b/browser/components/feeds/src/WebContentConverter.js
@@ -935,10 +935,8 @@ WebContentConverterRegistrar.prototype =
     service: true
   }]
 };
 
 function NSGetModule(cm, file) {
   return XPCOMUtils.generateModule([WebContentConverterRegistrar]);
 }
 
-#include ../../../../toolkit/content/debug.js
-
--- a/browser/components/microsummaries/src/nsMicrosummaryService.js
+++ b/browser/components/microsummaries/src/nsMicrosummaryService.js
@@ -64,18 +64,28 @@ const ANNO_MICSUM_GEN_URI    = "microsum
 const ANNO_MICSUM_EXPIRATION = "microsummary/expiration";
 const ANNO_STATIC_TITLE      = "bookmarks/staticTitle";
 const ANNO_CONTENT_TYPE      = "bookmarks/contentType";
 
 const MAX_SUMMARY_LENGTH = 4096;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+__defineGetter__("NetUtil", function() {
+  delete this.NetUtil;
+  Cu.import("resource://gre/modules/NetUtil.jsm");
+  return NetUtil;
+});
+
+XPCOMUtils.defineLazyServiceGetter(this, "gObsSvc",
+                                   "@mozilla.org/observer-service;1",
+                                   "nsIObserverService");
+
 function MicrosummaryService() {
-  this._obs.addObserver(this, "xpcom-shutdown", true);
+  gObsSvc.addObserver(this, "xpcom-shutdown", true);
   this._ans.addObserver(this, false);
 
   Cc["@mozilla.org/preferences-service;1"].
     getService(Ci.nsIPrefService).
     getBranch("browser.microsummary.").
     QueryInterface(Ci.nsIPrefBranch2).
     addObserver("", this, true);
 
@@ -94,42 +104,16 @@ MicrosummaryService.prototype = {
 
   // Annotation Service
   get _ans() {
     var svc = Cc["@mozilla.org/browser/annotation-service;1"].
               getService(Ci.nsIAnnotationService);
     this.__defineGetter__("_ans", function() svc);
     return this._ans;
   },
- 
-  // IO Service
-  get _ios() {
-    var svc = Cc["@mozilla.org/network/io-service;1"].
-              getService(Ci.nsIIOService);
-    this.__defineGetter__("_ios", function() svc);
-    return this._ios;
-  },
-
-  // Observer Service
-  get _obs() {
-    var svc = Cc["@mozilla.org/observer-service;1"].
-              getService(Ci.nsIObserverService);
-    this.__defineGetter__("_obs", function() svc);
-    return this._obs;
-  },
-
-  /**
-   * Make a URI from a spec.
-   * @param   spec
-   *          The string spec of the URI.
-   * @returns An nsIURI object.
-   */
-  _uri: function MSS__uri(spec) {
-    return this._ios.newURI(spec, null, null);
-  },
 
   // Directory Locator
   __dirs: null,
   get _dirs() {
     if (!this.__dirs)
       this.__dirs = Cc["@mozilla.org/file/directory_service;1"].
                     getService(Ci.nsIProperties);
     return this.__dirs;
@@ -197,17 +181,17 @@ MicrosummaryService.prototype = {
       notify: function(timer) { this._svc._updateMicrosummaries() }
     };
     this._timer.initWithCallback(callback,
                                  CHECK_INTERVAL,
                                  this._timer.TYPE_REPEATING_SLACK);
   },
   
   _destroy: function MSS__destroy() {
-    this._obs.removeObserver(this, "xpcom-shutdown", true);
+    gObsSvc.removeObserver(this, "xpcom-shutdown", true);
     this._ans.removeObserver(this);
     this._timer.cancel();
     this._timer = null;
   },
 
   _updateMicrosummaries: function MSS__updateMicrosummaries() {
     var bookmarks = this._bookmarks;
 
@@ -258,17 +242,17 @@ MicrosummaryService.prototype = {
 
     // Update if the microsummary differs from the current title.
     if (!title || title != microsummary.content) {
       this._bms.setItemTitle(bookmarkID, microsummary.content);
       var subject = new LiveTitleNotificationSubject(bookmarkID, microsummary);
       LOG("updated live title for " + bookmarkIdentity +
           " from '" + (title == null ? "<no live title>" : title) +
           "' to '" + microsummary.content + "'");
-      this._obs.notifyObservers(subject, "microsummary-livetitle-updated", title);
+      gObsSvc.notifyObservers(subject, "microsummary-livetitle-updated", title);
     }
     else {
       LOG("didn't update live title for " + bookmarkIdentity + "; it hasn't changed");
     }
 
     // Whether or not the title itself has changed, we still save any changes
     // to the update interval, since the interval represents how long to wait
     // before checking again for updates, and that can vary across updates,
@@ -320,17 +304,17 @@ MicrosummaryService.prototype = {
   /**
    * Load a local generator from a file into the cache.
    * 
    * @param   file
    *          nsIFile object pointing to file from which to load generator
    * 
    */
   _cacheLocalGeneratorFile: function MSS__cacheLocalGeneratorFile(file) {
-    var uri = this._ios.newFileURI(file);
+    var uri = NetUtil.ioService.newFileURI(file);
 
     var t = this;
     var callback =
       function MSS_cacheLocalGeneratorCallback(resource) {
         try     { t._handleLocalGenerator(resource) }
         finally { resource.destroy() }
       };
 
@@ -428,28 +412,29 @@ MicrosummaryService.prototype = {
     else {
       // This generator is not already installed.  Save it as a new file.
       topic = "microsummary-generator-installed";
       var generatorName = rootNode.getAttribute("name");
       var fileName = sanitizeName(generatorName) + ".xml";
       var file = this._dirs.get("UsrMicsumGens", Ci.nsIFile);
       file.append(fileName);
       file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
-      generator = new MicrosummaryGenerator(null, this._ios.newFileURI(file));
+      generator = new MicrosummaryGenerator(null,
+                                            NetUtil.ioService.newFileURI(file));
       this._localGenerators[generatorID] = generator;
     }
  
     // Initialize (or reinitialize) the generator from its XML definition,
     // the save the definition to the generator's file.
     generator.initFromXML(xmlDefinition);
     generator.saveXMLToFile(xmlDefinition);
 
     LOG("installed generator " + generatorID);
 
-    this._obs.notifyObservers(generator, topic, null);
+    gObsSvc.notifyObservers(generator, topic, null);
 
     return generator;
   },
 
   /**
    * Get the set of microsummaries available for a given page.  The set
    * might change after this method returns, since this method will trigger
    * an asynchronous load of the page in question (if it isn't already loaded)
@@ -604,18 +589,18 @@ MicrosummaryService.prototype = {
    *          if the bookmark does not have a current microsummary
    *
    */
   getMicrosummary: function MSS_getMicrosummary(bookmarkID) {
     if (!this.hasMicrosummary(bookmarkID))
       return null;
 
     var pageURI = this._bms.getBookmarkURI(bookmarkID);
-    var generatorURI = this._uri(this._ans.getItemAnnotation(bookmarkID,
-                                                             ANNO_MICSUM_GEN_URI));
+    var generatorURI = NetUtil.newURI(this._ans.getItemAnnotation(bookmarkID,
+                                                                  ANNO_MICSUM_GEN_URI));
     var generator = this.getGenerator(generatorURI);
 
     return new Microsummary(pageURI, generator);
   },
 
   /**
    * Get a microsummary for a given page URI and generator URI.
    *
@@ -736,18 +721,18 @@ MicrosummaryService.prototype = {
    */
   refreshMicrosummary: function MSS_refreshMicrosummary(bookmarkID) {
     if (!this.hasMicrosummary(bookmarkID))
       throw "bookmark " + bookmarkID + " does not have a microsummary";
 
     var pageURI = this._bms.getBookmarkURI(bookmarkID);
     if (!pageURI)
       throw("can't get URL for bookmark with ID " + bookmarkID);
-    var generatorURI = this._uri(this._ans.getItemAnnotation(bookmarkID,
-                                                             ANNO_MICSUM_GEN_URI));
+    var generatorURI = NetUtil.newURI(this._ans.getItemAnnotation(bookmarkID,
+                                                                  ANNO_MICSUM_GEN_URI));
 
     var generator = this._localGenerators[generatorURI.spec] ||
                     new MicrosummaryGenerator(generatorURI);
 
     var microsummary = new Microsummary(pageURI, generator);
 
     // A microsummary observer that calls the microsummary service
     // to update the datastore when the microsummary finishes loading.
@@ -835,35 +820,16 @@ Microsummary.prototype = {
   __mss: null,
   get _mss() {
     if (!this.__mss)
       this.__mss = Cc["@mozilla.org/microsummary/service;1"].
                    getService(Ci.nsIMicrosummaryService);
     return this.__mss;
   },
 
-  // IO Service
-  __ios: null,
-  get _ios() {
-    if (!this.__ios)
-      this.__ios = Cc["@mozilla.org/network/io-service;1"].
-                   getService(Ci.nsIIOService);
-    return this.__ios;
-  },
-
-  /**
-   * Make a URI from a spec.
-   * @param   spec
-   *          The string spec of the URI.
-   * @returns An nsIURI object.
-   */
-  _uri: function MSS__uri(spec) {
-    return this._ios.newURI(spec, null, null);
-  },
-
   // nsISupports
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMicrosummary]),
 
   // nsIMicrosummary
   get content() {
     // If we have everything we need to generate the content, generate it.
     if (!this._content &&
         this.generator.loaded &&
@@ -1056,17 +1022,17 @@ Microsummary.prototype = {
       function MS_missingGeneratorErrorCallback(resource) {
         try     { t._handleMissingGeneratorError(resource) }
         finally { resource.destroy() }
       };
 
     try {
       // Extract the URI from which the generator was originally installed.
       var sourceURL = this.generator.uri.path.replace(/^source:/, "");
-      var sourceURI = this._uri(sourceURL);
+      var sourceURI = NetUtil.newURI(sourceURL);
 
       var resource = new MicrosummaryResource(sourceURI);
       resource.load(loadCallback, errorCallback);
     }
     catch(ex) {
       Cu.reportError(ex);
       this._handleMissingGeneratorError();
     }
@@ -1148,26 +1114,16 @@ function MicrosummaryGenerator(aURI, aLo
   this._name = aName || null;
   this._loaded = false;
   this._rules = [];
   this._template = null;
   this._content = null;
 }
 
 MicrosummaryGenerator.prototype = {
-
-  // IO Service
-  __ios: null,
-  get _ios() {
-    if (!this.__ios)
-      this.__ios = Cc["@mozilla.org/network/io-service;1"].
-                   getService(Ci.nsIIOService);
-    return this.__ios;
-  },
-
   // nsISupports
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMicrosummaryGenerator]),
 
   // nsIMicrosummaryGenerator
 
   // Normally this is just the URL from which we download the generator,
   // but for generators stored in the app or profile generators directory
   // it's the value of the generator tag's "uri" attribute (or its local URI
@@ -1262,17 +1218,17 @@ MicrosummaryGenerator.prototype = {
     if (!generatorNode)
       throw Cr.NS_ERROR_FAILURE;
 
     this._name = generatorNode.getAttribute("name");
 
     // We have to retrieve the URI from local generators via the "uri" attribute
     // of its generator tag.
     if (this.localURI && generatorNode.hasAttribute("uri"))
-      this._uri = this._ios.newURI(generatorNode.getAttribute("uri"), null, null);
+      this._uri = NetUtil.newURI(generatorNode.getAttribute("uri"), null, null);
 
     function getFirstChildByTagName(tagName, parentNode, namespace) {
       var nodeList = parentNode.getElementsByTagNameNS(namespace, tagName);
       for (var i = 0; i < nodeList.length; i++) {
         // Make sure that the node is a direct descendent of the generator node
         if (nodeList[i].parentNode == parentNode)
           return nodeList[i];
       }
@@ -1422,17 +1378,17 @@ MicrosummaryGenerator.prototype = {
   },
 
   update: function MSD_update() {
     // Update this generator if it was downloaded from a remote source and has
     // been modified since we last downloaded it.
     var genURI = this.uri;
     if (genURI && /^urn:source:/i.test(genURI.spec)) {
       let genURL = genURI.spec.replace(/^urn:source:/, "");
-      genURI = this._ios.newURI(genURL, null, null);
+      genURI = NetUtil.newURI(genURL, null, null);
     }
 
     // Only continue if we have a valid remote URI
     if (!genURI || !/^https?/.test(genURI.scheme)) {
       LOG("generator did not have valid URI; skipping update: " + genURI.spec);
       return;
     }
 
@@ -1483,19 +1439,17 @@ MicrosummaryGenerator.prototype = {
     var generatorID = this.uri.spec;
     resource.content.documentElement.setAttribute("uri", generatorID);
 
     // Reinitialize this generator with the newly downloaded XML and save to disk.
     this.initFromXML(resource.content);
     this.saveXMLToFile(resource.content);
 
     // Let observers know we've updated this generator
-    var obs = Cc["@mozilla.org/observer-service;1"].
-              getService(Ci.nsIObserverService);
-    obs.notifyObservers(this, "microsummary-generator-updated", null);
+    gObsSvc.notifyObservers(this, "microsummary-generator-updated", null);
   }
 };
 
 
 
 
 
 // Microsummary sets are collections of microsummaries.  They allow callers
@@ -1504,25 +1458,16 @@ MicrosummaryGenerator.prototype = {
 // the set instead of each individual microsummary.
 
 function MicrosummarySet() {
   this._observers = [];
   this._elements = [];
 }
 
 MicrosummarySet.prototype = {
-  // IO Service
-  __ios: null,
-  get _ios() {
-    if (!this.__ios)
-      this.__ios = Cc["@mozilla.org/network/io-service;1"].
-                   getService(Ci.nsIIOService);
-    return this.__ios;
-  },
-
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIMicrosummarySet,
                                          Ci.nsIMicrosummaryObserver]),
 
   // nsIMicrosummaryObserver
 
   onContentLoaded: function MSSet_onContentLoaded(microsummary) {
     for ( var i = 0; i < this._observers.length; i++ )
       this._observers[i].onContentLoaded(microsummary);
@@ -1586,19 +1531,18 @@ MicrosummarySet.prototype = {
 
 
       // Look for a TITLE attribute to give the generator a nice name in the UI.
       var linkTitle = link.getAttribute("title");
 
 
       // Unlike the "href" attribute, the "href" property contains
       // an absolute URI spec, so we use it here to create the URI.
-      var generatorURI = this._ios.newURI(link.href,
-                                          resource.content.characterSet,
-                                          null);
+      var generatorURI = NetUtil.newURI(link.href, resource.content.characterSet,
+                                        null);
 
       if (!/^https?$/i.test(generatorURI.scheme)) {
         LOG("can't load generator " + generatorURI.spec + " from page " +
             resource.uri.spec);
         continue;
       }
 
       var generator = new MicrosummaryGenerator(generatorURI, null, linkTitle);
@@ -1733,25 +1677,16 @@ function MicrosummaryResource(uri) {
   this._loadCallback = null;
   // A function to call if we get an error while loading/parsing the resource.
   this._errorCallback = null;
   // A hidden iframe to parse HTML content.
   this._iframe = null;
 }
 
 MicrosummaryResource.prototype = {
-  // IO Service
-  __ios: null,
-  get _ios() {
-    if (!this.__ios)
-      this.__ios = Cc["@mozilla.org/network/io-service;1"].
-                   getService(Ci.nsIIOService);
-    return this.__ios;
-  },
-
   get uri() {
     return this._uri;
   },
 
   get content() {
     return this._content;
   },
 
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -47,23 +47,26 @@ const Cr = Components.results;
 const Cu = Components.utils;
 
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/distribution.js");
 
 const PREF_EM_NEW_ADDONS_LIST = "extensions.newAddons";
+const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
+const PREF_PLUGINS_UPDATEURL  = "plugins.update.url";
 
-// Check to see if bookmarks need backing up once per
-// day on 1 hour idle.
-const BOOKMARKS_ARCHIVE_IDLE_TIME = 60 * 60;
-
-// Backup bookmarks once every 24 hours.
-const BOOKMARKS_ARCHIVE_INTERVAL = 86400 * 1000;
+// We try to backup bookmarks at idle times, to avoid doing that at shutdown.
+// Number of idle seconds before trying to backup bookmarks.  15 minutes.
+const BOOKMARKS_BACKUP_IDLE_TIME = 15 * 60;
+// Minimum interval in milliseconds between backups.
+const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000;
+// Maximum number of backups to create.  Old ones will be purged.
+const BOOKMARKS_BACKUP_MAX_BACKUPS = 10;
 
 // Factory object
 const BrowserGlueServiceFactory = {
   _instance: null,
   createInstance: function (outer, iid) 
   {
     if (outer != null)
       throw Components.results.NS_ERROR_NO_AGGREGATION;
@@ -71,52 +74,52 @@ const BrowserGlueServiceFactory = {
       this._instance = new BrowserGlue() : this._instance;
   }
 };
 
 // Constructor
 
 function BrowserGlue() {
 
-  this.__defineGetter__("_prefs", function() {
-    delete this._prefs;
-    return this._prefs = Cc["@mozilla.org/preferences-service;1"].
-                         getService(Ci.nsIPrefBranch);
-  });
+  XPCOMUtils.defineLazyServiceGetter(this, "_prefs",
+                                     "@mozilla.org/preferences-service;1",
+                                     "nsIPrefBranch");
 
-  this.__defineGetter__("_bundleService", function() {
-    delete this._bundleService;
-    return this._bundleService = Cc["@mozilla.org/intl/stringbundle;1"].
-                                 getService(Ci.nsIStringBundleService);
-  });
+  XPCOMUtils.defineLazyServiceGetter(this, "_bundleService",
+                                     "@mozilla.org/intl/stringbundle;1",
+                                     "nsIStringBundleService");
 
-  this.__defineGetter__("_idleService", function() {
-    delete this._idleService;
-    return this._idleService = Cc["@mozilla.org/widget/idleservice;1"].
-                           getService(Ci.nsIIdleService);
-  });
+  XPCOMUtils.defineLazyServiceGetter(this, "_idleService",
+                                     "@mozilla.org/widget/idleservice;1",
+                                     "nsIIdleService");
 
-  this.__defineGetter__("_observerService", function() {
-    delete this._observerService;
-    return this._observerService = Cc['@mozilla.org/observer-service;1'].
-                                   getService(Ci.nsIObserverService);
-  });
+  XPCOMUtils.defineLazyServiceGetter(this, "_observerService",
+                                     "@mozilla.org/observer-service;1",
+                                     "nsIObserverService");
+
+  XPCOMUtils.defineLazyGetter(this, "_distributionCustomizer", function() {
+                                return new DistributionCustomizer();
+                              });
 
   this._init();
 }
 
 #ifndef XP_MACOSX
 # OS X has the concept of zero-window sessions and therefore ignores the
 # browser-lastwindow-close-* topics.
 #define OBSERVE_LASTWINDOW_CLOSE_TOPICS 1
 #endif
 
 BrowserGlue.prototype = {
   
   _saveSession: false,
+  _isIdleObserver: false,
+  _isPlacesInitObserver: false,
+  _isPlacesLockedObserver: false,
+  _isPlacesDatabaseLocked: false,
 
   _setPrefToSaveSession: function()
   {
     this._prefs.setBoolPref("browser.sessionstore.resume_session_once", true);
 
     // This method can be called via [NSApplication terminate:] on Mac, which
     // ends up causing prefs not to be flushed to disk, so we need to do that
     // explicitly here. See bug 497652.
@@ -172,30 +175,41 @@ BrowserGlue.prototype = {
       case "session-save":
         this._setPrefToSaveSession();
         subject.QueryInterface(Ci.nsISupportsPRBool);
         subject.data = true;
         break;
       case "places-init-complete":
         this._initPlaces();
         this._observerService.removeObserver(this, "places-init-complete");
+        this._isPlacesInitObserver = false;
         // no longer needed, since history was initialized completely.
         this._observerService.removeObserver(this, "places-database-locked");
+        this._isPlacesLockedObserver = false;
+
+        // Now apply distribution customized bookmarks.
+        // This should always run after Places initialization.
+        this._distributionCustomizer.applyBookmarks();
         break;
       case "places-database-locked":
         this._isPlacesDatabaseLocked = true;
         // stop observing, so further attempts to load history service
         // do not show the prompt.
         this._observerService.removeObserver(this, "places-database-locked");
+        this._isPlacesLockedObserver = false;
         break;
       case "idle":
-        if (this._idleService.idleTime > BOOKMARKS_ARCHIVE_IDLE_TIME * 1000) {
-          // Back up bookmarks.
-          this._archiveBookmarks();
-        }
+        if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000)
+          this._backupBookmarks();
+        break;
+      case "distribution-customization-complete":
+        this._observerService
+            .removeObserver(this, "distribution-customization-complete");
+        // Customization has finished, we don't need the customizer anymore.
+        delete this._distributionCustomizer;
         break;
     }
   }, 
 
   // initialization (called on application startup) 
   _init: function() 
   {
     // observer registration
@@ -208,44 +222,52 @@ BrowserGlue.prototype = {
     osvr.addObserver(this, "quit-application-requested", false);
     osvr.addObserver(this, "quit-application-granted", false);
 #ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
     osvr.addObserver(this, "browser-lastwindow-close-requested", false);
     osvr.addObserver(this, "browser-lastwindow-close-granted", false);
 #endif
     osvr.addObserver(this, "session-save", false);
     osvr.addObserver(this, "places-init-complete", false);
+    this._isPlacesInitObserver = true;
     osvr.addObserver(this, "places-database-locked", false);
+    this._isPlacesLockedObserver = true;
+    osvr.addObserver(this, "distribution-customization-complete", false);
   },
 
   // cleanup (called on application shutdown)
   _dispose: function() 
   {
     // observer removal 
     const osvr = this._observerService;
     osvr.removeObserver(this, "xpcom-shutdown");
     osvr.removeObserver(this, "prefservice:after-app-defaults");
     osvr.removeObserver(this, "final-ui-startup");
     osvr.removeObserver(this, "sessionstore-windows-restored");
     osvr.removeObserver(this, "browser:purge-session-history");
     osvr.removeObserver(this, "quit-application-requested");
+    osvr.removeObserver(this, "quit-application-granted");
 #ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
     osvr.removeObserver(this, "browser-lastwindow-close-requested");
     osvr.removeObserver(this, "browser-lastwindow-close-granted");
 #endif
-    osvr.removeObserver(this, "quit-application-granted");
     osvr.removeObserver(this, "session-save");
+    if (this._isIdleObserver)
+      this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
+    if (this._isPlacesInitObserver)
+      osvr.removeObserver(this, "places-init-complete");
+    if (this._isPlacesLockedObserver)
+      osvr.removeObserver(this, "places-database-locked");
   },
 
   _onAppDefaults: function()
   {
     // apply distribution customizations (prefs)
     // other customizations are applied in _onProfileStartup()
-    var distro = new DistributionCustomizer();
-    distro.applyPrefDefaults();
+    this._distributionCustomizer.applyPrefDefaults();
   },
 
   // profile startup handler (contains profile initialization routines)
   _onProfileStartup: function() 
   {
     this.Sanitizer.onStartup();
     // check if we're in safe mode
     var app = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).
@@ -254,18 +276,17 @@ BrowserGlue.prototype = {
       var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
                getService(Ci.nsIWindowWatcher);
       ww.openWindow(null, "chrome://browser/content/safeMode.xul", 
                     "_blank", "chrome,centerscreen,modal,resizable=no", null);
     }
 
     // apply distribution customizations
     // prefs are applied in _onAppDefaults()
-    var distro = new DistributionCustomizer();
-    distro.applyCustomizations();
+    this._distributionCustomizer.applyCustomizations();
 
     // handle any UI migration
     this._migrateUI();
 
     var ioService = Cc["@mozilla.org/network/io-service;1"].
                     getService(Ci.nsIIOService2);
 
     // if ioService is managing the offline status, then ioservice.offline
@@ -283,17 +304,18 @@ BrowserGlue.prototype = {
 
     this._observerService.notifyObservers(null, "browser-ui-startup-complete", "");
   },
 
   // profile shutdown handler (contains profile cleanup routines)
   _onProfileShutdown: function() 
   {
     this._shutdownPlaces();
-    this._idleService.removeIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME);
+    this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
+    this._isIdleObserver = false;
     this.Sanitizer.onShutdown();
   },
 
   // Browser startup complete. All initial windows have opened.
   _onBrowserStartup: function()
   {
     // Show about:rights notification, if needed.
     if (this._shouldShowRights())
@@ -322,16 +344,21 @@ BrowserGlue.prototype = {
     // Load the "more info" page for a locked places.sqlite
     // This property is set earlier in the startup process:
     // nsPlacesDBFlush loads after profile-after-change and initializes
     // the history service, which sends out places-database-locked
     // which sets this property.
     if (this._isPlacesDatabaseLocked) {
       this._showPlacesLockedNotificationBox();
     }
+
+    // If there are plugins installed that are outdated, and the user hasn't
+    // been warned about them yet, open the plugins update page.
+    if (this._prefs.getBoolPref(PREF_PLUGINS_NOTIFYUSER))
+      this._showPluginUpdatePage();
   },
 
   _onQuitRequest: function(aCancelQuit, aQuitType)
   {
     // If user has already dismissed quit request, then do nothing
     if ((aCancelQuit instanceof Ci.nsISupportsPRBool) && aCancelQuit.data)
       return;
 
@@ -514,16 +541,28 @@ BrowserGlue.prototype = {
 
     // Set pref to indicate we've shown the notification.
     var currentVersion = this._prefs.getIntPref("browser.rights.version");
     this._prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true);
 
     var box = notifyBox.appendNotification(notifyRightsText, "about-rights", null, notifyBox.PRIORITY_INFO_LOW, buttons);
     box.persistence = 3; // arbitrary number, just so bar sticks around for a bit
   },
+  
+  _showPluginUpdatePage : function () {
+    this._prefs.setBoolPref(PREF_PLUGINS_NOTIFYUSER, false);
+
+    var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
+                    getService(Ci.nsIURLFormatter);
+    var updateUrl = formatter.formatURLPref(PREF_PLUGINS_UPDATEURL);
+
+    var win = this.getMostRecentBrowserWindow();
+    var browser = win.gBrowser;
+    browser.selectedTab = browser.addTab(updateUrl);
+  },
 
   // returns the (cached) Sanitizer constructor
   get Sanitizer() 
   {
     if(typeof(Sanitizer) != "function") { // we should dynamically load the script
       Cc["@mozilla.org/moz/jssubscript-loader;1"].
       getService(Ci.mozIJSSubScriptLoader).
       loadSubScript("chrome://browser/content/sanitize.js", null);
@@ -587,31 +626,31 @@ BrowserGlue.prototype = {
 
     // Check if Safe Mode or the user has required to restore bookmarks from
     // default profile's bookmarks.html
     var restoreDefaultBookmarks = false;
     try {
       restoreDefaultBookmarks =
         this._prefs.getBoolPref("browser.bookmarks.restore_default_bookmarks");
       if (restoreDefaultBookmarks) {
-        // Ensure that we already have a bookmarks backup for today
-        this._archiveBookmarks();
+        // Ensure that we already have a bookmarks backup for today.
+        this._backupBookmarks();
         importBookmarks = true;
       }
     } catch(ex) {}
 
     // If the user did not require to restore default bookmarks, or import
     // from bookmarks.html, we will try to restore from JSON
     if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) {
       // get latest JSON backup
       Cu.import("resource://gre/modules/utils.js");
-      var bookmarksBackupFile = PlacesUtils.getMostRecentBackup();
-      if (bookmarksBackupFile && bookmarksBackupFile.leafName.match("\.json$")) {
+      var bookmarksBackupFile = PlacesUtils.backups.getMostRecent("json");
+      if (bookmarksBackupFile) {
         // restore from JSON backup
-        PlacesUtils.restoreBookmarksFromJSONFile(bookmarksBackupFile);
+        PlacesUtils.backups.restoreBookmarksFromJSONFile(bookmarksBackupFile);
         importBookmarks = false;
       }
       else {
         // We have created a new database but we don't have any backup available
         importBookmarks = true;
         var dirService = Cc["@mozilla.org/file/directory_service;1"].
                          getService(Ci.nsIProperties);
         var bookmarksHTMLFile = dirService.get("BMarks", Ci.nsILocalFile);
@@ -678,65 +717,66 @@ BrowserGlue.prototype = {
         this._prefs.setBoolPref("browser.places.importBookmarksHTML", false);
       if (restoreDefaultBookmarks)
         this._prefs.setBoolPref("browser.bookmarks.restore_default_bookmarks",
                                 false);
     }
 
     // Initialize bookmark archiving on idle.
     // Once a day, either on idle or shutdown, bookmarks are backed up.
-    this._idleService.addIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME);
+    if (!this._isIdleObserver) {
+      this._idleService.addIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
+      this._isIdleObserver = true;
+    }
   },
 
   /**
    * Places shut-down tasks
-   * - back up and archive bookmarks
-   * - export bookmarks as HTML, if so configured
+   * - back up bookmarks if needed.
+   * - export bookmarks as HTML, if so configured.
    *
    * Note: quit-application-granted notification is received twice
    *       so replace this method with a no-op when first called.
    */
   _shutdownPlaces: function bg__shutdownPlaces() {
-    // Backup and archive Places bookmarks.
-    this._archiveBookmarks();
+    this._backupBookmarks();
 
     // Backup bookmarks to bookmarks.html to support apps that depend
     // on the legacy format.
     var autoExportHTML = false;
     try {
       autoExportHTML = this._prefs.getBoolPref("browser.bookmarks.autoExportHTML");
-    } catch(ex) {
-      Components.utils.reportError(ex);
-    }
+    } catch(ex) { /* Don't export */ }
 
     if (autoExportHTML) {
       Cc["@mozilla.org/browser/places/import-export-service;1"].
         getService(Ci.nsIPlacesImportExportService).
         backupBookmarksFile();
     }
   },
 
   /**
-   * Back up and archive bookmarks
+   * Backup bookmarks if needed.
    */
-  _archiveBookmarks: function nsBrowserGlue__archiveBookmarks() {
+  _backupBookmarks: function nsBrowserGlue__backupBookmarks() {
     Cu.import("resource://gre/modules/utils.js");
 
-    var lastBackup = PlacesUtils.getMostRecentBackup();
+    let lastBackupFile = PlacesUtils.backups.getMostRecent();
 
-    // Backup bookmarks if there aren't any backups or 
-    // they haven't been backed up in the last 24 hrs.
-    if (!lastBackup ||
-        Date.now() - lastBackup.lastModifiedTime > BOOKMARKS_ARCHIVE_INTERVAL) {
-      var maxBackups = 5;
+    // Backup bookmarks if there are no backups or the maximum interval between
+    // backups elapsed.
+    if (!lastBackupFile ||
+        new Date() - PlacesUtils.backups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL) {
+      let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS;
       try {
         maxBackups = this._prefs.getIntPref("browser.bookmarks.max_backups");
-      } catch(ex) {}
+      }
+      catch(ex) { /* Use default. */ }
 
-      PlacesUtils.archiveBookmarksFile(maxBackups, false /* don't force */);
+      PlacesUtils.backups.create(maxBackups); // Don't force creation.
     }
   },
 
   /**
    * Show the notificationBox for a locked places database.
    */
   _showPlacesLockedNotificationBox: function nsBrowserGlue__showPlacesLockedNotificationBox() {
     var brandBundle  = this._bundleService.createBundle("chrome://branding/locale/brand.properties");
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -146,37 +146,34 @@ PlacesController.prototype = {
     case "cmd_copy":
     case "placesCmd_copy":
       return this._view.hasSelection;
     case "cmd_paste":
     case "placesCmd_paste":
       return this._canInsert(true) && this._isClipboardDataPasteable();
     case "cmd_selectAll":
       if (this._view.selType != "single") {
-        var result = this._view.getResult();
-        if (result) {
-          var container = asContainer(result.root);
-          if (container.containerOpen && container.childCount > 0)
+        var rootNode = this._view.getResultNode();
+        if (rootNode.containerOpen && rootNode.childCount > 0)
             return true;
-        }
       }
       return false;
     case "placesCmd_open":
     case "placesCmd_open:window":
     case "placesCmd_open:tab":
       var selectedNode = this._view.selectedNode;
       return selectedNode && PlacesUtils.nodeIsURI(selectedNode);
     case "placesCmd_new:folder":
     case "placesCmd_new:livemark":
       return this._canInsert();
     case "placesCmd_new:bookmark":
       return this._canInsert();
     case "placesCmd_new:separator":
       return this._canInsert() &&
-             !asQuery(this._view.getResult().root).queryOptions.excludeItems &&
+             !asQuery(this._view.getResultNode()).queryOptions.excludeItems &&
              this._view.getResult().sortingMode ==
                  Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
     case "placesCmd_show:info":
       var selectedNode = this._view.selectedNode;
       if (selectedNode &&
           PlacesUtils.getConcreteItemId(selectedNode) != -1  &&
           !PlacesUtils.nodeIsLivemarkItem(selectedNode))
         return true;
@@ -444,17 +441,17 @@ PlacesController.prototype = {
    *          node are set on its corresponding object as properties.
    * Notes:
    *   1) This can be slow, so don't call it anywhere performance critical!
    *   2) A single-object array corresponding the root node is returned if
    *      there's no selection.
    */
   _buildSelectionMetadata: function PC__buildSelectionMetadata() {
     var metadata = [];
-    var root = this._view.getResult().root;
+    var root = this._view.getResultNode();
     var nodes = this._view.getSelectionNodes();
     if (nodes.length == 0)
       nodes.push(root); // See the second note above
 
     for (var i=0; i < nodes.length; i++) {
       var nodeData = {};
       var node = nodes[i];
       var nodeType = node.type;
@@ -1006,17 +1003,16 @@ PlacesController.prototype = {
    * Removes the set of selected ranges from history.
    */
   _removeRowsFromHistory: function PC__removeRowsFromHistory() {
     // Other containers are history queries, just delete from history
     // history deletes are not undoable.
     var nodes = this._view.getSelectionNodes();
     var URIs = [];
     var bhist = PlacesUtils.history.QueryInterface(Ci.nsIBrowserHistory);
-    var resultView = this._view.getResultView();
     var root = this._view.getResultNode();
 
     for (var i = 0; i < nodes.length; ++i) {
       var node = nodes[i];
       if (PlacesUtils.nodeIsURI(node)) {
         var uri = PlacesUtils._uri(node.uri);
         // avoid trying to delete the same url twice
         if (URIs.indexOf(uri) < 0) {
@@ -1082,17 +1078,17 @@ PlacesController.prototype = {
    *          as part of another operation.
    */
   remove: function PC_remove(aTxnName) {
     if (!this._hasRemovableSelection(false))
       return;
 
     NS_ASSERT(aTxnName !== undefined, "Must supply Transaction Name");
 
-    var root = this._view.getResult().root;
+    var root = this._view.getResultNode();
 
     if (PlacesUtils.nodeIsFolder(root)) 
       this._removeRowsFromBookmarks(aTxnName);
     else if (PlacesUtils.nodeIsQuery(root)) {
       var queryType = asQuery(root).queryOptions.queryType;
       if (queryType == Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS)
         this._removeRowsFromBookmarks(aTxnName);
       else if (queryType == Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY)
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -1060,17 +1060,18 @@ var gEditItemOverlay = {
     case "unload":
       this.uninitPanel(false);
       break;
     }
   },
 
   // nsINavBookmarkObserver
   onItemChanged: function EIO_onItemChanged(aItemId, aProperty,
-                                            aIsAnnotationProperty, aValue) {
+                                            aIsAnnotationProperty, aValue,
+                                            aLastModified, aItemType) {
     if (this._itemId != aItemId) {
       if (aProperty == "title") {
         // If the title of a folder which is listed within the folders
         // menulist has been changed, we need to update the label of its
         // representing element.
         var menupopup = this._folderMenuList.menupopup;
         for (var i=0; i < menupopup.childNodes.length; i++) {
           if (menupopup.childNodes[i].folderId == aItemId) {
@@ -1140,29 +1141,29 @@ var gEditItemOverlay = {
       if (siteURI)
         siteURISpec = siteURI.spec;
       this._initTextField("siteLocationField", siteURISpec);
       break;
     }
   },
 
   onItemMoved: function EIO_onItemMoved(aItemId, aOldParent, aOldIndex,
-                                        aNewParent, aNewIndex) {
+                                        aNewParent, aNewIndex, aItemType) {
     if (aItemId != this._itemId ||
         aNewParent == this._getFolderIdFromMenuList())
       return;
 
     var folderItem = this._getFolderMenuItem(aNewParent);
 
     // just setting selectItem _does not_ trigger oncommand, so we don't
     // recurse
     this._folderMenuList.selectedItem = folderItem;
   },
 
-  onItemAdded: function EIO_onItemAdded(aItemId, aFolder, aIndex) {
+  onItemAdded: function EIO_onItemAdded(aItemId, aFolder, aIndex, aItemType) {
     this._lastNewItem = aItemId;
   },
 
   onBeginUpdateBatch: function() { },
   onEndUpdateBatch: function() { },
   onBeforeItemRemoved: function() { },
   onItemRemoved: function() { },
   onItemVisited: function() { },
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -73,18 +73,16 @@
 
       <!-- markers for start and end of valid places items -->
       <field name="_startMarker">-1</field>
       <field name="_endMarker">-1</field>
 
       <!-- This is the view that manage the popup -->
       <field name="_rootView">PlacesUIUtils.getViewForNode(this);</field>
 
-      <field name="_built">false</field>
-
       <method name="onDragOver">
         <parameter name="aEvent"/>
         <parameter name="aFlavour"/>
         <parameter name="aDragSession"/>
         <body><![CDATA[
           PlacesControllerDragHelper.currentDropTarget = aEvent.target;
           // check if we have a valid dropPoint
           var dropPoint = this._getDropPoint(aEvent);
@@ -531,19 +529,19 @@
     </handlers>
   </binding>
 
 
   <binding id="places-menupopup"
            extends="chrome://browser/content/places/menu.xml#places-popup-base">
     <implementation>
       <destructor><![CDATA[
-        this._resultNode = null;
         if (this._result) {
-          this._result.root.containerOpen = false;
+          this._resultNode.containerOpen = false;
+          this._resultNode = null;
           this._result.viewer = null;
           this._result = null;
         }
       ]]></destructor>
 
       <field name="_initialized">false</field>
       <method name="_ensureInitialized">
         <body><![CDATA[
@@ -569,22 +567,23 @@
 
       <method name="onPopupShowing">
         <parameter name="aEvent"/>
         <body><![CDATA[
           var popup = aEvent.target;
           var resultNode = popup._resultNode;
           if (!resultNode.containerOpen)
             resultNode.containerOpen = true;
-          if (!popup._built)
+          if (!popup.parentNode._built)
             this._rebuild(popup);
         ]]></body>
       </method>
 
       <field name="_result">null</field>
+      <field name="_resultNode">null</field>
 
       <!-- nsIPlacesView -->
       <method name="getResult">
         <body><![CDATA[
           return this._result;
         ]]></body>
       </method>
 
@@ -594,44 +593,35 @@
           this._ensureInitialized();
           return this._resultNode;
         ]]></body>
       </method>
 
       <method name="removeItem">
         <parameter name="child"/>
         <body><![CDATA[
-          if (PlacesUtils.nodeIsContainer(child.node)) {
-            for (var i=0; i < this._containerNodesMap.length; i++) {
-              if (this._containerNodesMap[i].resultNode == child.node) {
-                this._containerNodesMap.splice(i, 1);
-                break;
-              }
-            }
-          }
-
           // if document.popupNode pointed to this child, null it out,
           // otherwise controller's command-updating may rely on the removed
           // item still being "selected".
           if (document.popupNode == child)
             document.popupNode = null;
+
           child.parentNode.removeChild(child);
 
           if (this._endMarker != -1)
             this._endMarker--;
         ]]></body>
       </method>
 
       <method name="insertNewItem">
         <parameter name="aChild"/>
         <parameter name="aParentPopup"/>
         <parameter name="aBefore"/>
         <body><![CDATA[
-          var element =
-            PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
+          var element = PlacesUIUtils.createMenuItemForNode(aChild);
 
           if (aBefore)
             aParentPopup.insertBefore(element, aBefore);
           else {
             // Add the new element to the menu.  If there is static content at
             // the end of the menu, add the element before that.  Otherwise,
             // just add to the end.
             if (aParentPopup._endMarker != -1) {
@@ -684,220 +674,220 @@
             }
           }
           else {
             // This menu is empty.  If there is no static content, add
             // an element to show it is empty.
             if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
               this._showEmptyMenuItem(aPopup);
           }
-          aPopup._built = true;
+          aPopup.parentNode._built = true;
         ]]></body>
       </method>
 
       <!-- nsINavHistoryResultViewer -->
       <field name="_viewer"><![CDATA[({
         _self: this,
 
-        _getPopupForContainer:
-        function PMV__getPopupForContainer(aNode) {
-          if (this._self._resultNode == aNode)
-            return this._self;
-
-          for (var i=0; i < this._self._containerNodesMap.length; i++) {
-            if (this._self._containerNodesMap[i].resultNode == aNode)
-              return this._self._containerNodesMap[i].domNode;
-          }
-          throw("Container view not found");
-        },
-
         get result() {
           return this._self._result;
         },
 
         set result(val) {
           // some methods (e.g. getURLsFromContainer) temporarily null out the
           // viewer when they do temporary changes to the view, this does _not_
           // call setResult(null), but then, we're called again with the result
           // object which is already set for this viewer. At that point,
           // we should do nothing.
           if (this._self._result != val) {
             if (this._self._result)
-              this._self._result.root.containerOpen = false;
-            this._built = false;
-            this._self._containerNodesMap = [];
-            this._self._resultNode = val.root;
+              this._self._resultNode.containerOpen = false;
+
+            this._self.parentNode._built = false;
             this._self._result = val;
+            if (val) {
+              this._self._resultNode = val.root;
+              this._self._resultNode._DOMElement = this._self.parentNode;
+            }
+            else
+              this._self._resultNode = null;
           }
           return val;
         },
 
-        itemInserted: function PMV_itemInserted(aParentNode, aNode, aIndex) {
-          var popup = this._getPopupForContainer(aParentNode);
-          if (!popup._built)
+        nodeInserted: function PMV_nodeInserted(aParentNode, aNode, aIndex) {
+          let parentElt = aParentNode._DOMElement;
+          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
+
+          if (!parentElt._built)
             return;
 
-          var index = popup._startMarker + 1 + aIndex;
-          var before = popup.childNodes[index] || null;
-          this._self.insertNewItem(aNode, popup, before);
+          // parentElt is the <menu> element for the container,
+          // we need the <menupopup>
+          let popup = parentElt.firstChild;
+
+          let index = popup._startMarker + 1 + aIndex;
+          this._self.insertNewItem(aNode, popup, popup.childNodes[index]);
           if (popup._emptyMenuItem)
             popup._emptyMenuItem.hidden = true;
         },
 
-        itemRemoved: function PMV_itemRemoved(aParentNode, aNode, aIndex) {
-          var popup = this._getPopupForContainer(aParentNode);
-          if (!popup._built)
+        nodeRemoved: function PMV_nodeRemoved(aParentNode, aNode, aIndex) {
+          let parentElt = aParentNode._DOMElement;
+          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
+
+          if (!parentElt._built)
+            return;
+
+          // parentElt is the <menu> element for the container,
+          // we need the <menupopup>
+          let popup = parentElt.firstChild;
+
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+          popup.removeChild(nodeElt);
+
+          // Figure out if we need to show the "<Empty>" menu-item.
+          // TODO Bug 517701: This doesn't seem to handle the case of an empty
+          // root (parentElt == this._self.parentNode).
+          if (!popup.hasChildNodes() ||
+              (popup.childNodes.length == 1 &&
+              popup.firstChild == popup._emptyMenuItem))
+            this._self._showEmptyMenuItem(popup);
+
+          if (popup._endMarker != -1)
+            popup._endMarker--;
+        },
+
+        nodeMoved:
+        function PMV_nodeMoved(aNode,
+                               aOldParent, aOldIndex,
+                               aNewParent, aNewIndex) {
+          // Note: the current implementation of moveItem does not actually
+          // use this notification when the item in question is moved from one
+          // folder to another.  Instead, it calls nodeRemoved and nodeInserted
+          // for the two folders.  Thus, we can assume aOldParent == aNewParent.
+
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          // If our root node is a folder, it might be moved. There's nothing
+          // we need to do in that case.
+          if (nodeElt == this._self.parentNode)
             return;
 
-          var children = popup.childNodes;
-          for (var i = popup._startMarker + 1; i < children.length; i++) {
-            if (children[i].node == aNode) {
-              this._self.removeItem(children[i]);
-              if (!popup.hasChildNodes() ||
-                  (popup.childNodes.length == 1 &&
-                   popup.firstChild == popup._emptyMenuItem)) {
-                this._self._showEmptyMenuItem(popup);
-              }
-              return;
-            }
-          }
+          // Move the node.
+          let popup = nodeElt.parentNode;
+          let index = popup._startMarker + 1 + aNewIndex;
+          popup.removeChild(nodeElt);
+          popup.insertBefore(nodeElt, popup.childNodes[index]);
+        },
+
+        nodeTitleChanged: function PMV__nodeTitleChanged(aNode, aNewTitle) {
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          // There's no UI representation for the root node, thus there's
+          // nothing to be done when the title changes.
+          if (nodeElt == this._self.parentNode)
+            return;
+
+          nodeElt.label = aNewTitle || PlacesUIUtils.getBestTitle(aNode);
+        },
+
+        nodeURIChanged: function PMV_nodeURIChanged(aNode, aURIString) {
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          nodeElt.setAttribute("scheme",
+                               PlacesUIUtils.guessUrlSchemeForUI(aURIString));
         },
 
-        itemMoved:
-        function PMV_itemMoved(aItem, aOldParent, aOldIndex, aNewParent,
-                               aNewIndex) {
-          // This cannot actually happen yet (see IDL)
-          if (aNewParent != aOldParent)
+        nodeIconChanged: function PMV_nodeIconChanged(aNode) {
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          // There's no UI representation for the root node, thus there's
+          // nothing to be done when the icon changes.
+          if (nodeElt == this._self.parentNode)
             return;
 
-          var popup = this._getPopupForContainer(aNewParent);
-          var index = popup._startMarker + 1 + aNewIndex;
-          var children = popup.childNodes;
-          for (var i = popup._startMarker + 1; i < children.length; i++) {
-            var menuItem = children[i];
-            if (menuItem.node == aItem) {
-              popup.removeChild(menuItem);
-              popup.insertBefore(menuItem, children[index]);
-              return;
-            }
+          var icon = aNode.icon;
+          if (icon) {
+            if (nodeElt.getAttribute("image") != icon)
+              nodeElt.setAttribute("image", icon);
+          }
+          else
+            nodeElt.removeAttribute("image");
+        },
+
+        nodeAnnotationChanged:
+        function PMV_nodeAnnotationChanged(aNode, aAnno) {
+          // Ensure the changed annotation is a livemark one.
+          if (/^livemark\//.test(aAnno) &&
+              PlacesUtils.nodeIsLivemarkContainer(aNode)) {
+            let nodeElt = aNode._DOMElement;
+            NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+            if (!nodeElt.hasAttribute("livemark"))
+              nodeElt.setAttribute("livemark", "true");
+
+            // Add or remove the livemark status menuitem.
+            PlacesUIUtils.ensureLivemarkStatusMenuItem(nodeElt.firstChild);
           }
         },
 
-        itemChanged: function PMV_itemChanged(aNode) {
-          // this check can be removed once we fix bug #382397
-          var parentNode = aNode.parent;
-          if (!parentNode)
-            return;
+        nodeHistoryDetailsChanged: function() { },
+        nodeTagsChanged: function() { },
+        nodeDateAddedChanged: function() { },
+        nodeLastModifiedChanged: function() { },
+        nodeKeywordChanged: function() { },
 
-          if (PlacesUtils.nodeIsSeparator(aNode)) {
-            // nothing to do when a separator changes
-            return;
-          }
+        nodeReplaced:
+        function PMV_nodeReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
+          let parentElt = aParentNode._DOMElement;
+          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
 
-          var popup = this._getPopupForContainer(parentNode);
-          if (!popup._built)
+          if (!parentElt._built)
             return;
 
-          var children = popup.childNodes;
-          var menuitem;
-          for (var i = popup._startMarker + 1; i < children.length; i++) {
-            if (children[i].node == aNode) {
-              menuitem = children[i];
-              break;
-            }
-          }
-
-          var iconURI = aNode.icon;
-          if (iconURI) {
-            var spec = iconURI.spec;
-            if (menuitem.getAttribute("image") != spec)
-              menuitem.setAttribute("image", spec);
-          }
-          else
-            menuitem.removeAttribute("image");
-
-          var title = PlacesUIUtils.getBestTitle(aNode);
-          if (menuitem.getAttribute("label") != title)
-            menuitem.setAttribute("label", title);
+          // parentElt is the <menu> element for the container,
+          // we need the <menupopup>.
+          let popup = parentElt.firstChild;
 
-          if (PlacesUtils.nodeIsLivemarkContainer(aNode)) {
-            if (!menuitem.hasAttribute("livemark"))
-              menuitem.setAttribute("livemark", "true");
-            // If this is a livemark container check if the status menuitem has
-            // to be added or removed.
-            PlacesUIUtils.ensureLivemarkStatusMenuItem(menuitem.firstChild);
-          }
-          else if (PlacesUtils.nodeIsURI(aNode)) {
-              menuitem.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(aNode.uri));
-          }
-        },
+          let nodeElt = aOldNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
 
-        itemReplaced:
-        function PMV_itemReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
-          var popup = this._getPopupForContainer(aParentNode);
-          if (!popup._built)
-            return;
-
-          var children = popup.childNodes;
-          for (var i = popup._startMarker + 1; i < children.length; i++) {
-            if (children[i].node == aOldNode) {
-              var next = children[i].nextSibling;
-              this._self.removeItem(children[i]);
-              this._self.insertNewItem(aNewNode, popup, next);
-              return;
-            }
-          }
+          // No worries: If nodeElt is the last item (i.e. no nextSibling),
+          // insertNewItem will insert the new element as the last item.
+          let next = nodeElt.nextSibling;
+          this._self.removeItem(nodeElt);
+          this._self.insertNewItem(aNewNode, popup, next);
         },
 
         containerOpened: function PMV_containerOpened(aNode) {
           this.invalidateContainer(aNode);
         },
 
         containerClosed: function PMV_containerClosed(aNode) {
           this.invalidateContainer(aNode);
         },
- 
+
         invalidateContainer: function PMV_invalidateContainer(aContainer) {
-          if (!this._self._built)
+          // Do nothing if the entire view is already marked un-built.
+          if (!this._self.parentNode._built)
             return;
 
-          function isChildOf(node, container) {
-            var parent = node.parent;
-            while (parent) {
-              if (parent == container)
-                return true;
-              parent = parent.parent;
-            }
-            return false;
-          }
-
-          var popupToRebuild = null;
-          for (var i=0; i < this._self._containerNodesMap.length; i++) {
-            var node = this._self._containerNodesMap[i].resultNode;
+          let containerNodeElt = aContainer._DOMElement;
+          NS_ASSERT(containerNodeElt, "node must have _DOMElement set");
+          containerNodeElt._built = false;
 
-            if (node == aContainer)
-              popupToRebuild = this._self._containerNodesMap[i].domNode;
-            if (isChildOf(node, aContainer)) {
-              this._self._containerNodesMap.splice(i,1);
-              i--;
-            }
-          }
-
-          if (!popupToRebuild)
-            popupToRebuild = this._self;
-          popupToRebuild._built = false;
-
-          // if the menupopup is open we should live-update it
-          if (popupToRebuild.parentNode.open)
-            this._self._rebuild(popupToRebuild);
-        },
-
-        invalidateAll: function PMV_invalidateAll() {
-          this._self._containerNodesMap.splice(0);
-          this._self._built = false;
+          // If the menupopup is open we should live-update it.
+          if (containerNodeElt.open)
+            this._self._rebuild(containerNodeElt.firstChild);
         },
 
         sortingChanged: function PMV_sortingChanged(aSortingMode) {
         }
       })]]></field>
 
       <!-- nsIPlacesView -->
       <property name="place">
@@ -909,16 +899,17 @@
           var queries = { }, options = { };
           PlacesUtils.history.queryStringToQueries(val, queries, { }, options);
           if (!queries.value.length)
             queries.value = [PlacesUtils.history.getNewQuery()];
           var result =
             PlacesUtils.history.executeQueries(queries.value,
                                                queries.value.length,
                                                options.value);
+
           result.viewer = this._viewer;
           return val;
         ]]></setter>
       </property>
 
       <!-- nsIPlacesView -->
       <property name="hasSelection">
         <getter><![CDATA[
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -418,80 +418,62 @@ var PlacesOrganizer = {
       exporter.exportHTMLToFile(fp.file);
     }
   },
 
   /**
    * Populates the restore menu with the dates of the backups available.
    */
   populateRestoreMenu: function PO_populateRestoreMenu() {
-    var restorePopup = document.getElementById("fileRestorePopup");
+    let restorePopup = document.getElementById("fileRestorePopup");
 
-    var dateSvc = Cc["@mozilla.org/intl/scriptabledateformat;1"].
+    let dateSvc = Cc["@mozilla.org/intl/scriptabledateformat;1"].
                   getService(Ci.nsIScriptableDateFormat);
 
-    // remove existing menu items
-    // last item is the restoreFromFile item
+    // Remove existing menu items.  Last item is the restoreFromFile item.
     while (restorePopup.childNodes.length > 1)
       restorePopup.removeChild(restorePopup.firstChild);
 
-    // get list of files
-    var localizedFilename = PlacesUtils.getString("bookmarksArchiveFilename");
-    var localizedFilenamePrefix = localizedFilename.substr(0, localizedFilename.indexOf("-"));
-    var fileList = [];
-    var files = this.bookmarksBackupDir.directoryEntries;
-    while (files.hasMoreElements()) {
-      var f = files.getNext().QueryInterface(Ci.nsIFile);
-      var rx = new RegExp("^(bookmarks|" + localizedFilenamePrefix +
-                          ")-([0-9]{4}-[0-9]{2}-[0-9]{2})\.json$");
-      if (!f.isHidden() && f.leafName.match(rx)) {
-        var date = f.leafName.match(rx)[2].replace(/-/g, "/");
-        var dateObj = new Date(date);
-        fileList.push({date: dateObj, filename: f.leafName});
-      }
-    }
-
-    fileList.sort(function PO_fileList_compare(a, b) {
-      return b.date - a.date;
-    });
-
-    if (fileList.length == 0)
+    let backupFiles = PlacesUtils.backups.entries;
+    if (backupFiles.length == 0)
       return;
 
-    // populate menu
-    for (var i = 0; i < fileList.length; i++) {
-      var m = restorePopup.insertBefore
-        (document.createElement("menuitem"),
-         document.getElementById("restoreFromFile"));
+    // Populate menu with backups.
+    for (let i = 0; i < backupFiles.length; i++) {
+      let backupDate = PlacesUtils.backups.getDateForFile(backupFiles[i]);
+      let m = restorePopup.insertBefore(document.createElement("menuitem"),
+                                        document.getElementById("restoreFromFile"));
       m.setAttribute("label",
                      dateSvc.FormatDate("",
                                         Ci.nsIScriptableDateFormat.dateFormatLong,
-                                        fileList[i].date.getFullYear(),
-                                        fileList[i].date.getMonth() + 1,
-                                        fileList[i].date.getDate()));
-      m.setAttribute("value", fileList[i].filename);
+                                        backupDate.getFullYear(),
+                                        backupDate.getMonth() + 1,
+                                        backupDate.getDate()));
+      m.setAttribute("value", backupFiles[i].leafName);
       m.setAttribute("oncommand",
                      "PlacesOrganizer.onRestoreMenuItemClick(this);");
     }
+
+    // Add the restoreFromFile item.
     restorePopup.insertBefore(document.createElement("menuseparator"),
                               document.getElementById("restoreFromFile"));
   },
 
   /**
    * Called when a menuitem is selected from the restore menu.
    */
   onRestoreMenuItemClick: function PO_onRestoreMenuItemClick(aMenuItem) {
-    var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-                 getService(Ci.nsIProperties);
-    var bookmarksFile = dirSvc.get("ProfD", Ci.nsIFile);
-    bookmarksFile.append("bookmarkbackups");
-    bookmarksFile.append(aMenuItem.getAttribute("value"));
-    if (!bookmarksFile.exists())
-      return;
-    this.restoreBookmarksFromFile(bookmarksFile);
+    let backupName = aMenuItem.getAttribute("value");
+    let backupFiles = PlacesUtils.backups.entries;
+    for (let i = 0; i < backupFiles.length; i++) {
+      if (backupFiles[i].leafName == backupName) {
+        this.restoreBookmarksFromFile(backupFiles[i]);
+        break;
+      }
+    }
   },
 
   /**
    * Called when 'Choose File...' is selected from the restore menu.
    * Prompts for a file and restores bookmarks to those in the file.
    */
   onRestoreBookmarksFromFile: function PO_onRestoreBookmarksFromFile() {
     var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
@@ -524,17 +506,17 @@ var PlacesOrganizer = {
     var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
                   getService(Ci.nsIPromptService);
     if (!prompts.confirm(null,
                          PlacesUIUtils.getString("bookmarksRestoreAlertTitle"),
                          PlacesUIUtils.getString("bookmarksRestoreAlert")))
       return;
 
     try {
-      PlacesUtils.restoreBookmarksFromJSONFile(aFile);
+      PlacesUtils.backups.restoreBookmarksFromJSONFile(aFile);
     }
     catch(ex) {
       this._showErrorAlert(PlacesUIUtils.getString("bookmarksRestoreParseError"));
     }
   },
 
   _showErrorAlert: function PO__showErrorAlert(aMsg) {
     var brandShortName = document.getElementById("brandStrings").
@@ -557,40 +539,20 @@ var PlacesOrganizer = {
     fp.appendFilter(PlacesUIUtils.getString("bookmarksRestoreFilterName"),
                     PlacesUIUtils.getString("bookmarksRestoreFilterExtension"));
 
     var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
                  getService(Ci.nsIProperties);
     var backupsDir = dirSvc.get("Desk", Ci.nsILocalFile);
     fp.displayDirectory = backupsDir;
 
-    fp.defaultString = PlacesUtils.getBackupFilename();
-
-    if (fp.show() != Ci.nsIFilePicker.returnCancel) {
-      PlacesUtils.backupBookmarksToFile(fp.file);
+    fp.defaultString = PlacesUtils.backups.getFilenameForDate();
 
-      // copy new backup to /backups dir (bug 424389)
-      var latestBackup = PlacesUtils.getMostRecentBackup();
-      if (!latestBackup || latestBackup != fp.file) {
-        latestBackup.remove(false);
-        var name = PlacesUtils.getBackupFilename();
-        fp.file.copyTo(this.bookmarksBackupDir, name);
-      }
-    }
-  },
-
-  get bookmarksBackupDir() {
-    delete this.bookmarksBackupDir;
-    var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
-                 getService(Ci.nsIProperties);
-    var bookmarksBackupDir = dirSvc.get("ProfD", Ci.nsIFile);
-    bookmarksBackupDir.append("bookmarkbackups");
-    if (!bookmarksBackupDir.exists())
-      bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0700);
-    return this.bookmarksBackupDir = bookmarksBackupDir;
+    if (fp.show() != Ci.nsIFilePicker.returnCancel)
+      PlacesUtils.backups.saveBookmarksToJSONFile(fp.file);
   },
 
   _paneDisabled: false,
   _setDetailsFieldsDisabledState:
   function PO__setDetailsFieldsDisabledState(aDisabled) {
     if (aDisabled) {
       document.getElementById("paneElementsBroadcaster")
               .setAttribute("disabled", "true");
--- a/browser/components/places/content/toolbar.xml
+++ b/browser/components/places/content/toolbar.xml
@@ -19,30 +19,31 @@
 # Portions created by the Initial Developer are Copyright (C) 2005-2006
 # the Initial Developer. All Rights Reserved.
 #
 # Contributor(s):
 #   Annie Sullivan <annie.sullivan@gmail.com>
 #   Ben Goodger <beng@google.com>
 #   Myk Melez <myk@mozilla.org>
 #   Marco Bonardo <mak77@bonardo.net>
+#   Asaf Romano <mano@mozilla.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
-# ***** END LICENSE BLOCK ***** 
+# ***** END LICENSE BLOCK *****
 
 
 <!DOCTYPE bindings [
 <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd" >
 %browserDTD;
 ]>
 
 <bindings id="placesToolbarBindings"
@@ -94,38 +95,71 @@
       ]]></constructor>
 
       <destructor><![CDATA[
         this._scrollbox.removeEventListener("overflow", this, false);
         this._scrollbox.removeEventListener("underflow", this, false);
         window.removeEventListener("resize", this, false);
 
         if (this._result) {
+          this._resultNode.containerOpen = false;
+          this._resultNode = null;
           this._result.viewer = null;
           this._result = null;
         }
       ]]></destructor>
 
       <property name="controller"
                 readonly="true"
                 onget="return this._controller;"/>
 
       <method name="_init">
         <body><![CDATA[
-        this._controller = new PlacesController(this);
-        this.controllers.appendController(this._controller);
+          // XBL bug is in the middle...
+          // When toolbar customization is opened, this binding is attached
+          // again, as a result of adding the item under the wrapper.  However,
+          // the binding isn't detached from the "original" hbox element due
+          // to bug 83635.
+          //
+          // Then, when the customization dialog is closed, the binding is
+          // attached the third time, as a result of adding our element back to
+          // the toolbar.
+          //
+          // So, We'll just continue using the original binding, which was
+          // never removed, and avoid using the new bindings.  This means that
+          // this workaround will work just until bug 83635 is fixed.
+          //
+          // However, when the binding is "reconstructed", we do need to add
+          // back the event listeners and the places controller.
+          //
+          // Note: we could avoid part of this mess by moving the "Bookmark
+          // Toolbar Items" placeholder out of this binding.
 
-        this._scrollbox.addEventListener("overflow", this, false);
-        this._scrollbox.addEventListener("underflow", this, false);
-        window.addEventListener("resize", this, false);
+          // We also need to avoid initializing _result and _resultNode and
+          // _controller as XBL fields.  Otherwise, they'll be unset when the
+          // "extra" bindings are applied.
+
+          this._scrollbox.addEventListener("overflow", this, false);
+          this._scrollbox.addEventListener("underflow", this, false);
+          window.addEventListener("resize", this, false);
 
-        if (this.hasAttribute("place")) {
-          // Do the initial build.
-          this.place = this.place;
-        }
+          if (this._result === undefined) {
+            this._result = null;
+            this._resultNode = null;
+            if (this.hasAttribute("place")) {
+              // Do the initial build.
+              this.place = this.place;
+            }
+          }
+
+          // Attach the places controller.
+          if (!this._controller) 
+            this._controller = new PlacesController(this);
+
+          this.controllers.appendController(this._controller);
         ]]></body>
       </method>
 
       <field name="_scrollbox">
         document.getAnonymousElementByAttribute(this, "class",
                                                 "bookmarks-toolbar-items")
       </field>
       <field name="_dropIndicator">
@@ -137,139 +171,117 @@
       </field>
       <field name="_chevronPopup">
         document.getAnonymousElementByAttribute(this, "anonid", "chevronPopup")
       </field>
 
       <field name="_openedMenuButton">null</field>
       <field name="_allowPopupShowing">true</field>
 
-      <field name="_result">null</field>
-      <field name="_resultNode">null</field>
-
       <field name="_isRTL">
         document.defaultView.getComputedStyle(this.parentNode, "")
                             .direction == "rtl"
       </field>
 
       <!-- nsIPlacesView -->
       <method name="getResult">
         <body><![CDATA[
           return this._result;
         ]]></body>
       </method>
 
       <!-- nsIPlacesView -->
       <method name="getResultNode">
         <body><![CDATA[
-          return this._result.root;
+          return this._resultNode;
         ]]></body>
       </method>
 
       <method name="_rebuild">
         <body><![CDATA[
           // Clear out references to existing nodes, since they will be removed
           // and re-added.
           if (this._overFolder.node)
             this._clearOverFolder();
           this._openedMenuButton = null;
 
           while (this.hasChildNodes())
             this.removeChild(this.firstChild);
 
-          var rootNode = this._result.root;
-          var cc = rootNode.childCount;
+          let cc = this._resultNode.childCount;
           for (let i = 0; i < cc; ++i)
-            this.insertNewItem(rootNode.getChild(i), null);
+            this.insertNewItem(this._resultNode.getChild(i), null);
 
           if (this._chevronPopup.hasAttribute("type")) {
             // Chevron has already been initialized, but since we are forcing
             // a rebuild of the toolbar, it has to be rebuilt.
             // Otherwise, it will be initialized when the toolbar overflows.
             this._chevronPopup.place = this.place;
           }
-
-          while (chevronPopup.hasChildNodes())
-            this._chevronPopup.removeChild(this._chevronPopup.lastChild);
         ]]></body>
       </method>
 
       <method name="insertNewItem">
         <parameter name="aChild"/>
         <parameter name="aBefore"/>
         <body><![CDATA[
           var type = aChild.type;
           var button;
           if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR)
             button = document.createElement("toolbarseparator");
           else {
             button = document.createElement("toolbarbutton");
             button.className = "bookmark-item";
             button.setAttribute("label", aChild.title);
-            var iconURI = aChild.icon;
-            var iconURISpec = "";
-            if (iconURI) {
-              iconURISpec = iconURI.spec;
-              button.setAttribute("image", iconURISpec);
-            }
+            var icon = aChild.icon;
+            if (icon)
+              button.setAttribute("image", icon);
 
             if (PlacesUtils.containerTypes.indexOf(type) != -1) {
               button.setAttribute("type", "menu");
               button.setAttribute("container", "true");
 
               if (PlacesUtils.nodeIsQuery(aChild)) {
                 button.setAttribute("query", "true");
                 if (PlacesUtils.nodeIsTagQuery(aChild))
                   button.setAttribute("tagContainer", "true");
               }
               else if (PlacesUtils.nodeIsLivemarkContainer(aChild))
                 button.setAttribute("livemark", "true");
 
               var popup = document.createElement("menupopup");
               popup.setAttribute("placespopup", "true");
               button.appendChild(popup);
-              popup._result = this._result;
               popup._resultNode = asContainer(aChild);
 #ifndef XP_MACOSX
               popup.setAttribute("context", "placesContext");
 #endif
-              this._containerNodesMap.push({ resultNode: aChild,
-                                             domNode: popup });
             }
-            else if (PlacesUtils.nodeIsURI(aChild)) {
+            else if (PlacesUtils.nodeIsURI(aChild))
               button.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(aChild.uri));
-            }
           }
 
           button.node = aChild;
-          button.node.viewIndex = 0;
+          aChild._DOMElement = button;
           if (aBefore)
             this.insertBefore(button, aBefore);
           else
             this.appendChild(button);
         ]]></body>
       </method>
 
       <method name="removeItem">
         <parameter name="child"/>
         <body><![CDATA[
-          if (PlacesUtils.nodeIsContainer(child.node)) {
-            for (let i = 0; i < this._containerNodesMap.length; i++) {
-              if (this._containerNodesMap[i].resultNode == child.node) {
-                this._containerNodesMap.splice(i, 1);
-                break;
-              }
-            }
-          }
-
           // if document.popupNode pointed to this child, null it out,
           // otherwise controller's command-updating may rely on the removed
           // item still being "selected".
           if (document.popupNode == child)
             document.popupNode = null;
+
           child.parentNode.removeChild(child);
         ]]></body>
       </method>
 
       <method name="_updateChevronPopupNodesVisibility">
         <body><![CDATA[
           for (let i = 0; i < this._chevronPopup.childNodes.length; i++) {
             this._chevronPopup.childNodes[i].hidden =
@@ -373,41 +385,41 @@
         ]]></body>
       </method>
 
       <!-- nsIPlacesView -->
       <property name="place">
         <getter><![CDATA[
           return this.getAttribute("place");
         ]]></getter>
-        <setter><![CDATA[ 
+        <setter><![CDATA[
           this.setAttribute("place", val);
 
           var history = PlacesUtils.history;
           var queries = { }, options = { };
           history.queryStringToQueries(val, queries, { }, options);
-          if (!queries.value.length) 
+          if (!queries.value.length)
             queries.value = [history.getNewQuery()];
           try {
             var result =
               history.executeQueries(queries.value, queries.value.length,
                                      options.value);
             result.viewer = this._viewer;
           }
           catch(ex) {
             // Invalid query, or had no results.
-            // This is valid, eg: user deletes their bookmarks toolbar folder. 
+            // This is valid, eg: user deletes his bookmarks toolbar folder.
           }
           return val;
         ]]></setter>
       </property>
 
       <!-- nsIPlacesView -->
       <property name="hasSelection">
-        <getter><![CDATA[ 
+        <getter><![CDATA[
           return this.selectedNode != null;
         ]]></getter>
       </property>
 
       <!-- nsIPlacesView -->
       <method name="getSelectionNodes">
         <body><![CDATA[
           var selectedNode = this.selectedNode;
@@ -448,19 +460,19 @@
           }
           return null;
         ]]></getter>
       </property>
 
       <!-- nsIPlacesView -->
       <property name="insertionPoint">
         <getter><![CDATA[
-          // By default, the insertion point is at the top level, at the end. 
+          // By default, the insertion point is at the top level, at the end.
           var index = PlacesUtils.bookmarks.DEFAULT_INDEX;
-          var container = this._result.root;
+          var container = this._resultNode;
           var orientation = Ci.nsITreeView.DROP_BEFORE;
           var isTag = false;
 
           var selectedNode = this.selectedNode;
           if (selectedNode) {
             var popupNode = document.popupNode;
             if (!popupNode.node) {
               // If a static menuitem is selected the insertion point
@@ -481,293 +493,274 @@
 
           return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
                                     index, orientation, isTag);
         ]]></getter>
       </property>
 
       <!-- nsIPlacesView -->
       <method name="selectAll">
-        <body><![CDATA[ 
+        <body><![CDATA[
           // Nothing
         ]]></body>
       </method>
 
       <method name="selectItems">
         <body><![CDATA[
           // Nothing
         ]]></body>
       </method>
 
       <!-- nsINavHistoryResultViewer -->
       <field name="_viewer"><![CDATA[({
         _self: this,
 
-        _getPopupForContainer:
-        function PMV__getPopupForContainer(aNode) {
-          if (this._self._resultNode == aNode)
-            return this._self;
-
-          for (let i = 0; i < this._self._containerNodesMap.length; i++) {
-            if (this._self._containerNodesMap[i].resultNode == aNode)
-              return this._self._containerNodesMap[i].domNode;
-          }
-          throw("Container view not found");
-        },
-
         get result() {
           return this._self._result;
         },
 
         set result(val) {
           // some methods (e.g. getURLsFromContainer) temporarily null out the
           // viewer when they do temporary changes to the view, this does _not_
           // call setResult(null), but then, we're called again with the result
           // object which is already set for this viewer. At that point,
           // we should do nothing.
           if (this._self._result != val) {
             if (this._self._result)
-              this._self._result.root.containerOpen = false;
-            this._self._containerNodesMap = [];
+              this._self._resultNode.containerOpen = false;
+
             this._self._result = val;
-            if (val) // this calls _rebuild through invalidateContainer
-              val.root.containerOpen = true;
+            if (val) {
+              this._self._resultNode = val.root;
+              this._self._resultNode._DOMElement = this._self;
+              // This calls _rebuild through invalidateContainer.
+              this._self._resultNode.containerOpen = true;
+            }
+            else
+              this._self._resultNode = null;
           }
           return val;
         },
 
-        itemInserted: function TV_V_itemInserted(aParentNode, aNode, aIndex) {
-          // don't insert new items into the toolbar
-          // if the parent is not the root 
-          if (aParentNode == this._self.getResultNode()) {
-            var children = this._self.childNodes;
+        nodeInserted: function TV_V_nodeInserted(aParentNode, aNode, aIndex) {
+          let parentElt = aParentNode._DOMElement;
+          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
+
+          if (parentElt == this._self) {
+            // Node is on the toolbar.
+            let children = this._self.childNodes;
             this._self.insertNewItem(aNode,
               aIndex < children.length ? children[aIndex] : null);
             this._self.updateChevron();
           }
-          else {
-            var popup = this._getPopupForContainer(aParentNode);
-            if (!popup._built)
-              return;
-
-            var before = popup.childNodes[aIndex] || null;
+          else if (parentElt._built) {
+            // Node is within a built menu.
+            let popup = parentElt.firstChild;
+            let before = popup.childNodes[aIndex] || null;
             this._self.insertNewItemToPopup(aNode, popup, before);
             if (popup._emptyMenuItem)
               popup._emptyMenuItem.hidden = true;
           }
         },
 
-        itemRemoved: function TV_V_itemRemoved(aParentNode, aNode, aIndex) {
-          if (aParentNode == this._self.getResultNode()) {
-            var children = this._self.childNodes;
-            for (let i = 0; i < children.length; i++) {
-              if (children[i].node == aNode) {
-                this._self.removeItem(children[i]);
-                this._self.updateChevron();
-                return;
-              }
-            }
+        nodeRemoved: function TV_V_nodeRemoved(aParentNode, aNode, aIndex) {
+          let parentElt = aParentNode._DOMElement;
+          let nodeElt = aNode._DOMElement;
+
+          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          if (parentElt == this._self) {
+            // Node is on the toolbar.
+            this._self.removeChild(nodeElt);
+            this._self.updateChevron();
           }
-          else {
-            var popup = this._getPopupForContainer(aParentNode);
-            if (!popup._built)
-              return;
+          else if (parentElt._built) {
+            // Node is within a built menu.
+            var popup = parentElt.firstChild;
+            popup.removeChild(nodeElt);
+            if (!popup.hasChildNodes() ||
+                (popup.childNodes.length == 1 &&
+                popup.firstChild == popup._emptyMenuItem))
+              this._self._showEmptyMenuItem(popup);
 
-            var children = popup.childNodes;
-            for (let i = popup._startMarker + 1; i < children.length; i++) {
-              if (children[i].node == aNode) {
-                this._self.removeItem(children[i]);
-                if (!popup.hasChildNodes() ||
-                    (popup.childNodes.length == 1 &&
-                     popup.firstChild == popup._emptyMenuItem)) {
-                  this._self._showEmptyMenuItem(popup);
-                }
-                if (popup._endMarker != -1)
-                  popup._endMarker--;
-                return;
-              }
-            }
+            if (popup._endMarker != -1)
+              popup._endMarker--;
           }
         },
 
-        itemMoved:
-        function TV_V_itemMoved(aItem, aOldParent, aOldIndex, aNewParent,
-                                aNewIndex) {
-          // This cannot actually happen yet (see IDL)
-          if (aNewParent != aOldParent)
+        nodeMoved:
+        function TV_V_nodeMoved(aNode,
+                                aOldParent, aOldIndex,
+                                aNewParent, aNewIndex) {
+          // Note: the current implementation of moveItem does not actually
+          // use this notification when the item in question is moved from one
+          // folder to another.  Instead, it calls nodeRemoved and nodeInserted
+          // for the two folders.  Thus, we can assume aOldParent == aNewParent.
+
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          // If our root node is a folder, it might be moved. There's nothing
+          // we need to do in that case.
+          if (nodeElt == this._self)
             return;
 
-          if (aNewParent == this._self.getResultNode()) {
-            var children = this._self.childNodes;
-            for (let i = 0; i < children.length; i++) {
-              var button = children[i];
-              if (button.node == aItem) {
-                this._self.removeChild(button);
-                this._self.insertBefore(button, children[aNewIndex]);
-                // If the chevron popup is open, keep it in sync.
-                if (this._self._chevron.open) {
-                  var chevronPopup = this._self._chevronPopup;
-                  var menuitem = chevronPopup.childNodes[i];
-                  chevronPopup.removeChild(menuitem);
-                  chevronPopup.insertBefore(menuitem,
-                                            chevronPopup.childNodes[aNewIndex]);
-                }
-                this._self.updateChevron();
-                return;
-              }
+          let parentElt = aNewParent._DOMElement;
+          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
+
+          if (parentElt == this._self) {
+            // Container is on the toolbar.
+
+            // Move the node.
+            this._self.removeChild(nodeElt);
+            this._self.insertBefore(nodeElt, this._self.childNodes[aNewIndex]);
+
+            // If the chevron popup is open, keep it in sync.
+            if (this._self._chevron.open) {
+              let chevronPopup = this._self._chevronPopup;
+              let menuitem = chevronPopup.childNodes[aOldIndex];
+              chevronPopup.removeChild(menuitem);
+              chevronPopup.insertBefore(menuitem,
+                                        chevronPopup.childNodes[aNewIndex]);
             }
+            this._self.updateChevron();
+          }
+          else if (parentElt._built) {
+            // Container is within a built menu.
+
+            // parentElt is the <menu> element for the container,
+            // we need the <menupopup>.
+            var popup = parentElt.firstChild;
+
+            // Move the node.
+            popup.removeChild(nodeElt);
+            popup.insertBefore(nodeElt, popup.childNodes[aNewIndex]);
+          }
+        },
+
+        nodeTitleChanged: function TV_V_nodeTitleChanged(aNode, aNewTitle) {
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          // There's no UI representation for the root node, thus there's
+          // nothing to be done when the title changes.
+          if (nodeElt == this._self)
+            return;
+
+          if (nodeElt.parentNode == this._self) {
+            // Node is on the toolbar
+            nodeElt.label = aNewTitle;
+            this._self.updateChevron();
           }
           else {
-            var popup = this._getPopupForContainer(aNewParent);
-            var children = popup.childNodes;
-            for (let i = popup._startMarker + 1; i < children.length; i++) {
-              var menuItem = children[i];
-              if (menuItem.node == aItem) {
-                popup.removeChild(menuItem);
-                popup.insertBefore(menuItem, children[aNewIndex]);
-                return;
-              }
-            }
+            // Node is within a built menu.
+            nodeElt.label = aNewTitle || PlacesUIUtils.getBestTitle(aNode);
           }
         },
 
-        itemChanged: function TV_V_itemChanged(aNode) {
-          // this check can be removed once we fix bug #382397
-          var parentNode = aNode.parent;
-          if (!parentNode)
+        nodeURIChanged: function TV_V_nodeURIChanged(aNode, aURIString) {
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          nodeElt.setAttribute("scheme",
+                               PlacesUIUtils.guessUrlSchemeForUI(aURIString));
+        },
+
+        nodeIconChanged: function TV_V_nodeIconChanged(aNode) {
+          let nodeElt = aNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          // There's no UI representation for the root node, thus there's
+          // nothing to be done when the icon changes.
+          if (nodeElt == this._self)
             return;
 
-          if (PlacesUtils.nodeIsSeparator(aNode)) {
-            // nothing to do when a separator changes
-            return;
-          }
-
-          var element;
-          var onToolbar = false;
-          if (parentNode == this._self.getResultNode()) {
-            onToolbar = true;
-            var children = this._self.childNodes;
-            for (let i = 0; i < children.length; i++) {
-              if (children[i].node == aNode) {
-                element = children[i];
-                break;
-              }
-            }
-            // Don't replace title on toolbarbuttons
-            var title = aNode.title;
-          }
-          else {
-            var popup = this._getPopupForContainer(parentNode);
-            if (!popup._built)
-              return;
-
-            var children = popup.childNodes;
-            for (let i = popup._startMarker + 1; i < children.length; i++) {
-              if (children[i].node == aNode) {
-                element = children[i];
-                break;
-              }
-            }
-            var title = PlacesUIUtils.getBestTitle(aNode);
-          }
-
-          var iconURI = aNode.icon;
-          if (iconURI) {
-            var spec = iconURI.spec;
-            if (element.getAttribute("image") != spec)
-              element.setAttribute("image", spec);
+          let icon = aNode.icon;
+          if (icon) {
+            if (nodeElt.getAttribute("image") != icon)
+              nodeElt.setAttribute("image", icon);
           }
           else
-            element.removeAttribute("image");
-
-          if (element.getAttribute("label") != title) {
-            element.setAttribute("label", title);
-            if (onToolbar)
-              this._self.updateChevron();
-          }
+            nodeElt.removeAttribute("image");
+        },
 
-          if (PlacesUtils.nodeIsLivemarkContainer(aNode)) {
-            if (!element.hasAttribute("livemark"))
-              element.setAttribute("livemark", "true");
-            // If this is a livemark container check if the status menuitem has
-            // to be added or removed.
-            PlacesUIUtils.ensureLivemarkStatusMenuItem(element.firstChild);
-          }
-          else if (PlacesUtils.nodeIsURI(aNode)) {
-            element.setAttribute("scheme", PlacesUIUtils.guessUrlSchemeForUI(aNode.uri));
+        nodeAnnotationChanged:
+        function TV_V_nodeAnnotationChanged(aNode, aAnno) {
+          // Ensure the changed annotation is a livemark one.
+          if (/^livemark\//.test(aAnno) &&
+              PlacesUtils.nodeIsLivemarkContainer(aNode)) {
+            let nodeElt = aNode._DOMElement;
+            NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+            if (!nodeElt.hasAttribute("livemark"))
+              nodeElt.setAttribute("livemark", "true");
+
+            // Add or remove the livemark status menuitem.
+            PlacesUIUtils.ensureLivemarkStatusMenuItem(nodeElt.firstChild);
           }
         },
 
-        itemReplaced:
-        function TV_V_itemReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
-          if (aParentNode == this._self.getResultNode()) {
-            var children = this._self.childNodes;
-            for (let i = 0; i < children.length; i++) {
-              if (children[i].node == aOldNode) {
-                var next = children[i].nextSibling;
-                this._self.removeItem(children[i]);
-                this._self.insertNewItem(aNewNode, next);
-                this._self.updateChevron();
-                return;
-              }
-            }
+        nodeHistoryDetailsChanged: function() { },
+        nodeTagsChanged: function() { },
+        nodeDateAddedChanged: function() { },
+        nodeLastModifiedChanged: function() { },
+        nodeKeywordChanged: function() { },
+
+        nodeReplaced:
+        function TV_V_nodeReplaced(aParentNode, aOldNode, aNewNode, aIndex) {
+          let nodeElt = aOldNode._DOMElement;
+          NS_ASSERT(nodeElt, "node must have _DOMElement set");
+
+          // No worries: If nodeElt is the last item (i.e. no nextSibling),
+          // insertNewItem/insertNewItemToPopup will insert the new element as
+          // the last item.
+          let next = nodeElt.nextSibling;
+
+          let parentElt = aParentNode._DOMElement;
+          NS_ASSERT(parentElt, "parent node must have _DOMElement set");
+          if (parentElt == this._self) {
+            // Node is on the toolbar.
+            this._self.removeItem(nodeElt);
+            this._self.insertNewItem(aNewNode, next);
+            this._self.updateChevron();
+          }
+          else if (parentElt._built) {
+            // Node is within a built menu.
+            let popup = parentElt.firstChild;
+            popup.removeItem(nodeElt);
+            this._self.insertNewItemToPopup(aNewNode, popup, next);
           }
         },
 
-        containerOpened: function TV_V_containerOpened(aNode) {
-          this.invalidateContainer(aNode);
+        containerOpened: function TV_V_containerOpened(aContainer) {
+          this.invalidateContainer(aContainer);
         },
 
-        containerClosed: function TV_V_containerClosed(aNode) {
-          this.invalidateContainer(aNode);
+        containerClosed: function TV_V_containerClosed(aContainer) {
+          this.invalidateContainer(aContainer);
         },
 
         invalidateContainer: function TV_V_invalidateContainer(aContainer) {
-          if (aContainer == this._self.getResultNode()) {
-            this._self._containerNodesMap.splice(0);
-            this._self._rebuild();
-            return;
-          }
-
-          function isChildOf(node, container) {
-            var parent = node.parent;
-            while (parent) {
-              if (parent == container)
-                return true;
-              parent = parent.parent;
-            }
-            return false;
-          }
+          let containerNodeElt = aContainer._DOMElement;
+          NS_ASSERT(containerNodeElt, "node must have _DOMElement set");
 
-          var popupToRebuild = null;
-          for (let i = 0; i < this._self._containerNodesMap.length; i++) {
-            var node = this._self._containerNodesMap[i].resultNode;
-            
-            if (node == aContainer)
-              popupToRebuild = this._self._containerNodesMap[i].domNode;
-            if (isChildOf(node, aContainer)) {
-              this._self._containerNodesMap.splice(i,1);
-              i--;
-            }
+          if (containerNodeElt == this._self) {
+            // Container is the toolbar itself.
+            this._self._rebuild();
           }
-
-          if (popupToRebuild) {
-            popupToRebuild._built = false;
-
-            // if the menupopup is open we should live-update it
-            if (popupToRebuild.parentNode.open)
-              this._self._rebuildPopup(popupToRebuild);
+          else if (containerNodeElt._built) {
+            // Container is a built menu.
+            containerNodeElt._built = false;
+            // If the menupopup is open we should live-update it.
+            if (containerNodeElt.open)
+              this._self._rebuildPopup(containerNodeElt.firstChild);
           }
         },
 
-        invalidateAll: function TV_V_invalidateAll() {
-          this._self._containerNodesMap.splice(0);
-          this._self._rebuild();
-        },
-
         sortingChanged: function TV_V_sortingChanged(aSortingMode) {
         }
       })]]></field>
 
       <property name="selType" onget="return 'single';"/>
 
       <method name="buildContextMenu">
         <parameter name="aPopup"/>
@@ -803,18 +796,17 @@
         ]]></body>
       </method>
 
       <method name="insertNewItemToPopup">
         <parameter name="aChild"/>
         <parameter name="aParentPopup"/>
         <parameter name="aBefore"/>
         <body><![CDATA[
-          var element =
-            PlacesUIUtils.createMenuItemForNode(aChild, this._containerNodesMap);
+          var element = PlacesUIUtils.createMenuItemForNode(aChild);
 
           if (aBefore)
             aParentPopup.insertBefore(element, aBefore);
           else {
             // Add the new element to the menu.  If there is static content at
             // the end of the menu, add the element before that.  Otherwise,
             // just add to the end.
             if (aParentPopup._endMarker != -1) {
@@ -828,17 +820,17 @@
           if (aParentPopup._endMarker != -1)
             aParentPopup._endMarker++;
         ]]></body>
       </method>
 
       <method name="_containerPopupShowing">
         <parameter name="aPopup"/>
         <body><![CDATA[
-          if (!aPopup._built)
+          if (!aPopup.parentNode._built)
             this._rebuildPopup(aPopup);
         ]]></body>
       </method>
 
       <method name="_rebuildPopup">
         <parameter name="aPopup"/>
         <body><![CDATA[
           PlacesUIUtils.cleanPlacesPopup(aPopup);
@@ -863,17 +855,17 @@
             }
           }
           else {
             // This menu is empty.  If there is no static content, add
             // an element to show it is empty.
             if (aPopup._startMarker == -1 && aPopup._endMarker == -1)
               this._showEmptyMenuItem(aPopup);
           }
-          aPopup._built = true;
+          aPopup.parentNode._built = true;
         ]]></body>
       </method>
 
       <field name="_overFolder"><![CDATA[
        (
          // Menu buttons should be opened when the mouse drags over them, and
          // closed when the mouse drags off. This object manages opening and
          // closing of folders when the mouse hovers.
@@ -909,17 +901,17 @@
         <body><![CDATA[
           // This function returns information about where to drop when
           // dragging over the toolbar.
           // The returned object has 3 properties:
           // - ip: the insertion point for the bookmarks service.
           // - beforeIndex: child index to drop before, for the drop indicator.
           // - folderNode: the folder to drop into, if applicable.
           var result = this.getResult();
-          if (!PlacesUtils.nodeIsFolder(result.root))
+          if (!PlacesUtils.nodeIsFolder(this._resultNode))
             return null;
 
           var dropPoint = { ip: null, beforeIndex: null, folderNode: null };
           var xulNode = aEvent.target;
           if (xulNode.node) {
             let nodeRect = xulNode.getBoundingClientRect();
             let nodeIndex = Array.indexOf(this.childNodes, xulNode);
             if (PlacesUtils.nodeIsFolder(xulNode.node) &&
@@ -927,17 +919,17 @@
               // This is a folder.
               // If we are in the middle of it, drop inside it.
               // Otherwise, drop before it, with regards to RTL mode.
               let threshold = nodeRect.width * 0.25;
               if (this._isRTL ? (aEvent.clientX > nodeRect.right - threshold)
                               : (aEvent.clientX < nodeRect.left + threshold)) {
                 // Drop before this folder.
                 dropPoint.ip =
-                  new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
+                  new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
                                      nodeIndex, Ci.nsITreeView.DROP_BEFORE);
                 dropPoint.beforeIndex = nodeIndex;
               }
               else if (this._isRTL ? (aEvent.clientX > nodeRect.left + threshold)
                                    : (aEvent.clientX < nodeRect.right - threshold)) {
                 // Drop inside this folder.
                 dropPoint.ip =
                   new InsertionPoint(PlacesUtils.getConcreteItemId(xulNode.node),
@@ -946,49 +938,49 @@
                 dropPoint.beforeIndex = nodeIndex;
                 dropPoint.folderNode = xulNode;
               }
               else {
                 // Drop after this folder.
                 let beforeIndex =
                   (nodeIndex == this.childNodes.length - 1) ? -1 : nodeIndex + 1;
                 dropPoint.ip =
-                  new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
+                  new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
                                      beforeIndex, Ci.nsITreeView.DROP_BEFORE);
                 dropPoint.beforeIndex = beforeIndex;
               }
             }
             else {
               // This is a non-folder node or a read-only folder.
               // Drop before it with regards to RTL mode.
               let threshold = nodeRect.width * 0.5;
               if (this._isRTL ? (aEvent.clientX > nodeRect.left + threshold)
                               : (aEvent.clientX < nodeRect.left + threshold)) {
                 // Drop before this bookmark.
                 dropPoint.ip =
-	                new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
+	                new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
 	                                   nodeIndex, Ci.nsITreeView.DROP_BEFORE);
                 dropPoint.beforeIndex = nodeIndex;
               }
               else {
                 // Drop after this bookmark.
                 let beforeIndex =
                   nodeIndex == this.childNodes.length - 1 ? -1 : nodeIndex + 1;
                 dropPoint.ip =
-                  new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
+                  new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
                                      beforeIndex, Ci.nsITreeView.DROP_BEFORE);
                 dropPoint.beforeIndex = beforeIndex;
               }
             }
           }
           else {
             // We are most likely dragging on the empty area of the
             // toolbar, we should drop after the last node.
             dropPoint.ip =
-              new InsertionPoint(PlacesUtils.getConcreteItemId(result.root),
+              new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
                                  -1, Ci.nsITreeView.DROP_BEFORE);
             dropPoint.beforeIndex = -1;
           }
 
           return dropPoint;
         ]]></body>
       </method>
 
@@ -1211,17 +1203,17 @@
         if (this._overFolder.node)
             this._overFolder.closeTimer = this._setTimer(this._overFolder.hoverTime);
       ]]></handler>
 
       <handler event="dragend"><![CDATA[
         this._draggedNode = null;
       ]]></handler>
 
-      <handler event="popupshowing" phase="capturing"><![CDATA[      
+      <handler event="popupshowing" phase="capturing"><![CDATA[
         if (!this._allowPopupShowing) {
           this._allowPopupShowing = true;
           event.preventDefault();
           return;
         }
 
         var popup = event.originalTarget;
 
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -131,42 +131,27 @@
                                                   options);
           var callback;
           if (this.flatList) {
             var onOpenFlatContainer = this.onOpenFlatContainer;
             if (onOpenFlatContainer)
               callback = new Function("aContainer", onOpenFlatContainer);
           }
 
-          var treeView = new PlacesTreeView(this.showRoot, this.flatList, callback);
+          var treeView = new PlacesTreeView(this.flatList, callback);
           result.viewer = treeView;
           this.view = treeView;
           if (!this._controller) {
             this._controller = new PlacesController(this);
             this.controllers.appendController(this._controller);
           }
           this._cachedInsertionPoint = undefined;
         ]]></body>
       </method>
 
-      <property name="showRoot">
-        <getter><![CDATA[
-          return this.getAttribute("showRoot") == "true";
-        ]]></getter>
-        <setter><![CDATA[
-          if (this.showRoot != val) {
-            this.setAttribute("showRoot", val);
-            // reload with the last place set
-            if (this.place)
-              this.place = this.place;
-          }
-          return val;
-        ]]></setter>
-      </property>
-
       <property name="flatList">
         <getter><![CDATA[
           return this.getAttribute("flatList") == "true";
         ]]></getter>
         <setter><![CDATA[
           if (this.flatList != val) {
             this.setAttribute("flatList", val);
             // reload with the last place set
@@ -254,17 +239,17 @@
       <!-- 
         Causes a particular node to be selected in the tree, resulting in all 
         containers above the node in the hierarchy to be opened, so that the
         node is visible. 
         -->
       <method name="selectNode">
         <parameter name="node"/>
         <body><![CDATA[ 
-          var view = this.getResultView();
+          var view = this.view;
 
           var parent = node.parent;
           if (parent && !parent.containerOpen) {
             // Build a list of all of the nodes that are the parent of this one 
             // in the result. 
             var parents = [];
             var root = this.getResultNode();
             while (parent && parent != root) {
@@ -303,27 +288,16 @@
 
       <!-- nsIPlacesView -->
       <method name="getResultNode">
         <body><![CDATA[
           return this.getResult().root;
         ]]></body>
       </method>
 
-      <method name="getResultView">
-        <body><![CDATA[
-          try {
-            return this.view.QueryInterface(Ci.nsINavHistoryResultTreeViewer);
-          }
-          catch (e) {
-          }
-          return null;
-        ]]></body>
-      </method>
-
       <!-- nsIPlacesView -->
       <property name="place">
         <getter><![CDATA[
           return this.getAttribute("place");
         ]]></getter>
         <setter><![CDATA[
           this.setAttribute("place", val);
 
@@ -350,17 +324,17 @@
       </property>
       
       <!-- nsIPlacesView -->
       <method name="getSelectionNodes">
         <body><![CDATA[ 
           var selection = this.view.selection;
           var rc = selection.getRangeCount();
           var nodes = [];
-          var resultview = this.getResultView();
+          var resultview = this.view;
           for (var i = 0; i < rc; ++i) {
             var min = { }, max = { };
             selection.getRangeAt(i, min, max);
 
             for (var j = min.value; j <= max.value; ++j)
               nodes.push(resultview.nodeForTreeIndex(j));
           }
           return nodes;
@@ -391,17 +365,17 @@
           // ... returning http://www.bar.com/ as part of the selection is 
           // redundant because it is implied by removing "Some Folder". We 
           // filter out all such redundancies since some partial amount of
           // the folder's children may be selected.          
           //
           var selection = this.view.selection;
           var rc = selection.getRangeCount();
           var nodes = [];
-          var resultview = this.getResultView();
+          var resultview = this.view;
           // This list is kept independently of the range selected (i.e. OUTSIDE
           // the for loop) since the row index of a container is unique for the
           // entire view, and we could have some really wacky selection and we
           // don't want to blow up.
           var containers = { };
           for (var i = 0; i < rc; ++i) {
             var range = [];
             var min = { }, max = { };
@@ -432,17 +406,17 @@
           var view = this.view;
           if (view.selection.count != 1)
             return null;
 
           var selection = view.selection;
           var min = { }, max = { };
           selection.getRangeAt(0, min, max);
 
-          return this.getResultView().nodeForTreeIndex(min.value);
+          return this.view.nodeForTreeIndex(min.value);
         ]]></getter>
       </property>
 
       <!-- nsIPlacesView -->
       <property name="insertionPoint">
         <getter><![CDATA[
           // invalidated on selection and focus changes
           if (this._cachedInsertionPoint !== undefined)
@@ -473,17 +447,17 @@
           //
           // Warning: It may be tempting to use tree indexes in this code, but
           //          you must not, since the tree is nested and as your tree 
           //          index may change when folders before you are opened and
           //          closed. You must convert your tree index to a node, and
           //          then use getIndexOfNode to find your absolute index in
           //          the parent container instead. 
           //
-          var resultView = this.getResultView();
+          var resultView = this.view;
           var selection = resultView.selection;
           var rc = selection.getRangeCount();
           var min = { }, max = { };
           selection.getRangeAt(rc - 1, min, max);
           
           // If the sole selection is a container, and we are not in
           // a flatlist, insert into it.
           // Note that this only applies to _single_ selections,
@@ -504,17 +478,17 @@
         ]]></getter>
       </property>
 
       <method name="_getInsertionPoint">
         <parameter name="index"/>
         <parameter name="orientation"/>
         <body><![CDATA[ 
           var result = this.getResult();
-          var resultview = this.getResultView();
+          var resultview = this.view;
           var container = result.root;
           var dropNearItemId = -1;
           NS_ASSERT(container, "null container");
           // When there's no selection, assume the container is the container
           // the view is populated from (i.e. the result's itemId).
           if (index != -1) {
             var lastSelected = resultview.nodeForTreeIndex(index);
             if (resultview.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
@@ -668,17 +642,17 @@
           var result = this.getResult();
           var oldViewer = result.viewer;
           result.viewer = null;
           findNodes(this.getResultNode());
           result.viewer = oldViewer;
 
           // For all the nodes we've found, highlight the corresponding
           // index in the tree.
-          var resultview = this.getResultView();
+          var resultview = this.view;
           var selection = this.view.selection;
           selection.selectEventsSuppressed = true;
           selection.clearSelection();
           // Open nodes containing found items
           for (var i = 0; i < nodesToOpen.length; i++) {
             nodesToOpen[i].containerOpen = true;
           }
           for (var i = 0; i < nodes.length; i++) {
@@ -724,17 +698,17 @@
         <body><![CDATA[
           // Cache the dataTransfer for the view
           PlacesControllerDragHelper.currentDataTransfer = aEvent.dataTransfer;
 
           var row = { }, col = { }, child = { };
           this.treeBoxObject.getCellAt(aEvent.clientX, aEvent.clientY,
                                        row, col, child);
           var node = row.value != -1 ?
-                     this.getResultView().nodeForTreeIndex(row.value) :
+                     this.view.nodeForTreeIndex(row.value) :
                      this.getResultNode();
           // cache the dropTarget for the view
           PlacesControllerDragHelper.currentDropTarget = node;
 
           // We have to calculate the orientation since view.canDrop will use
           // it and we want to be consistent with the dropfeedback
           var tbo = this.treeBoxObject;
           var rowHeight = tbo.rowHeight;
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -72,119 +72,45 @@ PlacesTreeView.prototype = {
         aIID.equals(Ci.nsINavHistoryResultTreeViewer) ||
         aIID.equals(Ci.nsISupports))
       return this;
 
     throw Cr.NS_ERROR_NO_INTERFACE;
   },
 
   /**
-   * This is called when the result or tree may have changed.
-   * It reinitializes everything. Result and/or tree can be null
-   * when calling.
+   * This is called once both the result and the tree are set.
    */
   _finishInit: function PTV__finishInit() {
-    if (this._tree && this._result)
-      this.sortingChanged(this._result.sortingMode);
-
-    var qoInt = Ci.nsINavHistoryQueryOptions;
-    var options = asQuery(this._result.root).queryOptions;
-
-    // if there is no tree, BuildVisibleList will clear everything for us
-    this._buildVisibleList();
-  },
-
-  _computeShowSessions: function PTV__computeShowSessions() {
-    NS_ASSERT(this._result, "Must have a result to show sessions!");
-    this._showSessions = false;
-
-    var options = asQuery(this._result.root).queryOptions;
-    NS_ASSERT(options, "navHistoryResults must have valid options");
-
-    if (!options.showSessions)
-      return; // sessions are off
-
-    var resultType = options.resultType;
-    if (resultType != Ci.nsINavHistoryQueryOptions.RESULTS_AS_VISIT &&
-        resultType != Ci.nsINavHistoryQueryOptions.RESULTS_AS_FULL_VISIT)
-      return; // not visits
-
-    var sortType = this._result.sortingMode;
-    if (sortType != nsINavHistoryQueryOptions::SORT_BY_DATE_ASCENDING &&
-        sortType != nsINavHistoryQueryOptions::SORT_BY_DATE_DESCENDING)
-      return; // not date sorting
-
-    this._showSessions = true;
-  },
-
-  SESSION_STATUS_NONE: 0,
-  SESSION_STATUS_START: 1,
-  SESSION_STATUS_CONTINUE: 2,
-  _getRowSessionStatus: function PTV__getRowSessionStatus(aRow) {
-    var node = this._visibleElements[aRow].node;
-    if (!PlacesUtils.nodeIsVisit(node) || asVisit(node).sessionId == 0)
-      return this.SESSION_STATUS_NONE;
-
-    if (aRow == 0)
-      return this.SESSION_STATUS_START;
-
-    var previousNode = this._visibleElements[aRow - 1].node;
-    if (!PlacesUtils.nodeIsVisit(previousNode) ||
-        node.sessionId != asVisit(previousNode).sessionId)
-      return this.SESSION_STATUS_START;
-
-    return this.SESSION_STATUS_CONTINUE;
-  },
-
-  /**
-   * Call to completely rebuild the list of visible items. Note if there is no
-   * tree or root this will just clear out the list, so you can also call this
-   * when a tree is detached to clear the list.
-   */
-  _buildVisibleList: function PTV__buildVisibleList() {
     var selection = this.selection;
     if (selection)
       selection.selectEventsSuppressed = true;
 
-    if (this._result) {
-      // Any current visible elements need to be marked as invisible.
-      for (var i = 0; i < this._visibleElements.length; i++) {
-        this._visibleElements[i].node.viewIndex = -1;
-      }
+    this._rootNode._viewIndex = -1;
+    if (!this._rootNode.containerOpen) {
+      // This triggers containerOpened which then builds the visible section.
+      this._rootNode.containerOpen = true;
     }
-
-    var rootNode = this._result.root;
-    if (rootNode && this._tree) {
-      this._computeShowSessions();
+    else
+      this.invalidateContainer(this._rootNode);
 
-      asContainer(rootNode);
-      if (this._showRoot) {
-        // List the root node
-        this._visibleElements.push(
-          { node: this._result.root, properties: null });
-        this._tree.rowCountChanged(0, 1);
-        this._result.root.viewIndex = 0;
-      }
-      else if (!rootNode.containerOpen) {
-        // this triggers containerOpened which then builds the visible
-        // section
-        rootNode.containerOpen = true;
-      }
-      else
-        this.invalidateContainer(rootNode);
-    }
+    // "Activate" the sorting column and update commands.
+    this.sortingChanged(this._result.sortingMode);
+
     if (selection)
       selection.selectEventsSuppressed = false;
   },
 
+  _rootNode: null,
+
   /**
    * This takes a container and recursively appends visible elements to the
    * given array. This is used to build the visible element list (with
    * this._visibleElements passed as the array), or portions thereof (with
-   * a separate array that is merged with the main list later.
+   * a separate array that is merged with the main list later).
    *
    * aVisibleStartIndex is the visible index of the beginning of the 'aVisible'
    * array. When aVisible is this._visibleElements, this is 0. This is non-zero
    * when we are building up a sub-region for insertion. Then, this is the
    * index where the new array will be inserted into this._visibleElements.
    * It is used to compute each node's viewIndex.
    */
   _buildVisibleSection:
@@ -192,147 +118,148 @@ PlacesTreeView.prototype = {
   {
     if (!aContainer.containerOpen)
       return;  // nothing to do
 
     const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");
     const trueLiteral = PlacesUIUtils.RDF.GetLiteral("true");
 
     var cc = aContainer.childCount;
+    var sortingMode = this._result.sortingMode;
     for (var i=0; i < cc; i++) {
       var curChild = aContainer.getChild(i);
       var curChildType = curChild.type;
 
-      // don't display separators when sorted
+      // Don't display separators when sorted.
       if (curChildType == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
-        if (this._result.sortingMode !=
-            Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
-          curChild.viewIndex = -1;
+        if (sortingMode != Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
+          curChild._viewIndex = -1;
           continue;
         }
       }
 
-      // add item
-      curChild.viewIndex = aVisibleStartIndex + aVisible.length;
-      aVisible.push({ node: curChild, properties: null });
+      // Add the node to the visible-nodes array and set its viewIndex.
+      curChild._viewIndex = aVisibleStartIndex + aVisible.length;
+      aVisible.push(curChild);
 
-      // recursively do containers
-      if (!this._flatList && PlacesUtils.containerTypes.indexOf(curChildType) != -1) {
-        asContainer(curChild);
-
+      // Recursively do containers.
+      if (!this._flatList &&
+          curChild instanceof Ci.nsINavHistoryContainerResultNode) {
         var resource = this._getResourceForNode(curChild);
         var isopen = resource != null &&
                      PlacesUIUtils.localStore.HasAssertion(resource, openLiteral,
                                                            trueLiteral, true);
         if (isopen != curChild.containerOpen)
           aToOpen.push(curChild);
         else if (curChild.containerOpen && curChild.childCount > 0)
           this._buildVisibleSection(curChild, aVisible, aToOpen, aVisibleStartIndex);
       }
     }
   },
 
   /**
-   * This counts how many rows an item takes in the tree, that is, the
-   * item itself plus any nodes following it with an increased indent.
-   * This allows you to figure out how many rows an item (=1) or a
-   * container with all of its children takes.
+   * This counts how many rows a node takes in the tree.  For containers it
+   * will count the node itself plus any child node following it.
    */
-  _countVisibleRowsForItem: function PTV__countVisibleRowsForItem(aNode) {
-    if (aNode == this._result.root)
+  _countVisibleRowsForNode: function PTV__countVisibleRowsForNode(aNode) {
+    if (aNode == this._rootNode)
       return this._visibleElements.length;
 
-    var viewIndex = aNode.viewIndex;
-    NS_ASSERT(viewIndex >= 0, "Item is not visible, no rows to count");
+    var viewIndex = aNode._viewIndex;
+    NS_ASSERT(viewIndex >= 0, "Node is not visible, no rows to count");
     var outerLevel = aNode.indentLevel;
     for (var i = viewIndex + 1; i < this._visibleElements.length; i++) {
-      if (this._visibleElements[i].node.indentLevel <= outerLevel)
+      if (this._visibleElements[i].indentLevel <= outerLevel)
         return i - viewIndex;
     }
     // this node plus its children occupy the bottom of the list
     return this._visibleElements.length - viewIndex;
   },
 
   /**
    * This is called by containers when they change and we need to update
    * everything about the container. We build a new visible section with
    * the container as a separate object so we first know how the list
-   * changes. This way we only have to do one realloc/memcpy to update
-   * the list.
+   * changes.
    *
    * We also try to be smart here about redrawing the screen.
    */
   _refreshVisibleSection: function PTV__refreshVisibleSection(aContainer) {
     NS_ASSERT(this._result, "Need to have a result to update");
     if (!this._tree)
       return;
 
-    // The root node is invisible if showRoot is not set. Otherwise aContainer
-    // must be visible
-    if (this._showRoot || aContainer != this._result.root) {
-      if (aContainer.viewIndex < 0 ||
-          aContainer.viewIndex > this._visibleElements.length)
+    // The root node is invisible.
+    if (aContainer != this._rootNode) {
+      if (aContainer._viewIndex < 0 ||
+          aContainer._viewIndex > this._visibleElements.length)
         throw "Trying to expand a node that is not visible";
 
-      NS_ASSERT(this._visibleElements[aContainer.viewIndex].node == aContainer,
+      NS_ASSERT(this._visibleElements[aContainer._viewIndex] == aContainer,
                 "Visible index is out of sync!");
     }
 
-    var startReplacement = aContainer.viewIndex + 1;
-    var replaceCount = this._countVisibleRowsForItem(aContainer);
+    var startReplacement = aContainer._viewIndex + 1;
+    var replaceCount = this._countVisibleRowsForNode(aContainer);
 
-    // We don't replace the container item itself so we decrease the
-    // replaceCount by 1. We don't do so though if there is no visible item
-    // for the container. This happens when aContainer is the root node and
-    // showRoot is not set.
-    if (aContainer.viewIndex != -1)
-      replaceCount-=1;
+    // We don't replace the container node itself so we should decrease the
+    // replaceCount by 1, unless the container is our root node, which isn't
+    // visible.
+    if (aContainer != this._rootNode)
+      replaceCount -= 1;
 
-    // Persist selection state
+    // Persist selection state.
     var previouslySelectedNodes = [];
     var selection = this.selection;
     var rc = selection.getRangeCount();
     for (var rangeIndex = 0; rangeIndex < rc; rangeIndex++) {
       var min = { }, max = { };
       selection.getRangeAt(rangeIndex, min, max);
       var lastIndex = Math.min(max.value, startReplacement + replaceCount -1);
-      // if this range does not overlap the replaced chunk we don't need to
+      // If this range does not overlap the replaced chunk, we don't need to
       // persist the selection.
       if (max.value < startReplacement || min.value > lastIndex)
         continue;
-      // if this range starts before the replaced chunk we should persist from
-      // startReplacement to lastIndex
+
+      // If this range starts before the replaced chunk, we should persist from
+      // startReplacement to lastIndex.
       var firstIndex = Math.max(min.value, startReplacement);
-      for (var nodeIndex = firstIndex; nodeIndex <= lastIndex; nodeIndex++)
+      for (var nodeIndex = firstIndex; nodeIndex <= lastIndex; nodeIndex++) {
+        // Mark the node invisible if we're about to remove it,
+        // otherwise we'll try to select it later.
+        var node = this._visibleElements[nodeIndex];
+        if (nodeIndex >= startReplacement &&
+            nodeIndex < startReplacement + replaceCount)
+          node._viewIndex = -1;
+
         previouslySelectedNodes.push(
-          { node: this._visibleElements[nodeIndex].node, oldIndex: nodeIndex });
+          { node: node, oldIndex: nodeIndex });
+      }
     }
 
-    // Mark the removes as invisible
-    for (var i = 0; i < replaceCount; i++)
-      this._visibleElements[startReplacement + i].node.viewIndex = -1;
-
     // Building the new list will set the new elements' visible indices.
     var newElements = [];
     var toOpenElements = [];
     this._buildVisibleSection(aContainer,
                               newElements, toOpenElements, startReplacement);
 
-    // actually update the visible list
+    // Actually update the visible list.
+    // XXX: We can probably make this more efficient using splice through
+    // Function.apply.
     this._visibleElements =
       this._visibleElements.slice(0, startReplacement).concat(newElements)
           .concat(this._visibleElements.slice(startReplacement + replaceCount,
                                               this._visibleElements.length));
 
     // If the new area has a different size, we'll have to renumber the
     // elements following the area.
     if (replaceCount != newElements.length) {
       for (var i = startReplacement + newElements.length;
-           i < this._visibleElements.length; i ++) {
-        this._visibleElements[i].node.viewIndex = i;
+           i < this._visibleElements.length; i++) {
+        this._visibleElements[i]._viewIndex = i;
       }
     }
 
     // now update the number of elements
     selection.selectEventsSuppressed = true;
     this._tree.beginUpdateBatch();
 
     if (replaceCount)
@@ -359,44 +286,49 @@ PlacesTreeView.prototype = {
     }
 
     this._tree.endUpdateBatch();
 
     // restore selection
     if (previouslySelectedNodes.length > 0) {
       for (var i = 0; i < previouslySelectedNodes.length; i++) {
         var nodeInfo = previouslySelectedNodes[i];
-        var index = nodeInfo.node.viewIndex;
+        var index = nodeInfo.node._viewIndex;
 
-        // if the same node was used (happens on sorting-changes),
-        // just use viewIndex
-        if (index == -1) { // otherwise, try to find an equal node
+        // If the nodes under the invalidated container were preserved, we can
+        // just use viewIndex.
+        if (index == -1) {
+          // Otherwise, try to find an equal node.
           var itemId = PlacesUtils.getConcreteItemId(nodeInfo.node);
-          if (itemId != 1) { // bookmark-nodes in queries case
+          if (itemId != 1) {
+            // Search by itemId.
             for (var j = 0; j < newElements.length && index == -1; j++) {
               if (PlacesUtils.getConcreteItemId(newElements[j]) == itemId)
-                index = newElements[j].viewIndex;
+                index = newElements[j]._viewIndex;
             }
           }
-          else { // history nodes
+          else {
+            // Search by uri.
             var uri = nodeInfo.node.uri;
             if (uri) {
               for (var j = 0; j < newElements.length && index == -1; j++) {
                 if (newElements[j].uri == uri)
-                  index = newElements[j].viewIndex;
+                  index = newElements[j]._viewIndex;
               }
             }
           }
         }
+
+        // Select the found node, if any.
         if (index != -1)
           selection.rangedSelect(index, index, true);
       }
 
-      // if only one node was previously selected and there's no selection now,
-      // select the node at its old-viewIndex, if any
+      // If only one node was previously selected and there's no selection now,
+      // select the node at its old viewIndex, if any.
       if (previouslySelectedNodes.length == 1 &&
           selection.getRangeCount() == 0 &&
           this._visibleElements.length > previouslySelectedNodes[0].oldIndex) {
         selection.rangedSelect(previouslySelectedNodes[0].oldIndex,
                                previouslySelectedNodes[0].oldIndex, true);
       }
     }
     selection.selectEventsSuppressed = false;
@@ -505,268 +437,320 @@ PlacesTreeView.prototype = {
         return [this.COLUMN_TYPE_TAGS, false];
       case Ci.nsINavHistoryQueryOptions.SORT_BY_TAGS_DESCENDING:
         return [this.COLUMN_TYPE_TAGS, true];
     }
     return [this.COLUMN_TYPE_UNKNOWN, false];
   },
 
   // nsINavHistoryResultViewer
-  itemInserted: function PTV_itemInserted(aParent, aItem, aNewIndex) {
+  nodeInserted: function PTV_nodeInserted(aParentNode, aNode, aNewIndex) {
     if (!this._tree)
       return;
     if (!this._result)
       throw Cr.NS_ERROR_UNEXPECTED;
 
-    if (PlacesUtils.nodeIsSeparator(aItem) &&
+    if (PlacesUtils.nodeIsSeparator(aNode) &&
         this._result.sortingMode != Ci.nsINavHistoryQueryOptions.SORT_BY_NONE) {
-      aItem.viewIndex = -1;
+      aNode._viewIndex = -1;
       return;
     }
 
-    // update parent when inserting the first item because twisty may
-    // have changed
-    if (aParent.childCount == 1)
-      this.itemChanged(aParent);
+    // Update parent when inserting the first item, since twisty may
+    // have changed.
+    if (aParentNode.childCount == 1)
+      this._tree.invalidateRow(aParentNode._viewIndex);
 
     // compute the new view index of the item
     var newViewIndex = -1;
     if (aNewIndex == 0) {
       // item is the first thing in our child list, it takes our index +1. Note
       // that this computation still works if the parent is an invisible root
       // node, because root_index + 1 = -1 + 1 = 0
-      newViewIndex = aParent.viewIndex + 1;
+      newViewIndex = aParentNode._viewIndex + 1;
     }
     else {
       // Here, we try to find the next visible element in the child list so we
       // can set the new visible index to be right before that. Note that we
       // have to search DOWN instead of up, because some siblings could have
       // children themselves that would be in the way.
-      for (var i = aNewIndex + 1; i < aParent.childCount; i ++) {
-        var viewIndex = aParent.getChild(i).viewIndex;
+      for (var i = aNewIndex + 1; i < aParentNode.childCount; i++) {
+        var viewIndex = aParentNode.getChild(i)._viewIndex;
         if (viewIndex >= 0) {
           // the view indices of subsequent children have not been shifted so
           // the next item will have what should be our index
           newViewIndex = viewIndex;
           break;
         }
       }
       if (newViewIndex < 0) {
         // At the end of the child list without finding a visible sibling: This
         // is a little harder because we don't know how many rows the last item
         // in our list takes up (it could be a container with many children).
-        var prevChild = aParent.getChild(aNewIndex - 1);
-        newViewIndex = prevChild.viewIndex + this._countVisibleRowsForItem(prevChild);
+        var prevChild = aParentNode.getChild(aNewIndex - 1);
+        newViewIndex = prevChild._viewIndex + this._countVisibleRowsForNode(prevChild);
       }
     }
 
-    aItem.viewIndex = newViewIndex;
-    this._visibleElements.splice(newViewIndex, 0, 
-                                 { node: aItem, properties: null });
+    aNode._viewIndex = newViewIndex;
+    this._visibleElements.splice(newViewIndex, 0, aNode);
     for (var i = newViewIndex + 1;
-         i < this._visibleElements.length; i ++) {
-      this._visibleElements[i].node.viewIndex = i;
+         i < this._visibleElements.length; i++) {
+      this._visibleElements[i]._viewIndex = i;
     }
     this._tree.rowCountChanged(newViewIndex, 1);
 
-    // Need to redraw the rows around this one because session boundaries
-    // may have changed. For example, if we add a page to a session, the
-    // previous page will need to be redrawn because its session border
-    // will disappear.
-    if (this._showSessions) {
-      if (newViewIndex > 0)
-        this._tree.invalidateRange(newViewIndex - 1, newViewIndex - 1);
-      if (newViewIndex < this._visibleElements.length -1)
-        this._tree.invalidateRange(newViewIndex + 1, newViewIndex + 1);
-    }
-
-    if (PlacesUtils.nodeIsContainer(aItem) && asContainer(aItem).containerOpen)
-      this._refreshVisibleSection(aItem);
+    if (PlacesUtils.nodeIsContainer(aNode) && asContainer(aNode).containerOpen)
+      this._refreshVisibleSection(aNode);
   },
 
-  // this is used in itemRemoved and itemMoved to fix viewIndex values
-  // throw if the item has an invalid viewIndex
-  _fixViewIndexOnRemove: function PTV_fixViewIndexOnRemove(aItem, aParent) {
-    var oldViewIndex = aItem.viewIndex;
+  // This is used in nodeRemoved and nodeMoved to fix viewIndex values.
+  // Throws if the node has an invalid viewIndex.
+  _fixViewIndexOnRemove: function PTV_fixViewIndexOnRemove(aNode,
+                                                           aParentNode) {
+    var oldViewIndex = aNode._viewIndex;
     // this may have been a container, in which case it has a lot of rows
-    var count = this._countVisibleRowsForItem(aItem);
+    var count = this._countVisibleRowsForNode(aNode);
 
     if (oldViewIndex > this._visibleElements.length)
-      throw("Trying to remove an item with an invalid viewIndex");
+      throw("Trying to remove a node with an invalid viewIndex");
 
     this._visibleElements.splice(oldViewIndex, count);
     for (var i = oldViewIndex; i < this._visibleElements.length; i++)
-      this._visibleElements[i].node.viewIndex = i;
+      this._visibleElements[i]._viewIndex = i;
 
     this._tree.rowCountChanged(oldViewIndex, -count);
 
     // redraw parent because twisty may have changed
-    if (!aParent.hasChildren)
-      this.itemChanged(aParent);
-
-    return;
+    if (!aParentNode.hasChildren)
+      this._tree.invalidateRow(aParentNode._viewIndex);
   },
 
   /**
    * THIS FUNCTION DOES NOT HANDLE cases where a collapsed node is being
    * removed but the node it is collapsed with is not being removed (this then
    * just swap out the removee with its collapsing partner). The only time
    * when we really remove things is when deleting URIs, which will apply to
    * all collapsees. This function is called sometimes when resorting items.
    * However, we won't do this when sorted by date because dates will never
    * change for visits, and date sorting is the only time things are collapsed.
    */
-  itemRemoved: function PTV_itemRemoved(aParent, aItem, aOldIndex) {
+  nodeRemoved: function PTV_nodeRemoved(aParentNode, aNode, aOldIndex) {
     NS_ASSERT(this._result, "Got a notification but have no result!");
     if (!this._tree)
       return; // nothing to do
 
-    var oldViewIndex = aItem.viewIndex;
-    if (oldViewIndex < 0)
-      return; // item was already invisible, nothing to do
+    var oldViewIndex = aNode._viewIndex;
+    if (oldViewIndex < 0) {
+      // There's nothing to do if the node was already invisible.
+      return;
+    }
 
-    // if the item was exclusively selected, the node next to it will be
-    // selected
+    // If the node was exclusively selected, the node next to it will be
+    // selected.
     var selectNext = false;
     var selection = this.selection;
     if (selection.getRangeCount() == 1) {
       var min = { }, max = { };
       selection.getRangeAt(0, min, max);
       if (min.value == max.value &&
-          this.nodeForTreeIndex(min.value) == aItem)
+          this.nodeForTreeIndex(min.value) == aNode)
         selectNext = true;
     }
 
-    // remove the item and fix viewIndex values
-    this._fixViewIndexOnRemove(aItem, aParent);
+    // Remove the node and fix viewIndex values.
+    this._fixViewIndexOnRemove(aNode, aParentNode);
 
-    // restore selection if the item was exclusively selected
+    // Restore selection if the node was exclusively selected.
     if (!selectNext)
       return;
-    // restore selection
+
+    // Restore selection
     if (this._visibleElements.length > oldViewIndex)
       selection.rangedSelect(oldViewIndex, oldViewIndex, true);    
     else if (this._visibleElements.length > 0) {
       // if we removed the last child, we select the new last child if exists
       selection.rangedSelect(this._visibleElements.length - 1,
                              this._visibleElements.length - 1, true);
     }
   },
 
   /**
    * Be careful, aOldIndex and aNewIndex specify the index in the
    * corresponding parent nodes, not the visible indexes.
    */
-  itemMoved:
-  function PTV_itemMoved(aItem, aOldParent, aOldIndex, aNewParent, aNewIndex) {
+  nodeMoved:
+  function PTV_nodeMoved(aNode, aOldParent, aOldIndex, aNewParent, aNewIndex) {
     NS_ASSERT(this._result, "Got a notification but have no result!");
     if (!this._tree)
       return; // nothing to do
 
-    var oldViewIndex = aItem.viewIndex;
-    if (oldViewIndex < 0)
-      return; // item was already invisible, nothing to do
+    var oldViewIndex = aNode._viewIndex;
+    if (oldViewIndex < 0) {
+      // There's nothing to do if the node was already invisible.
+      return;
+    }
 
-    // this may have been a container, in which case it has a lot of rows
-    var count = this._countVisibleRowsForItem(aItem);
+    // This may have been a container, in which case it has a lot of rows.
+    var count = this._countVisibleRowsForNode(aNode);
 
-    // Persist selection state
+    // Persist selection state.
     var nodesToSelect = [];
     var selection = this.selection;
     var rc = selection.getRangeCount();
     for (var rangeIndex = 0; rangeIndex < rc; rangeIndex++) {
       var min = { }, max = { };
       selection.getRangeAt(rangeIndex, min, max);
       var lastIndex = Math.min(max.value, oldViewIndex + count -1);
       if (min.value < oldViewIndex || min.value > lastIndex)
         continue;
 
       for (var nodeIndex = min.value; nodeIndex <= lastIndex; nodeIndex++)
-        nodesToSelect.push(this._visibleElements[nodeIndex].node);
+        nodesToSelect.push(this._visibleElements[nodeIndex]);
     }
     if (nodesToSelect.length > 0)
       selection.selectEventsSuppressed = true;
 
-    // remove item from the old position
-    this._fixViewIndexOnRemove(aItem, aOldParent);
+    // Remove node from the old position.
+    this._fixViewIndexOnRemove(aNode, aOldParent);
 
-    // insert the item into the new position
-    this.itemInserted(aNewParent, aItem, aNewIndex);
+    // Insert the node into the new position.
+    this.nodeInserted(aNewParent, aNode, aNewIndex);
 
-    // restore selection
+    // Restore selection.
     if (nodesToSelect.length > 0) {
       for (var i = 0; i < nodesToSelect.length; i++) {
         var node = nodesToSelect[i];
-        var index = node.viewIndex;
+        var index = node._viewIndex;
         selection.rangedSelect(index, index, true);
       }
       selection.selectEventsSuppressed = false;
     }
   },
 
   /**
-   * Be careful, the parameter 'aIndex' here specifies the index in the parent
-   * node of the item, not the visible index.
-   *
-   * This is called from the result when the item is replaced, but this object
-   * calls this function internally also when duplicate collapsing changes. In
-   * this case, aIndex will be 0, so we should be careful not to use the value.
+   * Be careful, the parameter 'aIndex' here specifies the node's index in the
+   * parent node, not the visible index.
    */
-  itemReplaced:
-  function PTV_itemReplaced(aParent, aOldItem, aNewItem, aIndexDoNotUse) {
+  nodeReplaced:
+  function PTV_nodeReplaced(aParentNode, aOldNode, aNewNode, aIndexDoNotUse) {
     if (!this._tree)
       return;
 
-    var viewIndex = aOldItem.viewIndex;
-    aNewItem.viewIndex = viewIndex;
+    var viewIndex = aOldNode._viewIndex;
+    aNewNode._viewIndex = viewIndex;
     if (viewIndex >= 0 &&
         viewIndex < this._visibleElements.length) {
-      this._visibleElements[viewIndex].node = aNewItem;
-      this._visibleElements[viewIndex].properties = null;
+      this._visibleElements[viewIndex] = aNewNode;
     }
-    aOldItem.viewIndex = -1;
+    aOldNode._viewIndex = -1;
     this._tree.invalidateRow(viewIndex);
   },
 
-  itemChanged: function PTV_itemChanged(aItem) {
+  _invalidateCellValue: function PTV__invalidateCellValue(aNode,
+                                                          aColumnType) {
     NS_ASSERT(this._result, "Got a notification but have no result!");
-    var viewIndex = aItem.viewIndex;
-    if (this._tree && viewIndex >= 0)
-      this._tree.invalidateRow(viewIndex);
+    let viewIndex = aNode._viewIndex;
+    if (viewIndex == -1) // invisible
+      return;
+
+    if (this._tree) {
+      let column = this._findColumnByType(aColumnType);
+      if (column && !column.element.hidden)
+        this._tree.invalidateCell(viewIndex, column);
+
+      // Last modified time is altered for almost all node changes.
+      if (aColumnType != this.COLUMN_TYPE_LASTMODIFIED) {
+        let lastModifiedColumn =
+          this._findColumnByType(this.COLUMN_TYPE_LASTMODIFIED);
+        if (lastModifiedColumn && !lastModifiedColumn.hidden)
+          this._tree.invalidateCell(viewIndex, lastModifiedColumn);
+      }
+    }
+  },
+
+  nodeTitleChanged: function PTV_nodeTitleChanged(aNode, aNewTitle) {
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
+  },
+
+  nodeURIChanged: function PTV_nodeURIChanged(aNode, aNewURI) {
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_URI);
+  },
+
+  nodeIconChanged: function PTV_nodeIconChanged(aNode) {
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
   },
 
-  containerOpened: function PTV_containerOpened(aItem) {
-    this.invalidateContainer(aItem);
+  nodeHistoryDetailsChanged:
+  function PTV_nodeHistoryDetailsChanged(aNode, aUpdatedVisitDate,
+                                         aUpdatedVisitCount) {
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_DATE);
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_VISITCOUNT);
+  },
+
+  nodeTagsChanged: function PTV_nodeTagsChanged(aNode) {
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_TAGS);
+  },
+
+  nodeKeywordChanged: function PTV_nodeKeywordChanged(aNode, aNewKeyword) {
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_KEYWORD);
   },
 
-  containerClosed: function PTV_containerClosed(aItem) {
-    this.invalidateContainer(aItem);
+  nodeAnnotationChanged: function PTV_nodeAnnotationChanged(aNode, aAnno) {
+    if (aAnno == DESCRIPTION_ANNO)
+      this._invalidateCellValue(aNode, this.COLUMN_TYPE_DESCRIPTION);
+  },
+
+  nodeDateAddedChanged: function PTV_nodeDateAddedChanged(aNode, aNewValue) {
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_DATEADDED);
   },
 
-  invalidateContainer: function PTV_invalidateContainer(aItem) {
+  nodeLastModifiedChanged:
+  function PTV_nodeLastModifiedChanged(aNode, aNewValue) {
+    this._invalidateCellValue(aNode, this.COLUMN_TYPE_LASTMODIFIED);
+  },
+
+  containerOpened: function PTV_containerOpened(aNode) {
+    this.invalidateContainer(aNode);
+  },
+
+  containerClosed: function PTV_containerClosed(aNode) {
+    this.invalidateContainer(aNode);
+  },
+
+  invalidateContainer: function PTV_invalidateContainer(aNode) {
     NS_ASSERT(this._result, "Got a notification but have no result!");
     if (!this._tree)
       return; // nothing to do, container is not visible
-    var viewIndex = aItem.viewIndex;
-    if (viewIndex >= this._visibleElements.length) {
+
+    if (aNode._viewIndex >= this._visibleElements.length) {
       // be paranoid about visible indices since others can change it
       throw Cr.NS_ERROR_UNEXPECTED;
     }
-    this._refreshVisibleSection(aItem);
+    this._refreshVisibleSection(aNode);
   },
 
-  invalidateAll: function PTV_invalidateAll() {
-    NS_ASSERT(this._result, "Got message but don't have a result!");
-    if (!this._tree)
-      return;
+  _columns: [],
+  _findColumnByType: function PTV__findColumnByType(aColumnType) {
+    if (this._columns[aColumnType])
+      return this._columns[aColumnType];
 
-    var oldRowCount = this._visibleElements.length;
+    var columns = this._tree.columns;
+    var colCount = columns.count;
+    for (var i = 0; i < colCount; i++) {
+      let column = columns.getColumnAt(i);
+      let columnType = this._getColumnType(column);
+      this._columns[columnType] = column;
+      if (columnType == aColumnType)
+        return column;
+    }
 
-    // update flat list to new contents
-    this._buildVisibleList();
+    // That's completely valid.  Most of our trees actually include just the
+    // title column.
+    return null;
   },
 
   sortingChanged: function PTV__sortingChanged(aSortingMode) {
     if (!this._tree || !this._result)
       return;
 
     // depending on the sort mode, certain commands may be disabled
     window.updateCommands("sort");
@@ -776,64 +760,64 @@ PlacesTreeView.prototype = {
     // clear old sorting indicator
     var sortedColumn = columns.getSortedColumn();
     if (sortedColumn)
       sortedColumn.element.removeAttribute("sortDirection");
 
     // set new sorting indicator by looking through all columns for ours
     if (aSortingMode == Ci.nsINavHistoryQueryOptions.SORT_BY_NONE)
       return;
+
     var [desiredColumn, desiredIsDescending] =
       this._sortTypeToColumnType(aSortingMode);
     var colCount = columns.count;
-    for (var i = 0; i < colCount; i ++) {
-      var column = columns.getColumnAt(i);
-      if (this._getColumnType(column) == desiredColumn) {
-        // found our desired one, set
-        if (desiredIsDescending)
-          column.element.setAttribute("sortDirection", "descending");
-        else
-          column.element.setAttribute("sortDirection", "ascending");
-        break;
-      }
+    var column = this._findColumnByType(desiredColumn);
+    if (column) {
+      let sortDir = desiredIsDescending ? "descending" : "ascending";
+      column.element.setAttribute("sortDirection", sortDir);
     }
   },
 
   get result() {
     return this._result;
   },
 
   set result(val) {
-    // some methods (e.g. getURLsFromContainer) temporarily null out the
+    // Some methods (e.g. getURLsFromContainer) temporarily null out the
     // viewer when they do temporary changes to the view, this does _not_
     // call setResult(null), but then, we're called again with the result
     // object which is already set for this viewer. At that point,
     // we should do nothing.
     if (this._result != val) {
       if (this._result)
-        this._result.root.containerOpen = false;
+        this._rootNode.containerOpen = false;
+
       this._result = val;
-      this._finishInit();
+      this._rootNode = val ? val.root : null;
+
+      // If the tree is not set yet, setTree will call finishInit.
+      if (this._tree && val)
+        this._finishInit();
     }
     return val;
   },
 
   nodeForTreeIndex: function PTV_nodeForTreeIndex(aIndex) {
     if (aIndex > this._visibleElements.length)
       throw Cr.NS_ERROR_INVALID_ARG;
 
-    return this._visibleElements[aIndex].node;
+    return this._visibleElements[aIndex];
   },
 
   treeIndexForNode: function PTV_treeNodeForIndex(aNode) {
-    var viewIndex = aNode.viewIndex;
+    var viewIndex = aNode._viewIndex;
     if (viewIndex < 0)
       return Ci.nsINavHistoryResultTreeViewer.INDEX_INVISIBLE;
 
-    NS_ASSERT(this._visibleElements[viewIndex].node == aNode,
+    NS_ASSERT(this._visibleElements[viewIndex] == aNode,
               "Node's visible index and array out of sync");
     return viewIndex;
   },
 
   _getResourceForNode: function PTV_getResourceForNode(aNode)
   {
     var uri = aNode.uri;
     NS_ASSERT(uri, "if there is no uri, we can't persist the open state");
@@ -848,35 +832,17 @@ PlacesTreeView.prototype = {
   get selection() {
     return this._selection;
   },
 
   set selection(val) {
     return this._selection = val;
   },
 
-  getRowProperties: function PTV_getRowProperties(aRow, aProperties) {
-    this._ensureValidRow(aRow);
-
-    // Handle properties for session information.
-    if (!this._showSessions)
-      return;
-
-    var status = this._getRowSessionStatus(aRow);
-    switch (status) {
-      case this.SESSION_STATUS_NONE:
-        break;
-      case this.SESSION_STATUS_START:
-        aProperties.AppendElement(this._getAtomFor("session-start"));
-        break;
-      case this.SESSION_STATUS_CONTINUE:
-        aProperties.AppendElement(this._getAtomFor("session-continue"));
-        break
-    }
-  },
+  getRowProperties: function PTV_getRowProperties(aRow, aProperties) { },
 
   getCellProperties: function PTV_getCellProperties(aRow, aColumn, aProperties) {
     this._ensureValidRow(aRow);
 
     // for anonid-trees, we need to add the column-type manually
     var columnType = aColumn.element.getAttribute("anonid");
     if (columnType)
       aProperties.AppendElement(this._getAtomFor(columnType));
@@ -885,21 +851,19 @@ PlacesTreeView.prototype = {
 
     // Set the "ltr" property on url cells
     if (columnType == "url")
       aProperties.AppendElement(this._getAtomFor("ltr"));
 
     if (columnType != "title")
       return;
 
-    var node = this._visibleElements[aRow].node;
-    var properties = this._visibleElements[aRow].properties;
-
-    if (!properties) {
-      properties = new Array();
+    var node = this._visibleElements[aRow];
+    if (!node._cellProperties) {
+      let properties = new Array();
       var itemId = node.itemId;
       var nodeType = node.type;
       if (PlacesUtils.containerTypes.indexOf(nodeType) != -1) {
         if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY) {
           properties.push(this._getAtomFor("query"));
           if (PlacesUtils.nodeIsTagQuery(node))
             properties.push(this._getAtomFor("tagContainer"));
           else if (PlacesUtils.nodeIsDay(node))
@@ -924,82 +888,71 @@ PlacesTreeView.prototype = {
       else if (PlacesUtils.nodeIsURI(node)) {
         properties.push(this._getAtomFor(PlacesUIUtils.guessUrlSchemeForUI(node.uri)));
         if (itemId != -1) {
           if (PlacesUtils.nodeIsLivemarkContainer(node.parent))
             properties.push(this._getAtomFor("livemarkItem"));
         }
       }
 
-      this._visibleElements[aRow].properties = properties;
+      node._cellProperties = properties;
     }
-    for (var i = 0; i < properties.length; i++)
-      aProperties.AppendElement(properties[i]);
+    for (var i = 0; i < node._cellProperties.length; i++)
+      aProperties.AppendElement(node._cellProperties[i]);
   },
 
   getColumnProperties: function(aColumn, aProperties) { },
 
   isContainer: function PTV_isContainer(aRow) {
     this._ensureValidRow(aRow);
 
-    var node = this._visibleElements[aRow].node;
+    var node = this._visibleElements[aRow];
     if (PlacesUtils.nodeIsContainer(node)) {
-      // the root node is always expandable
-      if (!node.parent)
-        return true;
-
       // Flat-lists may ignore expandQueries and other query options when
       // they are asked to open a container.
       if (this._flatList)
         return true;
 
       // treat non-expandable childless queries as non-containers
       if (PlacesUtils.nodeIsQuery(node)) {
         var parent = node.parent;
-        if((PlacesUtils.nodeIsQuery(parent) ||
-            PlacesUtils.nodeIsFolder(parent)) &&
-           !node.hasChildren)
+        if ((PlacesUtils.nodeIsQuery(parent) ||
+             PlacesUtils.nodeIsFolder(parent)) &&
+            !node.hasChildren)
           return asQuery(parent).queryOptions.expandQueries;
       }
       return true;
     }
     return false;
   },
 
   isContainerOpen: function PTV_isContainerOpen(aRow) {
     if (this._flatList)
       return false;
 
     this._ensureValidRow(aRow);
-    if (!PlacesUtils.nodeIsContainer(this._visibleElements[aRow].node))
-      throw Cr.NS_ERROR_INVALID_ARG;
-
-    return this._visibleElements[aRow].node.containerOpen;
+    return this._visibleElements[aRow].containerOpen;
   },
 
   isContainerEmpty: function PTV_isContainerEmpty(aRow) {
     if (this._flatList)
       return true;
 
     this._ensureValidRow(aRow);
-
-    if (!PlacesUtils.nodeIsContainer(this._visibleElements[aRow].node))
-      throw Cr.NS_ERROR_INVALID_ARG;
-
-    return !this._visibleElements[aRow].node.hasChildren;
+    return !this._visibleElements[aRow].hasChildren;
   },
 
   isSeparator: function PTV_isSeparator(aRow) {
     this._ensureValidRow(aRow);
-    return PlacesUtils.nodeIsSeparator(this._visibleElements[aRow].node);
+    return PlacesUtils.nodeIsSeparator(this._visibleElements[aRow]);
   },
 
   isSorted: function PTV_isSorted() {
     return this._result.sortingMode !=
-           Components.interfaces.nsINavHistoryQueryOptions.SORT_BY_NONE;
+           Ci.nsINavHistoryQueryOptions.SORT_BY_NONE;
   },
 
   canDrop: function PTV_canDrop(aRow, aOrientation) {
     if (!this._result)
       throw Cr.NS_ERROR_UNEXPECTED;
 
     // drop position into a sorted treeview would be wrong
     if (this.isSorted())
@@ -1020,18 +973,18 @@ PlacesTreeView.prototype = {
         // If the last selected item is an open container, append _into_
         // it, rather than insert adjacent to it. 
         container = lastSelected;
         index = -1;
       }
       else if (lastSelected.containerOpen &&
                orientation == Ci.nsITreeView.DROP_AFTER &&
                lastSelected.hasChildren) {
-        // If the last selected item is an open container and the user is
-        // trying to drag into it as a first item, really insert into it.
+        // If the last selected node is an open container and the user is
+        // trying to drag into it as a first node, really insert into it.
         container = lastSelected;
         orientation = Ci.nsITreeView.DROP_ON;
         index = 0;
       }
       else {
         // Use the last-selected node's container unless the root node
         // is selected, in which case we use the root node itself as the
         // insertion point.
@@ -1080,76 +1033,65 @@ PlacesTreeView.prototype = {
     var ip = this._getInsertionPoint(aRow, aOrientation);
     if (!ip)
       return;
     PlacesControllerDragHelper.onDrop(ip);
   },
 
   getParentIndex: function PTV_getParentIndex(aRow) {
     this._ensureValidRow(aRow);
-    var parent = this._visibleElements[aRow].node.parent;
-    if (!parent || parent.viewIndex < 0)
+    var parent = this._visibleElements[aRow].parent;
+    if (!parent || parent._viewIndex < 0)
       return -1;
 
-    return parent.viewIndex;
+    return parent._viewIndex;
   },
 
   hasNextSibling: function PTV_hasNextSibling(aRow, aAfterIndex) {
     this._ensureValidRow(aRow);
     if (aRow == this._visibleElements.length -1) {
       // this is the last thing in the list -> no next sibling
       return false;
     }
 
-    var thisLevel = this._visibleElements[aRow].node.indentLevel;
+    var thisLevel = this._visibleElements[aRow].indentLevel;
     for (var i = aAfterIndex + 1; i < this._visibleElements.length; ++i) {
-      var nextLevel = this._visibleElements[i].node.indentLevel;
+      var nextLevel = this._visibleElements[i].indentLevel;
       if (nextLevel == thisLevel)
         return true;
       if (nextLevel < thisLevel)
         break;
     }
     return false;
   },
 
   getLevel: function PTV_getLevel(aRow) {
     this._ensureValidRow(aRow);
 
-    // Level is 0 for items at the root level, 1 for its children and so on.
-    // If we don't show the result's root node, the level is simply the node's
-    // indentLevel; if we do, it is the node's indentLevel increased by 1.
-    // That is because nsNavHistoryResult uses -1 as the indent level for the
-    // root node regardless of our internal showRoot state.
-    if (this._showRoot)
-      return this._visibleElements[aRow].node.indentLevel + 1;
-
-    return this._visibleElements[aRow].node.indentLevel;
+    // Level is 0 for nodes at the root level, 1 for its children and so on.
+    return this._visibleElements[aRow].indentLevel;
   },
 
   getImageSrc: function PTV_getImageSrc(aRow, aColumn) {
     this._ensureValidRow(aRow);
 
     // only the title column has an image
     if (this._getColumnType(aColumn) != this.COLUMN_TYPE_TITLE)
       return "";
 
-    var node = this._visibleElements[aRow].node;
-    var icon = node.icon;
-    if (icon)
-      return icon.spec;
-    return "";
+    return this._visibleElements[aRow].icon;
   },
 
   getProgressMode: function(aRow, aColumn) { },
   getCellValue: function(aRow, aColumn) { },
 
   getCellText: function PTV_getCellText(aRow, aColumn) {
     this._ensureValidRow(aRow);
 
-    var node = this._visibleElements[aRow].node;
+    var node = this._visibleElements[aRow];
     var columnType = this._getColumnType(aColumn);
     switch (columnType) {
       case this.COLUMN_TYPE_TITLE:
         // normally, this is just the title, but we don't want empty items in
         // the tree view so return a special string if the title is empty.
         // Do it here so that callers can still get at the 0 length title
         // if they go through the "result" API.
         if (PlacesUtils.nodeIsSeparator(node))
@@ -1157,27 +1099,27 @@ PlacesTreeView.prototype = {
         return PlacesUIUtils.getBestTitle(node);
       case this.COLUMN_TYPE_TAGS:
         return node.tags;
       case this.COLUMN_TYPE_URI:
         if (PlacesUtils.nodeIsURI(node))
           return node.uri;
         return "";
       case this.COLUMN_TYPE_DATE:
-        if (node.time == 0 || !PlacesUtils.nodeIsURI(node)) {
+        let nodeTime = node.time;
+        if (nodeTime == 0 || !PlacesUtils.nodeIsURI(node)) {
           // hosts and days shouldn't have a value for the date column.
           // Actually, you could argue this point, but looking at the
           // results, seeing the most recently visited date is not what
           // I expect, and gives me no information I know how to use.
           // Only show this for URI-based items.
           return "";
         }
-        if (this._getRowSessionStatus(aRow) != this.SESSION_STATUS_CONTINUE)
-          return this._convertPRTimeToString(node.time);
-        return "";
+
+        return this._convertPRTimeToString(nodeTime);
       case this.COLUMN_TYPE_VISITCOUNT:
         return node.accessCount;
       case this.COLUMN_TYPE_KEYWORD:
         if (PlacesUtils.nodeIsBookmark(node))
           return PlacesUtils.bookmarks.getKeywordForBookmark(node.itemId);
         return "";
       case this.COLUMN_TYPE_DESCRIPTION:
         if (node.itemId != -1) {
@@ -1199,37 +1141,34 @@ PlacesTreeView.prototype = {
     }
     return "";
   },
 
   setTree: function PTV_setTree(aTree) {
     var hasOldTree = this._tree != null;
     this._tree = aTree;
 
-    // do this before detaching from result when there is no tree.
-    // This ensures that the visible indices of the elements in the
-    // result have been set to -1
-    this._finishInit();
-
-    if (!aTree && hasOldTree && this._result) {
-      // detach from result when we are detaching from the tree.
-      // This breaks the reference cycle between us and the result.
-      this._result.viewer = null;
+    if (this._result) {
+      if (hasOldTree) {
+        // detach from result when we are detaching from the tree.
+        // This breaks the reference cycle between us and the result.
+        if (!aTree)
+          this._result.viewer = null;
+      }
+      if (aTree)
+        this._finishInit();
     }
   },
 
   toggleOpenState: function PTV_toggleOpenState(aRow) {
     if (!this._result)
       throw Cr.NS_ERROR_UNEXPECTED;
     this._ensureValidRow(aRow);
 
-    var node = this._visibleElements[aRow].node;
-    if (!PlacesUtils.nodeIsContainer(node))
-      return; // not a container, nothing to do
-
+    var node = this._visibleElements[aRow];
     if (this._flatList && this._openContainerCallback) {
       this._openContainerCallback(node);
       return;
     }
 
     var resource = this._getResourceForNode(node);
     if (resource) {
       const openLiteral = PlacesUIUtils.RDF.GetResource("http://home.netscape.com/NC-rdf#open");
@@ -1396,21 +1335,16 @@ PlacesTreeView.prototype = {
   selectionChanged: function() { },
   cycleCell: function PTV_cycleCell(aRow, aColumn) { },
   isSelectable: function(aRow, aColumn) { return false; },
   performAction: function(aAction) { },
   performActionOnRow: function(aAction, aRow) { },
   performActionOnCell: function(aAction, aRow, aColumn) { }
 };
 
-function PlacesTreeView(aShowRoot, aFlatList, aOnOpenFlatContainer) {
-  if (aShowRoot && aFlatList)
-    throw("Flat-list mode is not supported when show-root is set");
-
+function PlacesTreeView(aFlatList, aOnOpenFlatContainer) {
   this._tree = null;
   this._result = null;
-  this._showSessions = false;
   this._selection = null;
   this._visibleElements = [];
-  this._showRoot = aShowRoot;
   this._flatList = aFlatList;
   this._openContainerCallback = aOnOpenFlatContainer;
 }
--- a/browser/components/places/content/utils.js
+++ b/browser/components/places/content/utils.js
@@ -997,27 +997,22 @@ var PlacesUIUtils = {
   guessUrlSchemeForUI: function PUU_guessUrlSchemeForUI(aUrlString) {
     return aUrlString.substr(0, aUrlString.indexOf(":"));
   },
 
   /**
    * Helper for the toolbar and menu views
    */
   createMenuItemForNode:
-  function PUU_createMenuItemForNode(aNode, aContainersMap) {
+  function PUU_createMenuItemForNode(aNode) {
     var element;
     var type = aNode.type;
     if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR)
       element = document.createElement("menuseparator");
     else {
-      var iconURI = aNode.icon;
-      var iconURISpec = "";
-      if (iconURI)
-        iconURISpec = iconURI.spec;
-
       if (PlacesUtils.uriTypes.indexOf(type) != -1) {
         element = document.createElement("menuitem");
         element.className = "menuitem-iconic bookmark-item";
         element.setAttribute("scheme", this.guessUrlSchemeForUI(aNode.uri));
       }
       else if (PlacesUtils.containerTypes.indexOf(type) != -1) {
         element = document.createElement("menu");
         element.setAttribute("container", "true");
@@ -1046,30 +1041,29 @@ var PlacesUIUtils = {
         // the popup correctly.
         popup._startMarker = -1;
         popup._endMarker = -1;
 #else
         // no context menu on mac
         popup.setAttribute("context", "placesContext");
 #endif
         element.appendChild(popup);
-        if (aContainersMap)
-          aContainersMap.push({ resultNode: aNode, domNode: popup });
         element.className = "menu-iconic bookmark-item";
       }
       else
         throw "Unexpected node";
 
       element.setAttribute("label", this.getBestTitle(aNode));
 
-      if (iconURISpec)
-        element.setAttribute("image", iconURISpec);
+      var icon = aNode.icon;
+      if (icon)
+        element.setAttribute("image", icon);
     }
     element.node = aNode;
-    element.node.viewIndex = 0;
+    element.node._DOMElement = element;
 
     return element;
   },
 
   cleanPlacesPopup: function PU_cleanPlacesPopup(aPopup) {
     // Remove places popup children and update markers to keep track of
     // their indices.
     var start = aPopup._startMarker != -1 ? aPopup._startMarker + 1 : 0;
--- a/browser/components/places/src/nsPlacesTransactionsService.js
+++ b/browser/components/places/src/nsPlacesTransactionsService.js
@@ -570,17 +570,17 @@ placesCreateLivemarkTransactions.prototy
       PlacesUtils.bookmarks.setItemGUID(this._id, this._GUID);
   },
 
   undoTransaction: function PCLT_undoTransaction() {
     // If a GUID exists for this item, preserve it before removing the item.
     if (PlacesUtils.annotations.itemHasAnnotation(this._id, GUID_ANNO))
       this._GUID = PlacesUtils.bookmarks.getItemGUID(this._id);
 
-    PlacesUtils.bookmarks.removeFolder(this._id);
+    PlacesUtils.bookmarks.removeItem(this._id);
   }
 };
 
 function placesRemoveLivemarkTransaction(aFolderId) {
   this.redoTransaction = this.doTransaction;
   this._id = aFolderId;
   this._title = PlacesUtils.bookmarks.getItemTitle(this._id);
   this._container = PlacesUtils.bookmarks.getFolderIdForItem(this._id);
--- a/browser/components/places/tests/browser/browser_views_liveupdate.js
+++ b/browser/components/places/tests/browser/browser_views_liveupdate.js
@@ -183,45 +183,48 @@ var bookmarksObserver = {
   QueryInterface: function PSB_QueryInterface(aIID) {
     if (aIID.equals(Ci.nsINavBookmarkObserver) ||
         aIID.equals(Ci.nsISupports))
       return this;
     throw Cr.NS_NOINTERFACE;
   },
 
   // nsINavBookmarkObserver
-  onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex) {
+  onItemAdded: function PSB_onItemAdded(aItemId, aFolderId, aIndex,
+                                        aItemType) {
     var views = getViewsForFolder(aFolderId);
     ok(views.length > 0, "Found affected views: " + views);
 
     // Check that item has been added in the correct position.
     for (var i = 0; i < views.length; i++) {
       var node = null;
       var index = null;
       [node, index] = searchItemInView(aItemId, views[i]);
       isnot(node, null, "Found new Places node in " + views[i]);
       is(index, aIndex, "Node is at index " + index);
     }
   },
 
-  onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex) {
+  onItemRemoved: function PSB_onItemRemoved(aItemId, aFolder, aIndex,
+                                            aItemType) {
     var views = getViewsForFolder(aFolderId);
     ok(views.length > 0, "Found affected views: " + views);
     // Check that item has been removed.
     for (var i = 0; i < views.length; i++) {
       var node = null;
       var index = null;
       [node, index] = searchItemInView(aItemId, views[i]);
       is(node, null, "Places node not found in " + views[i]);
     }
   },
 
   onItemMoved: function(aItemId,
                         aOldFolderId, aOldIndex,
-                        aNewFolderId, aNewIndex) {
+                        aNewFolderId, aNewIndex,
+                        aItemType) {
     var views = getViewsForFolder(aNewFolderId);
     ok(views.length > 0, "Found affected views: " + views);
 
     // Check that item has been moved in the correct position.
     for (var i = 0; i < views.length; i++) {
       var node = null;
       var index = null;
       [node, index] = searchItemInView(aItemId, views[i]);
@@ -229,18 +232,17 @@ var bookmarksObserver = {
       is(index, aNewIndex, "Node is at index " + index);
     }
   },
 
   onBeginUpdateBatch: function PSB_onBeginUpdateBatch() {},
   onEndUpdateBatch: function PSB_onEndUpdateBatch() {},
   onBeforeItemRemoved: function PSB_onBeforeItemRemoved(aItemId) {},
   onItemVisited: function() {},
-  onItemChanged: function PSB_onItemChanged(aItemId, aProperty,
-                                            aIsAnnotationProperty, aValue) {}
+  onItemChanged: function PSB_onItemChanged() {}
 };
 
 /**
  * Search an item id in a view.
  *
  * @param aItemId
  *        item id of the item to search.
  * @param aView
@@ -286,17 +288,17 @@ function getNodeForToolbarItem(aItemId) 
       if (child.node.itemId == aItemId)
         return [child.node, i - staticNodes];
 
       // Don't search in queries, they could contain our item in a
       // different position.  Search only folders
       if (PlacesUtils.nodeIsFolder(child.node)) {
         var popup = child.lastChild;
         popup.showPopup(popup);
-        foundNode = findNode(popup);
+        var foundNode = findNode(popup);
         popup.hidePopup();
         if (foundNode[0] != null)
           return foundNode;
       }
     }
     return [null, null];
   }
 
@@ -329,17 +331,17 @@ function getNodeForMenuItem(aItemId) {
 
       // Don't search in queries, they could contain our item in a
       // different position.  Search only folders
       if (PlacesUtils.nodeIsFolder(child.node)) {
         var popup = child.lastChild;
         // XXX Why is this needed on Linux and Mac?
         popup.showPopup(popup);
         child.open = true;
-        foundNode = findNode(popup);
+        var foundNode = findNode(popup);
         popup.hidePopup();
         child.open = false;
         if (foundNode[0] != null)
           return foundNode;
       }
     }
     return [null, null];
   }
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/unit/distribution.ini
@@ -0,0 +1,21 @@
+# Distribution Configuration File
+# Bug 516444 demo
+
+[Global]
+id=516444
+version=1.0
+about=Test distribution file
+
+[BookmarksToolbar]
+item.1.title=Toolbar Link Before
+item.1.link=http://mozilla.com/
+item.2.type=default
+item.3.title=Toolbar Link After
+item.3.link=http://mozilla.com/
+
+[BookmarksMenu]
+item.1.title=Menu Link Before
+item.1.link=http://mozilla.com/
+item.2.type=default
+item.3.title=Menu Link After
+item.3.link=http://mozilla.com/
\ No newline at end of file
--- a/browser/components/places/tests/unit/head_bookmarks.js
+++ b/browser/components/places/tests/unit/head_bookmarks.js
@@ -152,20 +152,24 @@ function check_no_bookmarks() {
   root.containerOpen = false;
 }
 
 let gTestDir = do_get_cwd();
 const FILENAME_BOOKMARKS_HTML = "bookmarks.html";
 let backup_date = new Date().toLocaleFormat("%Y-%m-%d");
 const FILENAME_BOOKMARKS_JSON = "bookmarks-" + backup_date + ".json";
 
-// Smart bookmarks constants
+// Smart bookmarks constants.
 const SMART_BOOKMARKS_VERSION = 2;
 const SMART_BOOKMARKS_ON_TOOLBAR = 1;
-const SMART_BOOKMARKS_ON_MENU = 2;
+const SMART_BOOKMARKS_ON_MENU = 3; // Takes in count the additional separator.
+
+// Default bookmarks constants.
+const DEFAULT_BOOKMARKS_ON_TOOLBAR = 2;
+const DEFAULT_BOOKMARKS_ON_MENU = 3;
 
 /**
  * Creates a bookmarks.html file in the profile folder from a given source file.
  *
  * @param aFilename
  *        Name of the file to copy to the profile folder.  This file must
  *        exist in the directory that contains the test files.
  *
--- a/browser/components/places/tests/unit/test_384370.js
+++ b/browser/components/places/tests/unit/test_384370.js
@@ -94,21 +94,21 @@ function run_test() {
   validate();
 
   // Test exporting a Places canonical json file.
   // 1. export to bookmarks.exported.json
   // 2. empty bookmarks db
   // 3. import bookmarks.exported.json
   // 4. run the test-suite
   try {
-    PlacesUtils.backupBookmarksToFile(jsonFile);
+    PlacesUtils.backups.saveBookmarksToJSONFile(jsonFile);
   } catch(ex) { do_throw("couldn't export to file: " + ex); }
   LOG("exported json"); 
   try {
-    PlacesUtils.restoreBookmarksFromJSONFile(jsonFile);
+    PlacesUtils.backups.restoreBookmarksFromJSONFile(jsonFile);
   } catch(ex) { do_throw("couldn't import the exported file: " + ex); }
   LOG("imported json"); 
   validate();
   LOG("validated import"); 
 }
 
 var tagData = [
   { uri: uri("http://slint.us"), tags: ["indie", "kentucky", "music"] },
--- a/browser/components/places/tests/unit/test_bookmarksRestoreNotification.js
+++ b/browser/components/places/tests/unit/test_bookmarksRestoreNotification.js
@@ -75,37 +75,37 @@ var tests = [
     desc:       "JSON restore: normal restore should succeed",
     currTopic:  NSIOBSERVER_TOPIC_BEGIN,
     finalTopic: NSIOBSERVER_TOPIC_SUCCESS,
     data:       NSIOBSERVER_DATA_JSON,
     folderId:   null,
     run:        function () {
       this.file = createFile("bookmarks-test_restoreNotification.json");
       addBookmarks();
-      PlacesUtils.backupBookmarksToFile(this.file);
+      PlacesUtils.backups.saveBookmarksToJSONFile(this.file);
       remove_all_bookmarks();
       try {
-        PlacesUtils.restoreBookmarksFromJSONFile(this.file);
+        PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
       }
       catch (e) {
         do_throw("  Restore should not have failed");
       }
     }
   },
 
   {
     desc:       "JSON restore: empty file should succeed",
     currTopic:  NSIOBSERVER_TOPIC_BEGIN,
     finalTopic: NSIOBSERVER_TOPIC_SUCCESS,
     data:       NSIOBSERVER_DATA_JSON,
     folderId:   null,
     run:        function () {
       this.file = createFile("bookmarks-test_restoreNotification.json");
       try {
-        PlacesUtils.restoreBookmarksFromJSONFile(this.file);
+        PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
       }
       catch (e) {
         do_throw("  Restore should not have failed");
       }
     }
   },
 
   {
@@ -113,17 +113,17 @@ var tests = [
     currTopic:  NSIOBSERVER_TOPIC_BEGIN,
     finalTopic: NSIOBSERVER_TOPIC_FAILED,
     data:       NSIOBSERVER_DATA_JSON,
     folderId:   null,
     run:        function () {
       this.file = dirSvc.get("ProfD", Ci.nsILocalFile);
       this.file.append("this file doesn't exist because nobody created it");
       try {
-        PlacesUtils.restoreBookmarksFromJSONFile(this.file);
+        PlacesUtils.backups.restoreBookmarksFromJSONFile(this.file);
         do_throw("  Restore should have failed");
       }
       catch (e) {}
     }
   },
 
   {
     desc:       "HTML restore: normal restore should succeed",
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/unit/test_browserGlue_distribution.js
@@ -0,0 +1,143 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Places Unit Test code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Marco Bonardo <mak77@bonardo.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * Tests that nsBrowserGlue does not overwrite bookmarks imported from the
+ * migrators.  They usually run before nsBrowserGlue, so if we find any
+ * bookmark on init, we should not try to import.
+ */
+
+const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion";
+const PREF_BMPROCESSED = "distribution.516444.bookmarksProcessed";
+const PREF_DISTRIBUTION_ID = "distribution.id";
+
+const TOPIC_FINAL_UI_STARTUP = "final-ui-startup";
+const TOPIC_PLACES_INIT_COMPLETE = "places-init-complete";
+const TOPIC_CUSTOMIZATION_COMPLETE = "distribution-customization-complete";
+
+let os = Cc["@mozilla.org/observer-service;1"].
+         getService(Ci.nsIObserverService);
+
+let observer = {
+  observe: function(aSubject, aTopic, aData) {
+    if (aTopic == TOPIC_CUSTOMIZATION_COMPLETE) {
+      os.removeObserver(this, TOPIC_CUSTOMIZATION_COMPLETE);
+      do_timeout(0, "continue_test();");
+    }
+  }
+}
+os.addObserver(observer, TOPIC_CUSTOMIZATION_COMPLETE, false);
+
+function run_test() {
+  // Copy distribution.ini file to our app dir.
+  let distroDir = dirSvc.get("XCurProcD", Ci.nsIFile);
+  distroDir.append("distribution");
+  let iniFile = distroDir.clone();
+  iniFile.append("distribution.ini");
+  if (iniFile.exists()) {
+    iniFile.remove(false);
+    print("distribution.ini already exists, did some test forget to cleanup?");
+  }
+
+  let testDistributionFile = gTestDir.clone();
+  testDistributionFile.append("distribution.ini");
+  testDistributionFile.copyTo(distroDir, "distribution.ini");
+  do_check_true(testDistributionFile.exists());
+
+  // Disable Smart Bookmarks creation.
+  let ps = Cc["@mozilla.org/preferences-service;1"].
+           getService(Ci.nsIPrefBranch);
+  ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, -1);
+
+  // Initialize Places through the History Service, so it won't trigger
+  // browserGlue::_initPlaces since browserGlue is not yet in context.
+  let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
+           getService(Ci.nsINavHistoryService);
+  // Check a new database has been created.
+  // nsBrowserGlue will use databaseStatus to manage initialization.
+  do_check_eq(hs.databaseStatus, hs.DATABASE_STATUS_CREATE);
+
+  // Initialize nsBrowserGlue.
+  Cc["@mozilla.org/browser/browserglue;1"].getService(Ci.nsIBrowserGlue);
+
+  // Places initialization has already happened, so we need to simulate a new
+  // one.  This will force browserGlue::_initPlaces().
+  os.notifyObservers(null, TOPIC_FINAL_UI_STARTUP, null);
+  os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
+
+  do_test_pending();
+  // Test will continue on customization complete notification.
+}
+
+function continue_test() {
+  let bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
+           getService(Ci.nsINavBookmarksService);
+
+  // Check the custom bookmarks exist on menu.
+  let menuItemId = bs.getIdForItemAt(bs.bookmarksMenuFolder, 0);
+  do_check_neq(menuItemId, -1);
+  do_check_eq(bs.getItemTitle(menuItemId), "Menu Link Before");
+  menuItemId = bs.getIdForItemAt(bs.bookmarksMenuFolder, 1 + DEFAULT_BOOKMARKS_ON_MENU);
+  do_check_neq(menuItemId, -1);
+  do_check_eq(bs.getItemTitle(menuItemId), "Menu Link After");
+
+  // Check the custom bookmarks exist on toolbar.
+  let toolbarItemId = bs.getIdForItemAt(bs.toolbarFolder, 0);
+  do_check_neq(toolbarItemId, -1);
+  do_check_eq(bs.getItemTitle(toolbarItemId), "Toolbar Link Before");
+  toolbarItemId = bs.getIdForItemAt(bs.toolbarFolder, 1 + DEFAULT_BOOKMARKS_ON_TOOLBAR);
+  do_check_neq(toolbarItemId, -1);
+  do_check_eq(bs.getItemTitle(toolbarItemId), "Toolbar Link After");
+
+  // Check the bmprocessed pref has been created.
+  let ps = Cc["@mozilla.org/preferences-service;1"].
+           getService(Ci.nsIPrefBranch);
+  do_check_true(ps.getBoolPref(PREF_BMPROCESSED));
+
+  // Check distribution prefs have been created.
+  do_check_eq(ps.getCharPref(PREF_DISTRIBUTION_ID), "516444");
+
+  // Remove the distribution file.
+  let iniFile = dirSvc.get("XCurProcD", Ci.nsIFile);
+  iniFile.append("distribution");
+  iniFile.append("distribution.ini");
+  iniFile.remove(false);
+  do_check_false(iniFile.exists());
+
+  do_test_finished();
+}
--- a/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js
+++ b/browser/components/places/tests/unit/test_browserGlue_smartBookmarks.js
@@ -70,26 +70,26 @@ var tests = [];
 
 tests.push({
   description: "All smart bookmarks are created if smart bookmarks version is 0.",
   exec: function() {
     // Sanity check: we should not have any bookmark on the toolbar.
     do_check_eq(bs.getIdForItemAt(bs.toolbarFolder, 0), -1);
     // Sanity check: we should not have any bookmark on the menu.
     do_check_eq(bs.getIdForItemAt(bs.bookmarksMenuFolder, 0), -1);
-    
+
     // Set preferences.
     ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 0);
     // Force nsBrowserGlue::_initPlaces().
     os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
 
     // Count items on toolbar.
-    do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR);
+    do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR);
     // Count items on menu (+1 for the separator).
-    do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + 1);
+    do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU);
 
     // Check version has been updated.
     do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION);
 
     next_test();
   }
 });
 
@@ -108,19 +108,19 @@ tests.push({
     do_check_eq(bs.getItemTitle(itemId), "new title");
 
     // Set preferences.
     ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 1);
     // Force nsBrowserGlue::_initPlaces().
     os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
 
     // Count items on toolbar.
-    do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR);
+    do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR);
     // Count items on menu (+1 for the separator).
-    do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + 1);
+    do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU);
 
     // check smart bookmark has been replaced, itemId has changed.
     itemId = bs.getIdForItemAt(bs.toolbarFolder, 0);
     do_check_neq(itemId, -1);
     do_check_neq(bs.getItemTitle(itemId), "new title");
     do_check_true(as.itemHasAnnotation(itemId, SMART_BOOKMARKS_ANNO));
 
     // Check version has been updated.
@@ -133,25 +133,25 @@ tests.push({
 //------------------------------------------------------------------------------
 
 tests.push({
   description: "An explicitly removed smart bookmark should not be recreated.",
   exec: function() {   
     // Set preferences.
     ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 1);
     // Remove toolbar's smart bookmarks
-    bs.removeFolderChildren(bs.toolbarFolder);
+    bs.removeItem(bs.getIdForItemAt(bs.toolbarFolder, 0));
 
     // Force nsBrowserGlue::_initPlaces().
     os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
 
     // Count items on toolbar, we should not have recreated the smart bookmark.
-    do_check_eq(countFolderChildren(bs.toolbarFolder), 0);
+    do_check_eq(countFolderChildren(bs.toolbarFolder),  DEFAULT_BOOKMARKS_ON_TOOLBAR);
     // Count items on menu (+1 for the separator).
-    do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + 1);
+    do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU);
 
     // Check version has been updated.
     do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION);
 
     next_test();
   }
 });
 
@@ -162,19 +162,19 @@ tests.push({
   exec: function() {   
     // Set preferences.
     ps.setIntPref(PREF_SMART_BOOKMARKS_VERSION, 0);
 
     // Force nsBrowserGlue::_initPlaces().
     os.notifyObservers(null, TOPIC_PLACES_INIT_COMPLETE, null);
 
     // Count items on toolbar, we should not have recreated the smart bookmark.
-    do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR);
+    do_check_eq(countFolderChildren(bs.toolbarFolder), SMART_BOOKMARKS_ON_TOOLBAR + DEFAULT_BOOKMARKS_ON_TOOLBAR);
     // Count items on menu (+1 for the separator).
-    do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + 1);
+    do_check_eq(countFolderChildren(bs.bookmarksMenuFolder), SMART_BOOKMARKS_ON_MENU + DEFAULT_BOOKMARKS_ON_MENU);
 
     // Check version has been updated.
     do_check_eq(ps.getIntPref(PREF_SMART_BOOKMARKS_VERSION), SMART_BOOKMARKS_VERSION);
 
     finish_test();
   }
 });
 //------------------------------------------------------------------------------
@@ -188,33 +188,29 @@ function countFolderChildren(aFolderItem
   var cc = rootNode.childCount;
   rootNode.containerOpen = false;
   return cc;
 }
 
 function finish_test() {
   // Clean up database from all bookmarks.
   remove_all_bookmarks();
-  // Simulate application closing to remove the idle observer and avoid leaks.
-  os.notifyObservers(null, "quit-application-granted", null);
+
   do_test_finished();
 }
 
 var testIndex = 0;
 function next_test() {
-  // Simulate application closing to remove the idle observer and avoid leaks.
-  os.notifyObservers(null, "quit-application-granted", null);
-
   // nsBrowserGlue stops observing topics after first notification,
   // so we add back the observer to test additional runs.
   os.addObserver(bg, TOPIC_PLACES_INIT_COMPLETE, false);
 
   // Execute next test.
-  var test = tests.shift();
-  dump("\nTEST " + (++testIndex) + ": " + test.description);
+  let test = tests.shift();
+  print("\nTEST " + (++testIndex) + ": " + test.description);
   test.exec();
 }
 
 function run_test() {
   // Clean up database from all bookmarks.
   remove_all_bookmarks();
 
   // Kick-off tests.
--- a/browser/components/places/tests/unit/test_placesTxn.js
+++ b/browser/components/places/tests/unit/test_placesTxn.js
@@ -86,40 +86,43 @@ try {
 // create and add bookmarks observer
 var observer = {
   onBeginUpdateBatch: function() {
     this._beginUpdateBatch = true;
   },
   onEndUpdateBatch: function() {
     this._endUpdateBatch = true;
   },
-  onItemAdded: function(id, folder, index) {
+  onItemAdded: function(id, folder, index, itemType) {
     this._itemAddedId = id;
     this._itemAddedParent = folder;
     this._itemAddedIndex = index;
+    this._itemAddedType = itemType;
   },
   onBeforeItemRemoved: function(id) {
   },
-  onItemRemoved: function(id, folder, index) {
+  onItemRemoved: function(id, folder, index, itemType) {
     this._itemRemovedId = id;
     this._itemRemovedFolder = folder;
     this._itemRemovedIndex = index;
   },
-  onItemChanged: function(id, property, isAnnotationProperty, value) {
+  onItemChanged: function(id, property, isAnnotationProperty, newValue,
+                          lastModified, itemType) {
     this._itemChangedId = id;
     this._itemChangedProperty = property;
     this._itemChanged_isAnnotationProperty = isAnnotationProperty;
-    this._itemChangedValue = value;
+    this._itemChangedValue = newValue;
   },
   onItemVisited: function(id, visitID, time) {
     this._itemVisitedId = id;
     this._itemVisitedVistId = visitID;
     this._itemVisitedTime = time;
   },
-  onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex) {
+  onItemMoved: function(id, oldParent, oldIndex, newParent, newIndex,
+                        itemType) {
     this._itemMovedId = id
     this._itemMovedOldParent = oldParent;
     this._itemMovedOldIndex = oldIndex;
     this._itemMovedNewParent = newParent;
     this._itemMovedNewIndex = newIndex;
   },
   QueryInterface: function(iid) {
     if (iid.equals(Ci.nsINavBookmarkObserver) ||
@@ -145,28 +148,30 @@ function run_test() {
   var annos = [{ name: DESCRIPTION_ANNO,
                  type: annosvc.TYPE_STRING,
                 flags: 0,
                 value: TEST_DESCRIPTION,
               expires: annosvc.EXPIRE_NEVER }];
   var txn1 = ptSvc.createFolder("Testing folder", root, bmStartIndex, annos);
   ptSvc.doTransaction(txn1);
 
-  // the check check that calling undoTransaction on an "empty batch" doesn't undo
-  // the previous transaction
+  // This checks that calling undoTransaction on an "empty batch" doesn't
+  // undo the previous transaction (getItemTitle will fail)
   ptSvc.beginBatch();
   ptSvc.endBatch();
   ptSvc.undoTransaction();
 
-  var folderId = bmsvc.getChildFolder(root, "Testing folder");
-  do_check_eq(TEST_DESCRIPTION, 
-              annosvc.getItemAnnotation(folderId, DESCRIPTION_ANNO));
+  var folderId = observer._itemAddedId;
+  do_check_eq(bmsvc.getItemTitle(folderId), "Testing folder");
   do_check_eq(observer._itemAddedIndex, bmStartIndex);
   do_check_eq(observer._itemAddedParent, root);
   do_check_eq(observer._itemAddedId, folderId);
+  do_check_eq(TEST_DESCRIPTION, 
+              annosvc.getItemAnnotation(folderId, DESCRIPTION_ANNO));
+
   txn1.undoTransaction();
   do_check_eq(observer._itemRemovedId, folderId);
   do_check_eq(observer._itemRemovedFolder, root);
   do_check_eq(observer._itemRemovedIndex, bmStartIndex);
   txn1.redoTransaction();
   do_check_eq(observer._itemAddedIndex, bmStartIndex);
   do_check_eq(observer._itemAddedParent, root);
   do_check_eq(observer._itemAddedId, folderId);
@@ -196,17 +201,19 @@ function run_test() {
   txn2.undoTransaction();
   do_check_eq(observer._itemRemovedId, newId);
   do_check_eq(observer._itemRemovedFolder, root);
   do_check_eq(observer._itemRemovedIndex, bmStartIndex);
 
   // Create item to a folder
   var txn2a = ptSvc.createFolder("Folder", root, bmStartIndex);
   ptSvc.doTransaction(txn2a);
-  var fldrId = bmsvc.getChildFolder(root, "Folder");
+  var fldrId = observer._itemAddedId;
+  do_check_eq(bmsvc.getItemTitle(fldrId), "Folder");
+
   var txn2b = ptSvc.createItem(uri("http://www.example2.com"), fldrId, bmStartIndex, "Testing1b");
   ptSvc.doTransaction(txn2b);
   var b2 = (bmsvc.getBookmarkIdsForURI(uri("http://www.example2.com"), {}))[0];
   do_check_eq(observer._itemAddedId, b2);
   do_check_eq(observer._itemAddedIndex, bmStartIndex);
   do_check_true(bmsvc.isBookmarked(uri("http://www.example2.com")));
   txn2b.undoTransaction();
   do_check_eq(observer._itemRemovedId, b2);
@@ -282,17 +289,19 @@ function run_test() {
   do_check_eq(observer._itemMovedId, bkmk1Id);
   do_check_eq(observer._itemMovedOldParent, fldrId);
   do_check_eq(observer._itemMovedOldIndex, 1);
   do_check_eq(observer._itemMovedNewParent, root);
   do_check_eq(observer._itemMovedNewIndex, 1);
 
   // Test Removing a Folder
   ptSvc.doTransaction(ptSvc.createFolder("Folder2", root, -1));
-  var fldrId2 = bmsvc.getChildFolder(root, "Folder2");
+  var fldrId2 = observer._itemAddedId;
+  do_check_eq(bmsvc.getItemTitle(fldrId2), "Folder2");
+
   var txn4 = ptSvc.removeItem(fldrId2);
   txn4.doTransaction();
   do_check_eq(observer._itemRemovedId, fldrId2);
   do_check_eq(observer._itemRemovedFolder, root);
   do_check_eq(observer._itemRemovedIndex, 3);
   txn4.undoTransaction();
   do_check_eq(observer._itemAddedId, fldrId2);
   do_check_eq(observer._itemAddedParent, root);
@@ -544,17 +553,18 @@ function run_test() {
   do_check_true(annosvc.pageHasAnnotation(uri("http://www.mozilla.org/"), "testAnno/testInt"));
   genPageAnnoTxn.undoTransaction();
   do_check_false(annosvc.pageHasAnnotation(uri("http://www.mozilla.org/"), "testAnno/testInt"));
   genPageAnnoTxn.redoTransaction();
   do_check_true(annosvc.pageHasAnnotation(uri("http://www.mozilla.org/"), "testAnno/testInt"));
 
   // sortFolderByName
   ptSvc.doTransaction(ptSvc.createFolder("Sorting folder", root, bmStartIndex, [], null));
-  var srtFldId = bmsvc.getChildFolder(root, "Sorting folder");
+  var srtFldId = observer._itemAddedId;
+  do_check_eq(bmsvc.getItemTitle(srtFldId), "Sorting folder");
   ptSvc.doTransaction(ptSvc.createItem(uri("http://www.sortingtest.com"), srtFldId, -1, "c"));
   ptSvc.doTransaction(ptSvc.createItem(uri("http://www.sortingtest.com"), srtFldId, -1, "b"));   
   ptSvc.doTransaction(ptSvc.createItem(uri("http://www.sortingtest.com"), srtFldId, -1, "a"));
   var b = bmsvc.getBookmarkIdsForURI(uri("http://www.sortingtest.com"), {});
   b.sort();
   var b1 = b[0];
   var b2 = b[1];
   var b3 = b[2];
--- a/browser/components/preferences/applications.js
+++ b/browser/components/preferences/applications.js
@@ -1729,19 +1729,17 @@ var gApplicationsPane = {
     params.description   = handlerInfo.description;
     params.filename      = null;
     params.handlerApp    = null;
 
     window.openDialog("chrome://global/content/appPicker.xul", null,
                       "chrome,modal,centerscreen,titlebar,dialog=yes",
                       params);
 
-    if (params.handlerApp && 
-        params.handlerApp.executable && 
-        params.handlerApp.executable.isFile()) {
+    if (this.isValidHandlerApp(params.handlerApp)) {
       handlerApp = params.handlerApp;
 
       // Add the app to the type's list of possible handlers.
       handlerInfo.addPossibleApplicationHandler(handlerApp);
     }
 #else
     var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     var winTitle = this._prefsBundle.getString("fpTitleChooseApp");
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_viewsource.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_viewsource.js
@@ -56,17 +56,17 @@ function test() {
       observe: function(aSubject, aTopic, aData) {
         if (aTopic == "domwindowopened") {
           ww.unregisterNotification(this);
 
           let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
           win.addEventListener("load", function() {
             win.removeEventListener("load", arguments.callee, false);
 
-            let browser = win.getBrowser();
+            let browser = win.gBrowser;
             browser.addEventListener("load", function() {
               browser.removeEventListener("load", arguments.callee, true);
               
               // view source window is loaded, proceed with the rest of the test
               step1();
             }, true);
           }, false);
         }
@@ -128,17 +128,17 @@ function test() {
         observe: function(aSubject, aTopic, aData) {
           if (aTopic == "domwindowopened") {
             ww.unregisterNotification(this);
 
             let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
             win.addEventListener("load", function() {
               win.removeEventListener("load", arguments.callee, false);
 
-              let browser = win.getBrowser();
+              let browser = win.gBrowser;
               browser.addEventListener("load", function() {
                 browser.removeEventListener("load", arguments.callee, true);
                 
                 // view source window inside private browsing mode opened
                 step5();
               }, true);
             }, false);
           }
@@ -163,17 +163,17 @@ function test() {
             ok(true, "Leaving the private browsing mode should restore the previous view source window");
             if (++events == 2)
               ww.unregisterNotification(observer);
 
             let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
             win.addEventListener("load", function() {
               win.removeEventListener("load", arguments.callee, false);
 
-              let browser = win.getBrowser();
+              let browser = win.gBrowser;
               browser.addEventListener("load", function() {
                 browser.removeEventListener("load", arguments.callee, true);
                 
                 is(win.content.location.href, "view-source:about:",
                   "The correct view source window should be restored");
 
                 // cleanup
                 win.close();
--- a/browser/components/privatebrowsing/test/unit/do_test_removeDataFromDomain.js
+++ b/browser/components/privatebrowsing/test/unit/do_test_removeDataFromDomain.js
@@ -192,17 +192,17 @@ function check_downloaded(aURIString, aI
     "SELECT * " +
     "FROM moz_downloads " +
     "WHERE source = :source"
   );
   stmt.params.source = aURIString;
 
   let checker = aIsDownloaded ? do_check_true : do_check_false;
   try {
-    checker(stmt.step());
+    checker(stmt.executeStep());
   }
   finally {
     stmt.finalize();
   }
 }
 
 /**
  * Adds a disabled host to the login manager.
--- a/browser/fuel/src/fuelApplication.js
+++ b/browser/fuel/src/fuelApplication.js
@@ -542,17 +542,17 @@ BookmarkFolder.prototype = {
 
   addFolder : function bmf_addfolder(aTitle) {
     var newFolderID = Utilities.bookmarks.createFolder(this._id, aTitle, Utilities.bookmarks.DEFAULT_INDEX);
     var newFolder = new BookmarkFolder(newFolderID, this);
     return newFolder;
   },
 
   remove : function bmf_remove() {
-    Utilities.bookmarks.removeFolder(this._id);
+    Utilities.bookmarks.removeItem(this._id);
   },
 
   // observer
   onBeginUpdateBatch : function bmf_obub() {
   },
 
   onEndUpdateBatch : function bmf_oeub() {
   },
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -130,22 +130,17 @@
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.xpt
 @BINPATH@/components/content_xmldoc.xpt
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/content_xtf.xpt
 @BINPATH@/components/contentprefs.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
-#ifdef XP_WIN32
-;XXX: this is stupid. fix this.
-@BINPATH@/components/docshell_base.xpt
-#else
 @BINPATH@/components/docshell.xpt
-#endif
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_base.xpt
 @BINPATH@/components/dom_canvas.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_html.xpt
@@ -177,16 +172,17 @@
 @BINPATH@/components/fuel.xpt
 @BINPATH@/components/gfx.xpt
 @BINPATH@/components/htmlparser.xpt
 @BINPATH@/components/imglib2.xpt
 @BINPATH@/components/imgicon.xpt
 @BINPATH@/components/inspector.xpt
 @BINPATH@/components/intl.xpt
 @BINPATH@/components/jar.xpt
+@BINPATH@/components/jsctypes.xpt
 @BINPATH@/components/jsdservice.xpt
 @BINPATH@/components/layout_base.xpt
 #ifdef NS_PRINTING
 @BINPATH@/components/layout_printing.xpt
 #endif
 @BINPATH@/components/layout_xul_tree.xpt
 @BINPATH@/components/layout_xul.xpt
 #ifdef XP_UNIX
@@ -216,22 +212,17 @@
 @BINPATH@/components/necko_wifi.xpt
 @BINPATH@/components/necko.xpt
 @BINPATH@/components/loginmgr.xpt
 @BINPATH@/components/places.xpt
 @BINPATH@/components/plugin.xpt
 @BINPATH@/components/pref.xpt
 @BINPATH@/components/prefetch.xpt
 @BINPATH@/components/profile.xpt
-;XXX: stupid, fix this!
-#ifdef XP_WIN32
 @BINPATH@/components/proxyObject.xpt
-#else
-@BINPATH@/components/proxyObjInst.xpt
-#endif
 @BINPATH@/components/rdf.xpt
 @BINPATH@/components/satchel.xpt
 @BINPATH@/components/saxparser.xpt
 @BINPATH@/components/sessionstore.xpt
 @BINPATH@/components/shellservice.xpt
 @BINPATH@/components/shistory.xpt
 @BINPATH@/components/spellchecker.xpt
 @BINPATH@/components/storage.xpt
@@ -256,22 +247,17 @@
 @BINPATH@/components/widget.xpt
 @BINPATH@/components/windowds.xpt
 @BINPATH@/components/windowwatcher.xpt
 @BINPATH@/components/xpcom_base.xpt
 @BINPATH@/components/xpcom_system.xpt
 @BINPATH@/components/xpcom_components.xpt
 @BINPATH@/components/xpcom_ds.xpt
 @BINPATH@/components/xpcom_io.xpt
-;XXX: stupid, fix this!
-#ifdef XP_WIN32
-@BINPATH@/components/xpcom_thread.xpt
-#else
 @BINPATH@/components/xpcom_threads.xpt
-#endif
 @BINPATH@/components/xpcom_xpti.xpt
 @BINPATH@/components/xpconnect.xpt
 @BINPATH@/components/xpinstall.xpt
 @BINPATH@/components/xulapp.xpt
 @BINPATH@/components/xuldoc.xpt
 @BINPATH@/components/xultmpl.xpt
 @BINPATH@/components/zipwriter.xpt
 
@@ -309,22 +295,17 @@
 @BINPATH@/components/nsExtensionManager.js
 @BINPATH@/components/nsBlocklistService.js
 @BINPATH@/components/nsUpdateService.js
 @BINPATH@/components/pluginGlue.js
 @BINPATH@/components/nsSessionStartup.js
 @BINPATH@/components/nsSessionStore.js
 @BINPATH@/components/nsURLFormatter.js
 @BINPATH@/components/@DLL_PREFIX@browserdirprovider@DLL_SUFFIX@
-#ifdef XP_WIN32
-;XXX: lame, kill use_short_libname
-@BINPATH@/components/brwsrcmp.dll
-#else
 @BINPATH@/components/@DLL_PREFIX@browsercomps@DLL_SUFFIX@
-#endif
 @BINPATH@/components/txEXSLTRegExFunctions.js
 @BINPATH@/components/nsLivemarkService.js
 @BINPATH@/components/nsTaggingService.js
 @BINPATH@/components/nsPlacesDBFlush.js
 @BINPATH@/components/nsPlacesAutoComplete.js
 @BINPATH@/components/nsDefaultCLH.js
 @BINPATH@/components/nsContentPrefService.js
 @BINPATH@/components/nsContentDispatchChooser.js
@@ -377,19 +358,17 @@
 @BINPATH@/icons/*.png
 #endif
 
 ; [Default Preferences]
 ; All the pref files must be part of base to prevent migration bugs
 @BINPATH@/@PREF_DIR@/firefox.js
 @BINPATH@/@PREF_DIR@/firefox-branding.js
 @BINPATH@/@PREF_DIR@/channel-prefs.js
-@BINPATH@/greprefs/all.js
-@BINPATH@/greprefs/security-prefs.js
-@BINPATH@/greprefs/xpinstall.js
+@BINPATH@/greprefs.js
 @BINPATH@/defaults/autoconfig/platform.js
 @BINPATH@/defaults/autoconfig/prefcalls.js
 
 ; [Layout Engine Resources]
 ; Style Sheets, Graphics and other Resources used by the layout engine. 
 @BINPATH@/res/hiddenWindow.html
 @BINPATH@/res/ua.css
 @BINPATH@/res/html.css
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -775,16 +775,19 @@ components/xpcom_threads.xpt
 components/xpcom_xpti.xpt
 components/xpconnect.xpt
 components/xpinstall.xpt
 components/xulapp.xpt
 components/xuldoc.xpt
 components/xultmpl.xpt
 components/zipwriter.xpt
 components/firefox.xpt
+greprefs/all.js
+greprefs/security-prefs.js
+greprefs/xpinstall.js
 run-mozilla.sh
 firefox
 dependentlibs.list
 components/nsProgressDialog.js
 #endif
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
 readme.txt
@@ -803,8 +806,11 @@ msvcr80.dll
 #else
 mozcrt19.dll
 #endif
 #endif
 xpicleanup@BIN_SUFFIX@
 chrome.manifest
 install.rdf
 @DLL_PREFIX@jsj@DLL_SUFFIX@
+#ifdef XP_WIN
+components/brwsrcmp.dll
+#endif
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -77,16 +77,17 @@ APP_VERSION := $(shell cat $(srcdir)/../
 PWD := $(CURDIR)
 
 # These are defaulted to be compatible with the files the wget-en-US target
 # pulls. You may override them if you provide your own files. You _must_
 # override them when MOZ_PKG_PRETTYNAMES is defined - the defaults will not
 # work in that case.
 ZIP_IN ?= $(_ABS_DIST)/$(PACKAGE)
 WIN32_INSTALLER_IN ?= $(_ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe
+RETRIEVE_WINDOWS_INSTALLER = 1
 
 MOZ_LANGPACK_EID=langpack-$(AB_CD)@firefox.mozilla.org
 
 ifeq (,$(filter-out pref,$(MOZ_EXTENSIONS)))
 DEFINES += -DEXTENSION_PREF
 endif
 
 PREF_JS_EXPORTS = $(firstword $(wildcard $(LOCALE_SRCDIR)/firefox-l10n.js) \
--- a/browser/locales/en-US/chrome/browser/aboutSupport.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutSupport.dtd
@@ -6,17 +6,16 @@
   trying to solve a problem. If you are looking for answers to common questions
   about &brandShortName;, check out our <a id='supportLink'>support web site</a>.
 ">
 
 <!ENTITY aboutSupport.extensionsTitle "Extensions">
 <!ENTITY aboutSupport.extensionName "Name">
 <!ENTITY aboutSupport.extensionEnabled "Enabled">
 <!ENTITY aboutSupport.extensionVersion "Version">
-<!ENTITY aboutSupport.extensionFirstRun "FirstRun">
 <!ENTITY aboutSupport.extensionId "ID">
 
 <!ENTITY aboutSupport.appBasicsTitle "Application Basics">
 <!ENTITY aboutSupport.appBasicsName "Name">
 <!ENTITY aboutSupport.appBasicsVersion "Version">
 <!ENTITY aboutSupport.appBasicsProfileDir "Profile Directory">
 <!ENTITY aboutSupport.appBasicsPlugins "Installed Plugins">
 <!ENTITY aboutSupport.appBasicsBuildConfig "Build Configuration">
--- a/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd
+++ b/browser/locales/en-US/chrome/browser/baseMenuOverlay.dtd
@@ -5,18 +5,18 @@
 <!ENTITY windowMenu.label         "Window">
 
 <!ENTITY helpMenu.label           "Help"> 
 <!ENTITY helpMenu.accesskey       "H"> 
 <!-- LOCALIZATION NOTE some localizations of Windows (ex:french, german) use "?"
                        for the help button in the menubar but Gnome does not.   -->
 <!ENTITY helpMenuWin.label        "Help"> 
 <!ENTITY helpMenuWin.accesskey    "H">
-<!ENTITY aboutCmd.label           "About &brandFullName;">
-<!ENTITY aboutCmd.accesskey       "A">
+<!ENTITY aboutProduct.label       "About &brandShortName;">
+<!ENTITY aboutProduct.accesskey   "A">
 <!ENTITY productHelp.label        "&brandShortName; Help">
 <!ENTITY productHelp.accesskey    "H">
 <!ENTITY helpForIEUsers.label     "For Internet Explorer Users">
 <!ENTITY helpForIEUsers.accesskey "I">
 <!ENTITY openHelp.commandkey      "VK_F1">
 <!ENTITY helpMac.commandkey       "?">
 
 <!ENTITY helpReleaseNotes.label         "Release Notes">
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -330,16 +330,18 @@
 <!ENTITY mediaMute.label             "Mute">
 <!ENTITY mediaMute.accesskey         "M">
 <!ENTITY mediaUnmute.label           "Unmute">
 <!ENTITY mediaUnmute.accesskey       "m">
 <!ENTITY mediaShowControls.label     "Show Controls">
 <!ENTITY mediaShowControls.accesskey "C">
 <!ENTITY mediaHideControls.label     "Hide Controls">
 <!ENTITY mediaHideControls.accesskey "C">
+<!ENTITY videoFullScreen.label       "Full Screen">
+<!ENTITY videoFullScreen.accesskey   "F">
 
 
 <!-- LOCALIZATION NOTE :
 fullZoomEnlargeCmd.commandkey3, fullZoomReduceCmd.commandkey2 and
 fullZoomResetCmd.commandkey2 are alternative acceleration keys for zoom.
 If shift key is needed with your locale popular keyboard for them,
 you can use these alternative items. Otherwise, their values should be empty.  -->
 
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -2,16 +2,17 @@
 
 @AB_CD@.jar:
 % locale browser @AB_CD@ %locale/browser/
     locale/browser/aboutCertError.dtd              (%chrome/browser/aboutCertError.dtd)
     locale/browser/aboutDialog.dtd                 (%chrome/browser/aboutDialog.dtd)
     locale/browser/aboutPrivateBrowsing.dtd        (%chrome/browser/aboutPrivateBrowsing.dtd)
     locale/browser/aboutRobots.dtd                 (%chrome/browser/aboutRobots.dtd)
     locale/browser/aboutSessionRestore.dtd         (%chrome/browser/aboutSessionRestore.dtd)
+    locale/browser/aboutSupport.dtd                (%chrome/browser/aboutSupport.dtd)
     locale/browser/credits.dtd                     (%chrome/browser/credits.dtd)
 *   locale/browser/browser.dtd                     (%chrome/browser/browser.dtd)
     locale/browser/baseMenuOverlay.dtd             (%chrome/browser/baseMenuOverlay.dtd)
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
     locale/browser/openLocation.dtd                (%chrome/browser/openLocation.dtd)
     locale/browser/openLocation.properties         (%chrome/browser/openLocation.properties)
 *   locale/browser/pageInfo.dtd                    (%chrome/browser/pageInfo.dtd)
     locale/browser/pageInfo.properties             (%chrome/browser/pageInfo.properties)
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -65,23 +65,23 @@
 }
 
 #navigator-toolbox[inFullscreen="true"],
 #navigator-toolbox[inFullscreen="true"] > #nav-bar {
   border-top: none;
   padding-top: 0;
 }
 
-#main-window[lwtheme="true"] #urlbar:not([focused="true"]),
-#main-window[lwtheme="true"] #searchbar > textbox:not([focused="true"]),
-#main-window[lwtheme="true"] .tabbrowser-tab:not([selected="true"]) {
+#urlbar:-moz-lwtheme:not([focused="true"]),
+#searchbar:-moz-lwtheme > textbox:not([focused="true"]),
+.tabbrowser-tab:-moz-lwtheme:not([selected="true"]) {
   opacity: .85;
 }
 
-#main-window[lwtheme="true"] .tabbrowser-tab {
+.tabbrowser-tab:-moz-lwtheme {
   text-shadow: none;
 }
 
 /* Places toolbar */
 toolbarbutton.bookmark-item {
   margin: 0;
   min-width: 0;
   max-width: 13em;
@@ -1122,17 +1122,45 @@ tabpanels {
   height: 16px;
   -moz-margin-start: 4px;
   -moz-margin-end: 3px;
   list-style-image: url("chrome://global/skin/icons/folder-item.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 .tabbrowser-tab[busy] > .tab-icon-image {
-  list-style-image: url("chrome://global/skin/icons/loading_16.png") !important;
+  list-style-image: url("chrome://browser/skin/tabbrowser/progress.png") !important;
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
+.tabbrowser-tab[busy][stalled] > .tab-icon-image {
+  list-style-image: url("chrome://browser/skin/tabbrowser/progress-pulsing.png") !important;
+}
+.tabbrowser-tab[busy][progress="1"] > .tab-icon-image {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+.tabbrowser-tab[busy][progress="2"] > .tab-icon-image {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
+}
+.tabbrowser-tab[busy][progress="3"] > .tab-icon-image {
+  -moz-image-region: rect(0, 64px, 16px, 48px);
+}
+.tabbrowser-tab[busy][progress="4"] > .tab-icon-image {
+  -moz-image-region: rect(0, 80px, 16px, 64px);
+}
+.tabbrowser-tab[busy][progress="5"] > .tab-icon-image {
+  -moz-image-region: rect(0, 96px, 16px, 80px);
+}
+.tabbrowser-tab[busy][progress="6"] > .tab-icon-image {
+  -moz-image-region: rect(0, 112px, 16px, 96px);
+}
+.tabbrowser-tab[busy][progress="7"] > .tab-icon-image {
+  -moz-image-region: rect(0, 128px, 16px, 112px);
+}
+.tabbrowser-tab[busy][progress="8"] > .tab-icon-image {
+  -moz-image-region: rect(0, 144px, 16px, 128px);
 }
 
 .tabs-bottom {
   border-bottom: 1px solid threedshadow;
 }
 
 #context_newTab {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
new file mode 100644
--- /dev/null
+++ b/browser/themes/gnomestripe/browser/fullscreen-video.css
@@ -0,0 +1,8 @@
+#close {
+  position: absolute;
+  top: 0;
+  right: 0;
+  width: 32px;
+  height: 32px;
+  background: url(KUI-close.png) center center no-repeat;
+}
--- a/browser/themes/gnomestripe/browser/jar.mn
+++ b/browser/themes/gnomestripe/browser/jar.mn
@@ -3,16 +3,17 @@ browser.jar:
 % override chrome://global/skin/icons/warning-16.png moz-icon://stock/gtk-dialog-warning?size=menu
   skin/classic/browser/sanitizeDialog.css             (sanitizeDialog.css)
 * skin/classic/browser/aboutPrivateBrowsing.css             (aboutPrivateBrowsing.css)
 * skin/classic/browser/aboutSessionRestore.css        (aboutSessionRestore.css)
   skin/classic/browser/aboutSessionRestore-window-icon.png
   skin/classic/browser/aboutCertError.css             (aboutCertError.css)
 * skin/classic/browser/browser.css                    (browser.css)
 * skin/classic/browser/engineManager.css              (engineManager.css)
+  skin/classic/browser/fullscreen-video.css
   skin/classic/browser/Geo.png
   skin/classic/browser/Go-arrow.png
   skin/classic/browser/identity.png
   skin/classic/browser/Info.png
   skin/classic/browser/KUI-close.png
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
 * skin/classic/browser/pageInfo.css
@@ -54,9 +55,11 @@ browser.jar:
   skin/classic/browser/places/toolbarDropMarker.png   (places/toolbarDropMarker.png)
   skin/classic/browser/places/unsortedBookmarks.png   (places/unsortedBookmarks.png)
   skin/classic/browser/preferences/alwaysAsk.png      (preferences/alwaysAsk.png)
   skin/classic/browser/preferences/mail.png           (preferences/mail.png)
   skin/classic/browser/preferences/Options.png        (preferences/Options.png)
 * skin/classic/browser/preferences/preferences.css    (preferences/preferences.css)
   skin/classic/browser/preferences/applications.css   (preferences/applications.css)
   skin/classic/browser/tabbrowser/alltabs.png          (tabbrowser/alltabs.png)
+  skin/classic/browser/tabbrowser/progress.png         (tabbrowser/progress.png)
+  skin/classic/browser/tabbrowser/progress-pulsing.png (tabbrowser/progress-pulsing.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3c66ed3c8e9fffbf428441b8015217ea2f575776
GIT binary patch
literal 10429
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
Sv(xa0-&B>f6yGUWh5ZNL!5OIl
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b8bd2efe554ea9d42d6c4a489e0a3a15e620521f
GIT binary patch
literal 2088
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
SX?6Jk0000<MNUMnLSTZ@*b?;s
index 9bbfe10662ee4c540666d196565e09702b06ddd1..31167bd90a3b806a4dfd3ad04cccf1cc9811ca72
GIT binary patch
literal 34227
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