Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Thu, 01 Mar 2012 13:45:48 -0800
changeset 105911 f977d96263c2bbf35d4308c576feb7cce22c665e
parent 105910 7d6da2d655957746cf5ccbb3426b7ba65706634f (current diff)
parent 88053 3a7b9e61c26342f4fa46deb7f37cc6f6b389c00a (diff)
child 105912 3a1754a676440e0087bbbe9f20e3adfac0abbfeb
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherderautoland@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
accessible/src/base/nsTextAttrs.cpp
accessible/src/base/nsTextAttrs.h
accessible/src/html/nsHyperTextAccessible.h
accessible/src/msaa/CAccessibleText.cpp
accessible/tests/mochitest/events/Makefile.in
accessible/tests/mochitest/events/test_textattrchange.html
b2g/installer/package-manifest.in
browser/app/profile/firefox.js
browser/base/content/aboutSyncTabs-bindings.xml
browser/base/content/aboutSyncTabs.css
browser/base/content/aboutSyncTabs.js
browser/base/content/aboutSyncTabs.xul
browser/base/content/nsContextMenu.js
browser/base/content/sync/addDevice.js
browser/base/content/sync/addDevice.xul
browser/base/content/sync/notification.xml
browser/base/content/sync/setup.js
browser/base/content/sync/setup.xul
browser/base/content/syncAddDevice.js
browser/base/content/syncAddDevice.xul
browser/base/content/syncGenericChange.js
browser/base/content/syncGenericChange.xul
browser/base/content/syncKey.xhtml
browser/base/content/syncNotification.xml
browser/base/content/syncProgress.js
browser/base/content/syncProgress.xhtml
browser/base/content/syncQuota.js
browser/base/content/syncQuota.xul
browser/base/content/syncSetup.js
browser/base/content/syncSetup.xul
browser/base/content/syncUtils.js
browser/base/content/tabbrowser.xml
browser/base/jar.mn
browser/components/nsBrowserGlue.js
browser/components/places/tests/unit/test_placesTxn.js
browser/components/places/tests/unit/test_txnGUIDs.js
browser/components/preferences/sync.js
browser/components/preferences/sync.xul
browser/locales/en-US/chrome/browser/browser.properties
build/mobile/devicemanager-run-test.py
build/mobile/devicemanagerADB.py
caps/src/nsSecurityManagerFactory.cpp
content/base/public/nsContentUtils.h
content/base/public/nsDOMFile.h
content/base/src/nsAttrValue.cpp
content/base/src/nsContentAreaDragDrop.cpp
content/base/src/nsContentSink.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDOMAttribute.cpp
content/base/src/nsDOMAttributeMap.cpp
content/base/src/nsDocument.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/base/src/nsObjectLoadingContent.cpp
content/base/src/nsObjectLoadingContent.h
content/base/src/nsStyleLinkElement.cpp
content/canvas/src/CustomQS_Canvas2D.h
content/canvas/src/CustomQS_WebGL.h
content/canvas/src/WebGLContext.h
content/canvas/test/webgl/test_webgl_conformance_test_suite.html
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLLinkElement.cpp
content/html/content/src/nsHTMLStyleElement.cpp
content/html/document/src/nsHTMLDocument.cpp
content/media/VideoUtils.cpp
content/media/nsBuiltinDecoderReader.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/nsMediaCache.cpp
content/media/ogg/nsOggCodecState.cpp
content/media/ogg/nsOggCodecState.h
content/media/wave/nsWaveReader.cpp
content/media/webm/nsWebMReader.h
content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
content/svg/content/src/nsSVGAngle.cpp
content/svg/content/src/nsSVGBoolean.cpp
content/svg/content/src/nsSVGElement.h
content/svg/content/src/nsSVGEnum.cpp
content/svg/content/src/nsSVGFilterElement.cpp
content/svg/content/src/nsSVGFilterElement.h
content/svg/content/src/nsSVGFilters.cpp
content/svg/content/src/nsSVGFilters.h
content/svg/content/src/nsSVGForeignObjectElement.cpp
content/svg/content/src/nsSVGForeignObjectElement.h
content/svg/content/src/nsSVGImageElement.cpp
content/svg/content/src/nsSVGImageElement.h
content/svg/content/src/nsSVGInteger.cpp
content/svg/content/src/nsSVGIntegerPair.cpp
content/svg/content/src/nsSVGLength2.cpp
content/svg/content/src/nsSVGMarkerElement.cpp
content/svg/content/src/nsSVGMarkerElement.h
content/svg/content/src/nsSVGMaskElement.cpp
content/svg/content/src/nsSVGMaskElement.h
content/svg/content/src/nsSVGNumber2.cpp
content/svg/content/src/nsSVGNumberPair.cpp
content/svg/content/src/nsSVGPatternElement.cpp
content/svg/content/src/nsSVGPatternElement.h
content/svg/content/src/nsSVGRectElement.cpp
content/svg/content/src/nsSVGSVGElement.cpp
content/svg/content/src/nsSVGSVGElement.h
content/svg/content/src/nsSVGStyleElement.cpp
content/svg/content/src/nsSVGUseElement.cpp
content/svg/content/src/nsSVGUseElement.h
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLProtoImplField.h
content/xbl/src/nsXBLProtoImplProperty.h
content/xbl/src/nsXBLPrototypeHandler.cpp
content/xslt/src/base/txStringUtils.h
content/xslt/src/xpath/txExprParser.cpp
content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp
content/xslt/src/xslt/txMozillaXMLOutput.cpp
dom/Makefile.in
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIScriptContext.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
dom/dom-config.mk
dom/indexedDB/IDBCursor.cpp
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBKeyRange.cpp
dom/indexedDB/IDBTransaction.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/system/NetworkGeolocationProvider.js
dom/workers/Events.cpp
dom/workers/Exceptions.cpp
dom/workers/File.cpp
dom/workers/Location.cpp
dom/workers/Navigator.cpp
dom/workers/RuntimeService.cpp
dom/workers/ScriptLoader.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerScope.cpp
dom/workers/XMLHttpRequest.cpp
dom/workers/XMLHttpRequestPrivate.cpp
gfx/src/nsDeviceContext.cpp
gfx/src/nsFontMetrics.cpp
gfx/thebes/gfxASurface.cpp
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxPlatformGtk.cpp
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxScriptItemizer.h
gfx/thebes/gfxXlibSurface.cpp
image/src/RasterImage.cpp
ipc/testshell/TestShellParent.cpp
ipc/testshell/XPCShellEnvironment.cpp
js/ipc/ObjectWrapperParent.cpp
js/jsd/jsd_val.c
js/jsd/jsd_xpc.cpp
js/src/Makefile.in
js/src/MemoryMetrics.cpp
js/src/ctypes/Library.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SemanticAnalysis.cpp
js/src/gc/Statistics.h
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi-tests/testDebugger.cpp
js/src/jsapi-tests/testVersion.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jsbool.cpp
js/src/jsclass.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jscompat.h
js/src/jsdate.cpp
js/src/jsdate.h
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcinlines.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jspropertycache.cpp
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsreflect.cpp
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jsweakmap.cpp
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/shell/jsoptparse.cpp
js/src/shell/jsworkers.cpp
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/XPCCallContext.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCQuickStubs.h
js/xpconnect/src/XPCThrower.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeInfo.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/XPCWrapper.cpp
js/xpconnect/src/dom_quickstubs.qsconf
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/qsgen.py
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/CrossOriginWrapper.cpp
js/xpconnect/wrappers/CrossOriginWrapper.h
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/FilteringWrapper.h
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/WrapperFactory.h
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
layout/base/nsBidiPresUtils.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsDisplayList.cpp
layout/base/nsPresContext.cpp
layout/build/Makefile.in
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsHTMLCanvasFrame.h
layout/generic/nsSubDocumentFrame.cpp
layout/reftests/svg/reftest.list
layout/reftests/svg/smil/reftest.list
layout/style/nsDOMMediaQueryList.cpp
layout/style/nsDOMMediaQueryList.h
layout/svg/base/src/nsSVGImageFrame.cpp
layout/svg/base/src/nsSVGUseFrame.cpp
layout/svg/base/src/nsSVGUtils.cpp
mfbt/StdInt.h
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
modules/libpref/src/init/all.js
netwerk/base/src/nsSocketTransport2.cpp
netwerk/cache/nsCacheService.cpp
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/components/telemetry/TelemetryPing.js
toolkit/content/license.html
widget/xpwidgets/nsIdleService.cpp
xpcom/ds/nsAtomTable.cpp
xpcom/ds/nsCheapSets.h
xpcom/ds/nsHashSets.cpp
xpcom/ds/nsHashSets.h
xpcom/ds/nsIAtom.idl
xpcom/io/nsLocalFileWin.cpp
--- a/accessible/src/atk/nsMaiInterfaceText.cpp
+++ b/accessible/src/atk/nsMaiInterfaceText.cpp
@@ -38,16 +38,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsMaiInterfaceText.h"
 
 #include "nsHyperTextAccessible.h"
 #include "nsRoleMap.h"
 
+#include "nsIPersistentProperties2.h"
+
 AtkAttributeSet* ConvertToAtkAttributeSet(nsIPersistentProperties* aAttributes);
 
 void
 textInterfaceInitCB(AtkTextIface *aIface)
 {
     NS_ASSERTION(aIface, "Invalid aIface");
     if (!aIface)
         return;
--- a/accessible/src/base/StyleInfo.cpp
+++ b/accessible/src/base/StyleInfo.cpp
@@ -107,19 +107,27 @@ StyleInfo::Margin(css::Side aSide, nsASt
   aValue.Truncate();
 
   nscoord coordVal = mElement->GetPrimaryFrame()->GetUsedMargin().Side(aSide);
   aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
   aValue.AppendLiteral("px");
 }
 
 void
-StyleInfo::Format(const nscolor& aValue, nsString& aFormattedValue)
+StyleInfo::FormatColor(const nscolor& aValue, nsString& aFormattedValue)
 {
   // Combine the string like rgb(R, G, B) from nscolor.
   aFormattedValue.AppendLiteral("rgb(");
   aFormattedValue.AppendInt(NS_GET_R(aValue));
   aFormattedValue.AppendLiteral(", ");
   aFormattedValue.AppendInt(NS_GET_G(aValue));
   aFormattedValue.AppendLiteral(", ");
   aFormattedValue.AppendInt(NS_GET_B(aValue));
   aFormattedValue.Append(')');
 }
+
+void
+StyleInfo::FormatFontStyle(const nscoord& aValue, nsAString& aFormattedValue)
+{
+  nsCSSKeyword keyword =
+    nsCSSProps::ValueToKeywordEnum(aValue, nsCSSProps::kFontStyleKTable);
+  AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(keyword), aFormattedValue);
+}
--- a/accessible/src/base/StyleInfo.h
+++ b/accessible/src/base/StyleInfo.h
@@ -55,17 +55,18 @@ public:
   void Display(nsAString& aValue);
   void TextAlign(nsAString& aValue);
   void TextIndent(nsAString& aValue);
   void MarginLeft(nsAString& aValue) { Margin(css::eSideLeft, aValue); }
   void MarginRight(nsAString& aValue) { Margin(css::eSideRight, aValue); }
   void MarginTop(nsAString& aValue) { Margin(css::eSideTop, aValue); }
   void MarginBottom(nsAString& aValue) { Margin(css::eSideBottom, aValue); }
 
-  static void Format(const nscolor& aValue, nsString& aFormattedValue);
+  static void FormatColor(const nscolor& aValue, nsString& aFormattedValue);
+  static void FormatFontStyle(const nscoord& aValue, nsAString& aFormattedValue);
 
 private:
   StyleInfo() MOZ_DELETE;
   StyleInfo(const StyleInfo&) MOZ_DELETE;
   StyleInfo& operator = (const StyleInfo&) MOZ_DELETE;
 
   void Margin(css::Side aSide, nsAString& aValue);
 
--- a/accessible/src/base/nsTextAttrs.cpp
+++ b/accessible/src/base/nsTextAttrs.cpp
@@ -69,18 +69,16 @@ struct nsCSSTextAttrMapItem
  * The map of CSS properties to text attributes.
  */
 const char* const kAnyValue = nsnull;
 const char* const kCopyValue = nsnull;
 
 static nsCSSTextAttrMapItem gCSSTextAttrsMap[] =
 {
   // CSS name            CSS value        Attribute name                                Attribute value
-  { "font-family",       kAnyValue,       &nsGkAtoms::font_family,            kCopyValue },
-  { "font-style",        kAnyValue,       &nsGkAtoms::font_style,             kCopyValue },
   { "text-decoration",   "line-through",  &nsGkAtoms::textLineThroughStyle,  "solid" },
   { "text-decoration",   "underline",     &nsGkAtoms::textUnderlineStyle,    "solid" },
   { "vertical-align",    kAnyValue,       &nsGkAtoms::textPosition,          kCopyValue }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsTextAttrs
 
@@ -150,53 +148,53 @@ nsTextAttrsMgr::GetAttributes(nsIPersist
     offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode);
     frame = offsetElm->GetPrimaryFrame();
   }
 
   nsTArray<nsITextAttr*> textAttrArray(10);
 
   // "language" text attribute
   nsLangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&langTextAttr));
-
-  // "font-family" text attribute
-  nsCSSTextAttr fontFamilyTextAttr(0, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontFamilyTextAttr));
-
-  // "font-style" text attribute
-  nsCSSTextAttr fontStyleTextAttr(1, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontStyleTextAttr));
+  textAttrArray.AppendElement(&langTextAttr);
 
   // "text-line-through-style" text attribute
-  nsCSSTextAttr lineThroughTextAttr(2, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&lineThroughTextAttr));
+  nsCSSTextAttr lineThroughTextAttr(0, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(&lineThroughTextAttr);
 
   // "text-underline-style" text attribute
-  nsCSSTextAttr underlineTextAttr(3, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&underlineTextAttr));
+  nsCSSTextAttr underlineTextAttr(1, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(&underlineTextAttr);
 
   // "text-position" text attribute
-  nsCSSTextAttr posTextAttr(4, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&posTextAttr));
+  nsCSSTextAttr posTextAttr(2, hyperTextElm, offsetElm);
+  textAttrArray.AppendElement(&posTextAttr);
 
   // "background-color" text attribute
   nsBGColorTextAttr bgColorTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&bgColorTextAttr));
+  textAttrArray.AppendElement(&bgColorTextAttr);
 
   // "color" text attribute
   ColorTextAttr colorTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&colorTextAttr));
+  textAttrArray.AppendElement(&colorTextAttr);
+
+  // "font-family" text attribute
+  FontFamilyTextAttr fontFamilyTextAttr(rootFrame, frame);
+  textAttrArray.AppendElement(&fontFamilyTextAttr);
 
   // "font-size" text attribute
   nsFontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontSizeTextAttr));
+  textAttrArray.AppendElement(&fontSizeTextAttr);
+
+  // "font-style" text attribute
+  FontStyleTextAttr fontStyleTextAttr(rootFrame, frame);
+  textAttrArray.AppendElement(&fontStyleTextAttr);
 
   // "font-weight" text attribute
   nsFontWeightTextAttr fontWeightTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontWeightTextAttr));
+  textAttrArray.AppendElement(&fontWeightTextAttr);
 
   // Expose text attributes if applicable.
   if (aAttributes) {
     PRUint32 len = textAttrArray.Length();
     for (PRUint32 idx = 0; idx < len; idx++) {
       nsITextAttr *textAttr = textAttrArray[idx];
 
       nsAutoString value;
@@ -386,17 +384,17 @@ nsBGColorTextAttr::GetValueFor(nsIConten
 
   return GetColor(frame, aValue);
 }
 
 void
 nsBGColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
 {
   nsAutoString value;
-  StyleInfo::Format(aValue, value);
+  StyleInfo::FormatColor(aValue, value);
   aFormattedValue = value;
 }
 
 bool
 nsBGColorTextAttr::GetColor(nsIFrame *aFrame, nscolor *aColor)
 {
   const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
 
@@ -448,22 +446,66 @@ ColorTextAttr::GetValueFor(nsIContent* a
 
   return false;
 }
 
 void
 ColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
 {
   nsAutoString value;
-  StyleInfo::Format(aValue, value);
+  StyleInfo::FormatColor(aValue, value);
   aFormattedValue = value;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
+// FontFamilyTextAttr
+////////////////////////////////////////////////////////////////////////////////
+
+FontFamilyTextAttr::FontFamilyTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  nsTextAttr<nsAutoString>(aFrame == nsnull)
+{
+  mIsRootDefined = GetFontFamily(aRootFrame, mRootNativeValue);
+
+  if (aFrame)
+    mIsDefined = GetFontFamily(aFrame, mNativeValue);
+}
+
+bool
+FontFamilyTextAttr::GetValueFor(nsIContent* aElm, nsAutoString* aValue)
+{
+  nsIFrame* frame = aElm->GetPrimaryFrame();
+  if (!frame)
+    return false;
+
+  return GetFontFamily(frame, *aValue);
+}
+
+void
+FontFamilyTextAttr::Format(const nsAutoString& aValue,
+                           nsAString& aFormattedValue)
+{
+  aFormattedValue = aValue;
+}
+
+bool
+FontFamilyTextAttr::GetFontFamily(nsIFrame* aFrame, nsAutoString& aFamily)
+{
+  nsRefPtr<nsFontMetrics> fm;
+  nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
+
+  gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
+  gfxFont* font = fontGroup->GetFontAt(0);
+  gfxFontEntry* fontEntry = font->GetFontEntry();
+  aFamily = fontEntry->FamilyName();
+  return true;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
 // nsFontSizeTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
   nsTextAttr<nscoord>(aFrame == nsnull)
 {
   mDC = aRootFrame->PresContext()->DeviceContext();
 
@@ -477,29 +519,29 @@ nsFontSizeTextAttr::nsFontSizeTextAttr(n
 }
 
 bool
 nsFontSizeTextAttr::GetValueFor(nsIContent *aContent, nscoord *aValue)
 {
   nsIFrame *frame = aContent->GetPrimaryFrame();
   if (!frame)
     return false;
-  
+
   *aValue = GetFontSize(frame);
   return true;
 }
 
 void
 nsFontSizeTextAttr::Format(const nscoord& aValue, nsAString& aFormattedValue)
 {
   // Convert from nscoord to pt.
   //
   // Note: according to IA2, "The conversion doesn't have to be exact.
   // The intent is to give the user a feel for the size of the text."
-  // 
+  //
   // ATK does not specify a unit and will likely follow IA2 here.
   //
   // XXX todo: consider sharing this code with layout module? (bug 474621)
   float px =
     NSAppUnitsToFloatPixels(aValue, nsDeviceContext::AppUnitsPerCSSPixel());
   // Each pt is 4/3 of a CSS pixel.
   int pts = NS_lround(px*3/4);
 
@@ -512,16 +554,51 @@ nsFontSizeTextAttr::Format(const nscoord
 nscoord
 nsFontSizeTextAttr::GetFontSize(nsIFrame *aFrame)
 {
   return aFrame->GetStyleFont()->mSize;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
+// FontStyleTextAttr
+////////////////////////////////////////////////////////////////////////////////
+
+FontStyleTextAttr::FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  nsTextAttr<nscoord>(!aFrame)
+{
+  mRootNativeValue = aRootFrame->GetStyleFont()->mFont.style;
+  mIsRootDefined = true;
+
+  if (aFrame) {
+    mNativeValue = aFrame->GetStyleFont()->mFont.style;
+    mIsDefined = true;
+  }
+}
+
+bool
+FontStyleTextAttr::GetValueFor(nsIContent* aContent, nscoord* aValue)
+{
+  nsIFrame* frame = aContent->GetPrimaryFrame();
+  if (frame) {
+    *aValue = frame->GetStyleFont()->mFont.style;
+    return true;
+  }
+
+  return false;
+}
+
+void
+FontStyleTextAttr::Format(const nscoord& aValue, nsAString& aFormattedValue)
+{
+  StyleInfo::FormatFontStyle(aValue, aFormattedValue);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
 // nsFontWeightTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 nsFontWeightTextAttr::nsFontWeightTextAttr(nsIFrame *aRootFrame,
                                            nsIFrame *aFrame) :
   nsTextAttr<PRInt32>(aFrame == nsnull)
 {
   mRootNativeValue = GetFontWeight(aRootFrame);
--- a/accessible/src/base/nsTextAttrs.h
+++ b/accessible/src/base/nsTextAttrs.h
@@ -36,27 +36,20 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsTextAttrs_h_
 #define nsTextAttrs_h_
 
 class nsHyperTextAccessible;
 
-
-#include "nsIDOMNode.h"
-#include "nsIDOMElement.h"
-
 #include "nsIContent.h"
 #include "nsIFrame.h"
 #include "nsIPersistentProperties2.h"
 
-#include "nsCOMPtr.h"
-#include "nsString.h"
-
 class nsITextAttr;
 
 /**
  * Used to expose text attributes for the hyper text accessible (see
  * nsHyperTextAccessible class). It is indended for the work with 'language' and
  * CSS based text attributes.
  *
  * @note "invalid: spelling" text attrbiute is implemented entirerly in
@@ -95,17 +88,16 @@ public:
    * @param aStartHTOffset [out, optional] start hyper text offset
    * @param aEndHTOffset   [out, optional] end hyper text offset
    */
   nsresult GetAttributes(nsIPersistentProperties *aAttributes,
                          PRInt32 *aStartHTOffset = nsnull,
                          PRInt32 *aEndHTOffset = nsnull);
 
 protected:
-
   /**
    * Calculates range (start and end offsets) of text where the text attributes
    * are stretched. New offsets may be smaller if one of text attributes changes
    * its value before or after the given offsets.
    *
    * @param aTextAttrArray  [in] text attributes array
    * @param aStartHTOffset  [in, out] the start offset
    * @param aEndHTOffset    [in, out] the end offset
@@ -322,16 +314,40 @@ public:
 protected:
   // nsTextAttr
   virtual bool GetValueFor(nsIContent* aContent, nscolor* aValue);
   virtual void Format(const nscolor& aValue, nsAString& aFormattedValue);
 };
 
 
 /**
+ * Class is used for the work with "font-family" text attribute in
+ * nsTextAttrsMgr class.
+ */
+class FontFamilyTextAttr : public nsTextAttr<nsAutoString>
+{
+public:
+  FontFamilyTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+
+  // nsITextAttr
+  virtual nsIAtom* GetName() const { return nsGkAtoms::font_family; }
+
+protected:
+
+  // nsTextAttr
+  virtual bool GetValueFor(nsIContent* aContent, nsAutoString* aValue);
+  virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
+
+private:
+
+  bool GetFontFamily(nsIFrame* aFrame, nsAutoString& aFamily);
+};
+
+
+/**
  * Class is used for the work with "font-size" text attribute in nsTextAttrsMgr
  * class.
  */
 class nsFontSizeTextAttr : public nsTextAttr<nscoord>
 {
 public:
   nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
 
@@ -354,16 +370,36 @@ private:
    */
    nscoord GetFontSize(nsIFrame *aFrame);
 
   nsDeviceContext *mDC;
 };
 
 
 /**
+ * Class is used for the work with "font-style" text attribute in nsTextAttrsMgr
+ * class.
+ */
+class FontStyleTextAttr : public nsTextAttr<nscoord>
+{
+public:
+  FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+
+  // nsITextAttr
+  virtual nsIAtom* GetName() const { return nsGkAtoms::font_style; }
+
+protected:
+
+  // nsTextAttr
+  virtual bool GetValueFor(nsIContent* aContent, nscoord* aValue);
+  virtual void Format(const nscoord &aValue, nsAString &aFormattedValue);
+};
+
+
+/**
  * Class is used for the work with "font-weight" text attribute in
  * nsTextAttrsMgr class.
  */
 class nsFontWeightTextAttr : public nsTextAttr<PRInt32>
 {
 public:
   nsFontWeightTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
 
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -41,17 +41,16 @@
 #define _nsHyperTextAccessible_H_
 
 #include "nsIAccessibleText.h"
 #include "nsIAccessibleHyperText.h"
 #include "nsIAccessibleEditableText.h"
 
 #include "AccCollector.h"
 #include "nsAccessibleWrap.h"
-#include "nsTextAttrs.h"
 
 #include "nsFrameSelection.h"
 #include "nsISelectionController.h"
 
 enum EGetTextType { eGetBefore=-1, eGetAt=0, eGetAfter=1 };
 
 // This character marks where in the text returned via nsIAccessibleText(),
 // that embedded object characters exist
--- a/accessible/src/msaa/CAccessibleText.cpp
+++ b/accessible/src/msaa/CAccessibleText.cpp
@@ -40,16 +40,18 @@
 
 #include "CAccessibleText.h"
 
 #include "Accessible2.h"
 #include "AccessibleText_i.c"
 
 #include "nsHyperTextAccessible.h"
 
+#include "nsIPersistentProperties2.h"
+
 // IUnknown
 
 STDMETHODIMP
 CAccessibleText::QueryInterface(REFIID iid, void** ppv)
 {
   *ppv = NULL;
 
   if (IID_IAccessibleText == iid) {
--- a/accessible/tests/mochitest/attributes.js
+++ b/accessible/tests/mochitest/attributes.js
@@ -203,38 +203,71 @@ const kNormalFontWeight =
 
 const kBoldFontWeight =
   function equalsToBold(aWeight) { return aWeight > 400; }
 
 // The pt font size of the input element can vary by Linux distro.
 const kInputFontSize = WIN ?
   "10pt" : (MAC ? "8pt" : function() { return true; });
 
+const kAbsentFontFamily =
+  function(aFontFamily) { return aFontFamily != "sans-serif"; }
+const kInputFontFamily =
+  function(aFontFamily) { return aFontFamily != "sans-serif"; }
+
+const kMonospaceFontFamily =
+  function(aFontFamily) { return aFontFamily != "monospace"; }
+const kSansSerifFontFamily =
+  function(aFontFamily) { return aFontFamily != "sans-serif"; }
+const kSerifFontFamily =
+  function(aFontFamily) { return aFontFamily != "serif"; }
+
+const kCursiveFontFamily = WIN ? "Comic Sans MS" :
+  (LINUX ? "DejaVu Serif" : "MacFont");
+
+/**
+ * Return used font from the given computed style.
+ */
+function fontFamily(aComputedStyle)
+{
+  var name = aComputedStyle.fontFamily;
+  switch (name) {
+    case "monospace":
+      return kMonospaceFontFamily;
+    case "sans-serif":
+      return kSansSerifFontFamily;
+    case "serif":
+      return kSerifFontFamily;
+    default:
+      return name;
+  }
+}
+
 /**
  * Build an object of default text attributes expected for the given accessible.
  *
  * @param aID          [in] identifier of accessible
  * @param aFontSize    [in] font size
  * @param aFontWeight  [in, optional] kBoldFontWeight or kNormalFontWeight,
  *                      default value is kNormalFontWeight
  */
-function buildDefaultTextAttrs(aID, aFontSize, aFontWeight)
+function buildDefaultTextAttrs(aID, aFontSize, aFontWeight, aFontFamily)
 {
   var elm = getNode(aID);
   var computedStyle = document.defaultView.getComputedStyle(elm, "");
   var bgColor = computedStyle.backgroundColor == "transparent" ?
     "rgb(255, 255, 255)" : computedStyle.backgroundColor;
 
   var defAttrs = {
     "font-style": computedStyle.fontStyle,
     "font-size": aFontSize,
     "background-color": bgColor,
     "font-weight": aFontWeight ? aFontWeight : kNormalFontWeight,
     "color": computedStyle.color,
-    "font-family": computedStyle.fontFamily,
+    "font-family": aFontFamily ? aFontFamily : fontFamily(computedStyle),
     "text-position": computedStyle.verticalAlign
   };
 
   return defAttrs;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Private.
--- a/accessible/tests/mochitest/attributes/test_text.html
+++ b/accessible/tests/mochitest/attributes/test_text.html
@@ -258,17 +258,17 @@
       testTextAttrs(ID, 45, attrs, defAttrs, 44, 61);
 
       attrs = {};
       testTextAttrs(ID, 62, attrs, defAttrs, 61, 69);
 
       // Walk from span with font-style to the one with font-family.
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = { "font-family": gComputedStyle.fontFamily };
+      attrs = { "font-family": kMonospaceFontFamily };
       testTextAttrs(ID, 70, attrs, defAttrs, 69, 83);
 
       attrs = {};
       testTextAttrs(ID, 84, attrs, defAttrs, 83, 91);
 
       attrs = { "text-underline-style": "solid" };
       testTextAttrs(ID, 92, attrs, defAttrs, 91, 101);
 
@@ -276,16 +276,17 @@
       testTextAttrs(ID, 102, attrs, defAttrs, 101, 109);
 
       attrs = { "text-line-through-style": "solid" };
       testTextAttrs(ID, 110, attrs, defAttrs, 109, 122);
 
       attrs = {};
       testTextAttrs(ID, 123, attrs, defAttrs, 122, 130);
 
+      //////////////////////////////////////////////////////////////////////////
       // area10, different single style spans in non-styled paragraph
       ID = "area10";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
       testDefaultTextAttrs(ID, defAttrs);
 
       attrs = {};
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
 
@@ -311,17 +312,17 @@
       testTextAttrs(ID, 46, attrs, defAttrs, 45, 62);
 
       attrs = {};
       testTextAttrs(ID, 63, attrs, defAttrs, 62, 70);
 
       // Walk from span with font-style to the one with font-family.
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"font-family": gComputedStyle.fontFamily};
+      attrs = { "font-family": kMonospaceFontFamily };
       testTextAttrs(ID, 71, attrs, defAttrs, 70, 84);
 
       attrs = {};
       testTextAttrs(ID, 85, attrs, defAttrs, 84, 92);
 
       attrs = { "text-underline-style": "solid" };
       testTextAttrs(ID, 93, attrs, defAttrs, 92, 102);
 
@@ -329,16 +330,17 @@
       testTextAttrs(ID, 103, attrs, defAttrs, 102, 110);
 
       attrs = { "text-line-through-style": "solid" };
       testTextAttrs(ID, 111, attrs, defAttrs, 110, 123);
 
       attrs = {};
       testTextAttrs(ID, 124, attrs, defAttrs, 123, 131);
 
+      //////////////////////////////////////////////////////////////////////////
       // area11, "font-weight" tests
       ID = "area11";
       defAttrs = buildDefaultTextAttrs(ID, "12pt", kBoldFontWeight);
       testDefaultTextAttrs(ID, defAttrs);
 
       attrs = { };
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 13);
 
@@ -368,17 +370,18 @@
       //////////////////////////////////////////////////////////////////////////
       // test zero offset on empty hypertext accessibles
       ID = "area13";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
       attrs = { };
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 0);
 
       ID = "area14";
-      defAttrs = buildDefaultTextAttrs(ID, kInputFontSize);
+      defAttrs = buildDefaultTextAttrs(ID, kInputFontSize,
+                                       kNormalFontWeight, kInputFontFamily);
 
       attrs = { };
       testTextAttrs(ID, 0, attrs, defAttrs, 0, 0);
 
       //////////////////////////////////////////////////////////////////////////
       // area15, embed char tests, "*plain*plain**bold*bold*"
       ID = "area15";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
@@ -399,29 +402,64 @@
       // p
       testTextAttrs(ID, 18, { }, { }, 18, 19);
       // bold
       attrs = { "font-weight": kBoldFontWeight };
       testTextAttrs(ID, 19, attrs, defAttrs, 19, 23);
       // p
       testTextAttrs(ID, 23, { }, { }, 23, 24);
 
+      //////////////////////////////////////////////////////////////////////////
+      // area16, "font-family" tests
+      ID = "area16";
+      defAttrs = buildDefaultTextAttrs(ID, "12pt");
+      testDefaultTextAttrs(ID, defAttrs);
+
+      attrs = { "font-family": kMonospaceFontFamily };
+      testTextAttrs(ID, 0, attrs, defAttrs, 0, 4);
+
+      attrs = { };
+      testTextAttrs(ID, 4, attrs, defAttrs, 4, 9);
+
+      attrs = { "font-family": kSerifFontFamily };
+      testTextAttrs(ID, 9, attrs, defAttrs, 9, 13);
+
+      attrs = { };
+      testTextAttrs(ID, 13, attrs, defAttrs, 13, 18);
+
+      attrs = { "font-family": kAbsentFontFamily };
+      testTextAttrs(ID, 18, attrs, defAttrs, 18, 22);
+
+      attrs = { };
+      testTextAttrs(ID, 22, attrs, defAttrs, 22, 27);
+
+      attrs = { "font-family": kCursiveFontFamily };
+      testTextAttrs(ID, 27, attrs, defAttrs, 27, 31);
+
+      attrs = { };
+      testTextAttrs(ID, 31, attrs, defAttrs, 31, 45);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body style="font-size: 12pt">
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=345759"
      title="Implement text attributes">
     Mozilla Bug 345759
+  </a><br>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=473576"
+     title="font-family text attribute should expose actual font used">
+    Mozilla Bug 473576
   </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <p id="area1" style="font-size: smaller">Normal <b>Bold</b> Normal</p>
   <p id="area2" style="font-size: 120%">Normal <b>Bold <i>Italic </i>Bold</b> Normal</p>
@@ -464,26 +502,26 @@
       <span style="color: magenta">Magenta<b>Bold</b>Magenta</span>
     </span>
   </p>
 
   <p id="area9" style="font-size: smaller">Small
     <span style="font-size: 120%">bigger</span> smaller
     <span style="background-color: blue;">background blue</span> normal
     <span style="font-style: italic;">Different styling</span> normal
-    <span style="font-family: tahoma;">Different font</span> normal
+    <span style="font-family: monospace;">Different font</span> normal
     <span style="text-decoration: underline;">underlined</span> normal
     <span style="text-decoration: line-through;">strikethrough</span> normal
   </p>
 
   <p id="area10">Normal
     <span style="font-size: 120%">bigger</span> smaller
     <span style="background-color: blue;">background blue</span> normal
     <span style="font-style: italic;">Different styling</span> normal
-    <span style="font-family: tahoma;">Different font</span> normal
+    <span style="font-family: monospace;">Different font</span> normal
     <span style="text-decoration: underline;">underlined</span> normal
     <span style="text-decoration: line-through;">strikethrough</span> normal
   </p>
 
   <p id="area11" style="font-weight: bolder;">
     <span style="font-weight: bolder;">bolder</span>bolder
     <span style="font-weight: lighter;">lighter</span>bolder
     <span style="font-weight: normal;">normal</span>bolder
@@ -495,10 +533,18 @@
   </p>
 
   <p id="area12">hello</p>
   <p id="area13"></p>
   <input id="area14">
 
   <!-- *plain*plain**bold*bold*-->
   <div id="area15"><p>embed</p>plain<p>embed</p>plain<p>embed</p><img src="../moz.png" alt="image"/><b>bold</b><p>embed</p><b>bold</b><p>embed</p></div>
+
+  <p id="area16" style="font-family: sans-serif;">
+    <span style="font-family: monospace;">text</span>text
+    <span style="font-family: serif;">text</span>text
+    <span style="font-family: BodoniThatDoesntExist;">text</span>text
+    <span style="font-family: Comic Sans MS, cursive;">text</span>text
+    <span style="font-family: sans-serif, fantasy;">text</span>text
+  </p>
 </body>
 </html>
--- a/accessible/tests/mochitest/events/Makefile.in
+++ b/accessible/tests/mochitest/events/Makefile.in
@@ -60,16 +60,17 @@ include $(topsrcdir)/config/rules.mk
 		test_contextmenu.html \
 		test_docload.html \
 		test_docload.xul \
 		test_dragndrop.html \
 		test_flush.html \
 		test_focus_aria_activedescendant.html \
 		test_focus_autocomplete.xul \
 		test_focus_browserui.xul \
+		test_focus_canvas.html \
 		test_focus_contextmenu.xul \
 		test_focus_controls.html \
 		test_focus_dialog.html \
 		test_focus_doc.html \
 		test_focus_general.html \
 		test_focus_general.xul \
 		test_focus_listcontrols.xul \
 		test_focus_menu.xul \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/events/test_focus_canvas.html
@@ -0,0 +1,59 @@
+<html>
+
+<head>
+  <title>Accessible focus testing in canvas subdom</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+  <script type="application/javascript"
+          src="../states.js"></script>
+
+  <script type="application/javascript">
+    //gA11yEventDumpToConsole = true;
+
+    var gQueue = null;
+    function doTests()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new synthFocus("button"));
+      gQueue.push(new synthTab("button", new focusChecker("textbox")));
+
+      gQueue.invoke(); // Will call SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTests);
+  </script>
+</head>
+
+<body>
+  <a target="_blank"
+     title="Expose content in Canvas element"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=495912">
+    Mozilla Bug 495912
+  </a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <canvas>
+    <input id="button" type="button">
+    <input id="textbox">
+  </canvas>
+
+  <div id="eventdump"></div>
+</body>
+</html>
--- a/accessible/tests/mochitest/events/test_textattrchange.html
+++ b/accessible/tests/mochitest/events/test_textattrchange.html
@@ -44,17 +44,19 @@
         //var spellchecker = editor.getInlineSpellChecker(true);
         //spellchecker.enableRealTimeSpell = true;
 
         this.DOMNode.value = "valid text inalid tixt";
       }
 
       this.finalCheck = function spelledTextInvoker_finalCheck()
       {
-        var defAttrs = buildDefaultTextAttrs(this.DOMNode, kInputFontSize);
+        var defAttrs = buildDefaultTextAttrs(this.DOMNode, kInputFontSize,
+                                             kNormalFontWeight,
+                                             kInputFontFamily);
         testDefaultTextAttrs(aID, defAttrs);
 
         var attrs = { };
         var misspelledAttrs = {
           "invalid": "spelling"
         };
 
         testTextAttrs(aID, 0, attrs, defAttrs, 0, 11);
--- a/accessible/tests/mochitest/tree/test_canvas.html
+++ b/accessible/tests/mochitest/tree/test_canvas.html
@@ -13,23 +13,23 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
 
   <script type="application/javascript">
     function doTest()
     {
-      var accTree = {
-        role: ROLE_CANVAS,
-        children: [
-        ]
-      };
+      var accTree =
+        { CANVAS: [
+          { CHECKBUTTON: [] },
+          { ENTRY: [] }
+        ] };
+
       testAccessibleTree("canvas", accTree);
-
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -37,19 +37,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <a target="_blank"
      title="Expose alternative content in Canvas element to ATs"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=495912">Mozilla Bug 495912</a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
-  <canvas id="canvas" tabindex="0">
-    fallback content.
-  </canvas>
+  <canvas id="canvas" tabindex="0"><input type="checkbox"><input></canvas>
 
   <script type="text/javascript">
     var c=document.getElementById("canvas");
     var cxt=c.getContext("2d");
     cxt.fillStyle="#005500";
     cxt.fillRect(0,0,150,75);
   </script>  
 
--- a/accessible/tests/mochitest/treeupdate/Makefile.in
+++ b/accessible/tests/mochitest/treeupdate/Makefile.in
@@ -42,16 +42,17 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = accessible/treeupdate
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
 		test_ariadialog.html \
+		test_canvas.html \
 		test_colorpicker.xul \
 		test_cssoverflow.html \
 		test_contextmenu.xul \
 		test_doc.html \
 		test_gencontent.html \
 		test_list_editabledoc.html \
 		test_list.html \
 		test_menu.xul \
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_canvas.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <title>Canvas subdom mutation</title>
+
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Invokers
+
+    function addSubtree(aID)
+    {
+      this.node = getNode(aID);
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_SHOW, this.node)
+      ];
+
+      this.invoke = function addSubtree_invoke()
+      {
+        // ensure we start with no subtree
+        testAccessibleTree("canvas", { CANVAS: [] });
+        getNode("dialog").style.display = "block";
+      }
+
+      this.finalCheck = function addSubtree_finalCheck() {
+        testAccessibleTree("dialog", { DIALOG: [] });
+      }
+
+      this.getID = function addSubtree_getID()
+      {
+        return "show canvas subdom";
+      }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Test
+
+    //gA11yEventDumpID = "eventdump"; // debug stuff
+    //gA11yEventDumpToConsole = true;
+
+    var gQueue = null;
+
+    function doTest()
+    {
+      gQueue = new eventQueue();
+
+      // make the subdom come alive!
+      gQueue.push(new addSubtree("dialog"));
+
+      gQueue.invoke(); // SimpleTest.finish() will be called in the end
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="Expose content in Canvas element"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=495912">
+    Mozilla Bug 495912
+  </a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <canvas id="canvas">
+    <div id="dialog" role="dialog" style="display: none;">
+    </div>
+  </canvas>
+
+  <div id="eventdump"></div>
+</body>
+</html>
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -405,16 +405,20 @@ pref("browser.link.open_newwindow.restri
 // Enable browser frame
 pref("dom.mozBrowserFramesEnabled", true);
 pref("dom.mozBrowserFramesWhitelist", "http://localhost:7777");
 
 // Temporary permission hack for WebSMS
 pref("dom.sms.enabled", true);
 pref("dom.sms.whitelist", "file://,http://localhost:7777");
 
+// Temporary permission hack for WebContacts
+pref("dom.mozContacts.enabled", true);
+pref("dom.mozContacts.whitelist", "http://localhost:7777");
+
 // Ignore X-Frame-Options headers.
 pref("b2g.ignoreXFrameOptions", true);
 
 // controls if we want camera support
 pref("device.camera.enabled", true);
 pref("media.realtime_decoder.enabled", true);
 
 // "Preview" landing of bug 710563, which is bogged down in analysis
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -11,16 +11,17 @@ const CC = Components.Constructor;
 const Cr = Components.results;
 
 const LocalFile = CC('@mozilla.org/file/local;1',
                      'nsILocalFile',
                      'initWithPath');
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import('resource://gre/modules/Services.jsm');
+Cu.import('resource://gre/modules/ContactService.jsm');
 
 XPCOMUtils.defineLazyGetter(Services, 'env', function() {
   return Cc['@mozilla.org/process/environment;1']
            .getService(Ci.nsIEnvironment);
 });
 
 XPCOMUtils.defineLazyGetter(Services, 'ss', function() {
   return Cc['@mozilla.org/content/style-sheet-service;1']
@@ -55,17 +56,17 @@ function startupHttpd(baseDir, port) {
 #endif
 
 // FIXME Bug 707625
 // until we have a proper security model, add some rights to
 // the pre-installed web applications
 // XXX never grant 'content-camera' to non-gaia apps
 function addPermissions(urls) {
   let permissions = [
-    'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'content-camera'
+    'indexedDB', 'indexedDB-unlimited', 'webapps-manage', 'offline-app', 'content-camera', 'webcontacts-manage'
   ];
   urls.forEach(function(url) {
     let uri = Services.io.newURI(url, null, null);
     let allow = Ci.nsIPermissionManager.ALLOW_ACTION;
 
     permissions.forEach(function(permission) {
       Services.perms.add(uri, permission, allow);
     });
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -150,16 +150,17 @@
 @BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 #ifdef MOZ_B2G_BT
 @BINPATH@/components/dom_bluetooth.xpt
 #endif
 @BINPATH@/components/dom_canvas.xpt
+@BINPATH@/components/dom_contacts.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
@@ -289,16 +290,18 @@
 @BINPATH@/components/xuldoc.xpt
 @BINPATH@/components/xultmpl.xpt
 @BINPATH@/components/zipwriter.xpt
 @BINPATH@/components/webapps.xpt
 
 ; JavaScript components
 @BINPATH@/components/ConsoleAPI.manifest
 @BINPATH@/components/ConsoleAPI.js
+@BINPATH@/components/ContactManager.js
+@BINPATH@/components/ContactManager.manifest
 @BINPATH@/components/FeedProcessor.manifest
 @BINPATH@/components/FeedProcessor.js
 @BINPATH@/components/BrowserFeeds.manifest
 @BINPATH@/components/FeedConverter.js
 @BINPATH@/components/FeedWriter.js
 @BINPATH@/components/fuelApplication.manifest
 @BINPATH@/components/fuelApplication.js
 @BINPATH@/components/WebContentConverter.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -953,16 +953,17 @@ pref("services.sync.prefs.sync.addons.ig
 // uncompromised Sync-connected devices.
 pref("services.sync.prefs.sync.app.update.mode", true);
 pref("services.sync.prefs.sync.browser.download.manager.closeWhenDone", true);
 pref("services.sync.prefs.sync.browser.download.manager.retention", true);
 pref("services.sync.prefs.sync.browser.download.manager.scanWhenDone", true);
 pref("services.sync.prefs.sync.browser.download.manager.showWhenStarting", true);
 pref("services.sync.prefs.sync.browser.formfill.enable", true);
 pref("services.sync.prefs.sync.browser.link.open_newwindow", true);
+pref("services.sync.prefs.sync.browser.newtabpage.enabled", true);
 pref("services.sync.prefs.sync.browser.offline-apps.notify", true);
 pref("services.sync.prefs.sync.browser.safebrowsing.enabled", true);
 pref("services.sync.prefs.sync.browser.safebrowsing.malware.enabled", true);
 pref("services.sync.prefs.sync.browser.search.selectedEngine", true);
 pref("services.sync.prefs.sync.browser.search.update", true);
 pref("services.sync.prefs.sync.browser.sessionstore.restore_on_demand", true);
 pref("services.sync.prefs.sync.browser.startup.homepage", true);
 pref("services.sync.prefs.sync.browser.startup.page", true);
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -96,35 +96,35 @@ var StarUI = {
       case "popuphidden":
         if (aEvent.originalTarget == this.panel) {
           if (!this._element("editBookmarkPanelContent").hidden)
             this.quitEditMode();
 
           this._restoreCommandsState();
           this._itemId = -1;
           if (this._batching) {
-            PlacesUIUtils.ptm.endBatch();
+            PlacesUtils.transactionManager.endBatch();
             this._batching = false;
           }
 
           switch (this._actionOnHide) {
             case "cancel": {
-              PlacesUIUtils.ptm.undoTransaction();
+              PlacesUtils.transactionManager.undoTransaction();
               break;
             }
             case "remove": {
               // Remove all bookmarks for the bookmark's url, this also removes
               // the tags for the url.
-              PlacesUIUtils.ptm.beginBatch();
+              PlacesUtils.transactionManager.beginBatch();
               let itemIds = PlacesUtils.getBookmarksForURI(this._uriForRemoval);
               for (let i = 0; i < itemIds.length; i++) {
-                let txn = PlacesUIUtils.ptm.removeItem(itemIds[i]);
-                PlacesUIUtils.ptm.doTransaction(txn);
+                let txn = new PlacesRemoveItemTransaction(itemIds[i]);
+                PlacesUtils.transactionManager.doTransaction(txn);
               }
-              PlacesUIUtils.ptm.endBatch();
+              PlacesUtils.transactionManager.endBatch();
               break;
             }
           }
           this._actionOnHide = "";
         }
         break;
       case "keypress":
         if (aEvent.defaultPrevented) {
@@ -270,17 +270,17 @@ var StarUI = {
   removeBookmarkButtonCommand: function SU_removeBookmarkButtonCommand() {
     this._uriForRemoval = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
     this._actionOnHide = "remove";
     this.panel.hidePopup();
   },
 
   beginBatch: function SU_beginBatch() {
     if (!this._batching) {
-      PlacesUIUtils.ptm.beginBatch();
+      PlacesUtils.transactionManager.beginBatch();
       this._batching = true;
     }
   }
 }
 
 var PlacesCommandHook = {
   /**
    * Adds a bookmark to the page loaded in the given browser.
@@ -320,19 +320,20 @@ var PlacesCommandHook = {
         // but open right into the "edit" state, start batching here, so
         // "Cancel" in that state removes the bookmark.
         StarUI.beginBatch();
       }
 
       var parent = aParent != undefined ?
                    aParent : PlacesUtils.unfiledBookmarksFolderId;
       var descAnno = { name: PlacesUIUtils.DESCRIPTION_ANNO, value: description };
-      var txn = PlacesUIUtils.ptm.createItem(uri, parent, -1,
-                                             title, null, [descAnno]);
-      PlacesUIUtils.ptm.doTransaction(txn);
+      var txn = new PlacesCreateBookmarkTransaction(uri, parent, 
+                                                    PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                                    title, null, [descAnno]);
+      PlacesUtils.transactionManager.doTransaction(txn);
       // Set the character-set
       if (charset)
         PlacesUtils.history.setCharsetForURI(uri, charset);
       itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
     }
 
     // Revert the contents of the location bar
     if (gURLBar)
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -286,41 +286,41 @@ let gSyncUI = {
    *          "reset" -- reset sync
    */
 
   openSetup: function SUI_openSetup(wizardType) {
     let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
     if (win)
       win.focus();
     else {
-      window.openDialog("chrome://browser/content/syncSetup.xul",
+      window.openDialog("chrome://browser/content/sync/setup.xul",
                         "weaveSetup", "centerscreen,chrome,resizable=no",
                         wizardType);
     }
   },
 
   openAddDevice: function () {
     if (!Weave.Utils.ensureMPUnlocked())
       return;
 
     let win = Services.wm.getMostRecentWindow("Sync:AddDevice");
     if (win)
       win.focus();
     else
-      window.openDialog("chrome://browser/content/syncAddDevice.xul",
+      window.openDialog("chrome://browser/content/sync/addDevice.xul",
                         "syncAddDevice", "centerscreen,chrome,resizable=no");
   },
 
   openQuotaDialog: function SUI_openQuotaDialog() {
     let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
     if (win)
       win.focus();
     else
       Services.ww.activeWindow.openDialog(
-        "chrome://browser/content/syncQuota.xul", "",
+        "chrome://browser/content/sync/quota.xul", "",
         "centerscreen,chrome,dialog,modal");
   },
 
   openPrefs: function SUI_openPrefs() {
     openPreferences("paneSync");
   },
 
 
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -324,22 +324,22 @@ window[chromehidden~="toolbar"] toolbar:
 #status-bar ,
 #mainPopupSet {
   min-width: 1px;
 }
 
 %ifdef MOZ_SERVICES_SYNC
 /* Sync notification UI */
 #sync-notifications {
-  -moz-binding: url("chrome://browser/content/syncNotification.xml#notificationbox");
+  -moz-binding: url("chrome://browser/content/sync/notification.xml#notificationbox");
   overflow-y: visible !important;
 }
 
 #sync-notifications notification {
-  -moz-binding: url("chrome://browser/content/syncNotification.xml#notification");
+  -moz-binding: url("chrome://browser/content/sync/notification.xml#notification");
 }
 %endif
 
 /* Identity UI */
 #identity-popup-content-box.unknownIdentity > #identity-popup-connectedToLabel ,
 #identity-popup-content-box.unknownIdentity > #identity-popup-runByLabel ,
 #identity-popup-content-box.unknownIdentity > #identity-popup-content-host ,
 #identity-popup-content-box.unknownIdentity > #identity-popup-content-owner ,
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -284,19 +284,24 @@ nsContextMenu.prototype = {
     // (or is in a frame), or a canvas.
     this.showItem("context-viewimage", (this.onImage &&
                   (!this.inSyntheticDoc || this.inFrame)) || this.onCanvas);
 
     // View video depends on not having a standalone video.
     this.showItem("context-viewvideo", this.onVideo && (!this.inSyntheticDoc || this.inFrame));
     this.setItemAttr("context-viewvideo",  "disabled", !this.mediaURL);
 
-    // View background image depends on whether there is one.
-    this.showItem("context-viewbgimage", shouldShow && !this._hasMultipleBGImages);
-    this.showItem("context-sep-viewbgimage", shouldShow && !this._hasMultipleBGImages);
+    // View background image depends on whether there is one, but don't make
+    // background images of a stand-alone media document available.
+    this.showItem("context-viewbgimage", shouldShow &&
+                                         !this._hasMultipleBGImages &&
+                                         !this.inSyntheticDoc);
+    this.showItem("context-sep-viewbgimage", shouldShow &&
+                                             !this._hasMultipleBGImages &&
+                                             !this.inSyntheticDoc);
     document.getElementById("context-viewbgimage")
             .disabled = !this.hasBGImage;
 
     this.showItem("context-viewimageinfo", this.onImage);
   },
 
   initMiscItems: function CM_initMiscItems() {
     var isTextSelected = this.isTextSelected;
@@ -382,17 +387,19 @@ nsContextMenu.prototype = {
     this.showItem("context-sep-undo", this.onTextInput);
     this.showItem("context-cut", this.onTextInput);
     this.showItem("context-copy",
                   this.isContentSelected || this.onTextInput);
     this.showItem("context-paste", this.onTextInput);
     this.showItem("context-delete", this.onTextInput);
     this.showItem("context-sep-paste", this.onTextInput);
     this.showItem("context-selectall", !(this.onLink || this.onImage ||
-                  this.onVideo || this.onAudio) || this.isDesignMode);
+                                         this.onVideo || this.onAudio ||
+                                         this.inSyntheticDoc) ||
+                                       this.isDesignMode);
     this.showItem("context-sep-selectall", this.isContentSelected );
 
     // XXX dr
     // ------
     // nsDocumentViewer.cpp has code to determine whether we're
     // on a link or an image. we really ought to be using that...
 
     // Copy email link depends on whether we're on an email link.
--- a/browser/base/content/overrides/app-license.html
+++ b/browser/base/content/overrides/app-license.html
@@ -1,3 +1,3 @@
     <p><b>Binaries</b> of this product have been made available to you by the
     <a href="http://www.mozilla.org/">Mozilla Project</a> under the Mozilla
-    Public License. <a href="about:rights">Know your rights</a>.</p>
+    Public License 2.0 (MPL). <a href="about:rights">Know your rights</a>.</p>
rename from browser/base/content/aboutSyncTabs-bindings.xml
rename to browser/base/content/sync/aboutSyncTabs-bindings.xml
rename from browser/base/content/aboutSyncTabs.css
rename to browser/base/content/sync/aboutSyncTabs.css
--- a/browser/base/content/aboutSyncTabs.css
+++ b/browser/base/content/sync/aboutSyncTabs.css
@@ -1,7 +1,7 @@
 richlistitem[type="tab"] {
-  -moz-binding: url(chrome://browser/content/aboutSyncTabs-bindings.xml#tab-listing);
+  -moz-binding: url(chrome://browser/content/sync/aboutSyncTabs-bindings.xml#tab-listing);
 }
 
 richlistitem[type="client"] {
-  -moz-binding: url(chrome://browser/content/aboutSyncTabs-bindings.xml#client-listing);
+  -moz-binding: url(chrome://browser/content/sync/aboutSyncTabs-bindings.xml#client-listing);
 }
rename from browser/base/content/aboutSyncTabs.js
rename to browser/base/content/sync/aboutSyncTabs.js
rename from browser/base/content/aboutSyncTabs.xul
rename to browser/base/content/sync/aboutSyncTabs.xul
--- a/browser/base/content/aboutSyncTabs.xul
+++ b/browser/base/content/sync/aboutSyncTabs.xul
@@ -35,30 +35,30 @@
 # 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 *****
 
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/aboutSyncTabs.css" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/content/aboutSyncTabs.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/content/sync/aboutSyncTabs.css" type="text/css"?>
 
 <!DOCTYPE window [
   <!ENTITY % aboutSyncTabsDTD SYSTEM "chrome://browser/locale/aboutSyncTabs.dtd">
   %aboutSyncTabsDTD;
 ]>
 
 <window id="tabs-display"
         onload="RemoteTabViewer.init()"
         onunload="RemoteTabViewer.uninit()"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         title="&tabs.otherComputers.label;">
-  <script type="application/javascript;version=1.8" src="chrome://browser/content/aboutSyncTabs.js"/>
+  <script type="application/javascript;version=1.8" src="chrome://browser/content/sync/aboutSyncTabs.js"/>
   <script type="application/javascript" src="chrome://browser/content/utilityOverlay.js"/>
   <html:head>
     <html:link rel="icon" href="chrome://browser/skin/sync-16.png"/>
   </html:head>
 
   <popupset id="contextmenus">
     <menupopup id="tabListContext">
       <menuitem label="&tabs.context.openTab.label;"
rename from browser/base/content/syncAddDevice.js
rename to browser/base/content/sync/addDevice.js
rename from browser/base/content/syncAddDevice.xul
rename to browser/base/content/sync/addDevice.xul
--- a/browser/base/content/syncAddDevice.xul
+++ b/browser/base/content/sync/addDevice.xul
@@ -56,19 +56,19 @@
         windowtype="Sync:AddDevice"
         persist="screenX screenY"
         onwizardnext="return gSyncAddDevice.onWizardAdvance();"
         onwizardback="return gSyncAddDevice.onWizardBack();"
         onwizardcancel="gSyncAddDevice.onWizardCancel();"
         onload="gSyncAddDevice.init();">
 
   <script type="application/javascript"
-          src="chrome://browser/content/syncAddDevice.js"/>
+          src="chrome://browser/content/sync/addDevice.js"/>
   <script type="application/javascript"
-          src="chrome://browser/content/syncUtils.js"/>
+          src="chrome://browser/content/sync/utils.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/utilityOverlay.js"/>
   <script type="application/javascript"
           src="chrome://global/content/printUtils.js"/>
 
   <wizardpage id="addDevicePage"
               label="&pairDevice.title.label;"
               onpageshow="gSyncAddDevice.onPageShow();">
rename from browser/base/content/syncGenericChange.js
rename to browser/base/content/sync/genericChange.js
rename from browser/base/content/syncGenericChange.xul
rename to browser/base/content/sync/genericChange.xul
--- a/browser/base/content/syncGenericChange.xul
+++ b/browser/base/content/sync/genericChange.xul
@@ -55,19 +55,19 @@
         xmlns:html="http://www.w3.org/1999/xhtml"
         id="change-dialog"
         windowtype="Weave:ChangeSomething"
         persist="screenX screenY"
         onwizardnext="Change.onLoad()"
         onwizardfinish="return Change.onDialogAccept();">
 
   <script type="application/javascript"
-          src="chrome://browser/content/syncGenericChange.js"/>
+          src="chrome://browser/content/sync/genericChange.js"/>
   <script type="application/javascript"
-          src="chrome://browser/content/syncUtils.js"/>
+          src="chrome://browser/content/sync/utils.js"/>
   <script type="application/javascript"
           src="chrome://global/content/printUtils.js"/>
 
   <wizardpage id="change-page"
               label="">
 
     <description id="introText">
     </description>
rename from browser/base/content/syncKey.xhtml
rename to browser/base/content/sync/key.xhtml
rename from browser/base/content/syncNotification.xml
rename to browser/base/content/sync/notification.xml
rename from browser/base/content/syncProgress.js
rename to browser/base/content/sync/progress.js
rename from browser/base/content/syncProgress.xhtml
rename to browser/base/content/sync/progress.xhtml
--- a/browser/base/content/syncProgress.xhtml
+++ b/browser/base/content/sync/progress.xhtml
@@ -56,17 +56,17 @@
 
     <link rel="stylesheet" type="text/css" media="all"
           href="chrome://browser/skin/syncProgress.css"/>
 
     <link rel="icon" type="image/png" id="favicon"
           href="chrome://browser/skin/sync-16.png"/>
 
     <script type="text/javascript;version=1.8"
-            src="chrome://browser/content/syncProgress.js"/>
+            src="chrome://browser/content/sync/progress.js"/>
   </head>
   <body onload="onLoad(event)" onunload="onUnload(event)">
     <title>&setup.successPage.title;</title>
     <div id="floatingBox" class="main-content">
       <div id="title">
         <h1>&setup.successPage.title;</h1>
       </div>
       <div id="successLogo">
rename from browser/base/content/syncQuota.js
rename to browser/base/content/sync/quota.js
rename from browser/base/content/syncQuota.xul
rename to browser/base/content/sync/quota.xul
--- a/browser/base/content/syncQuota.xul
+++ b/browser/base/content/sync/quota.xul
@@ -55,17 +55,17 @@
         xmlns:html="http://www.w3.org/1999/xhtml"
         onload="gSyncQuota.init()"
         buttons="accept,cancel"
         title="&quota.dialogTitle.label;"
         ondialogcancel="return gSyncQuota.onCancel();"
         ondialogaccept="return gSyncQuota.onAccept();">
 
   <script type="application/javascript"
-          src="chrome://browser/content/syncQuota.js"/>
+          src="chrome://browser/content/sync/quota.js"/>
 
   <stringbundleset id="stringbundleset">
     <stringbundle id="quotaStrings"
                   src="chrome://browser/locale/syncQuota.properties"/>
   </stringbundleset>
 
   <vbox flex="1">
     <label id="usageLabel"
rename from browser/base/content/syncSetup.js
rename to browser/base/content/sync/setup.js
rename from browser/base/content/syncSetup.xul
rename to browser/base/content/sync/setup.xul
--- a/browser/base/content/syncSetup.xul
+++ b/browser/base/content/sync/setup.xul
@@ -60,19 +60,19 @@
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         onwizardnext="return gSyncSetup.onWizardAdvance()"
         onwizardback="return gSyncSetup.onWizardBack()"
         onwizardcancel="gSyncSetup.onWizardCancel()"
         onload="gSyncSetup.init()">
 
   <script type="application/javascript"
-          src="chrome://browser/content/syncSetup.js"/>
+          src="chrome://browser/content/sync/setup.js"/>
   <script type="application/javascript"
-          src="chrome://browser/content/syncUtils.js"/>
+          src="chrome://browser/content/sync/utils.js"/>
   <script type="application/javascript"
           src="chrome://browser/content/utilityOverlay.js"/>
   <script type="application/javascript"
           src="chrome://global/content/printUtils.js"/>
 
   <wizardpage id="addDevicePage"
               label="&pairDevice.title.label;"
               onpageshow="gSyncSetup.onPageShow()">
rename from browser/base/content/syncUtils.js
rename to browser/base/content/sync/utils.js
--- a/browser/base/content/syncUtils.js
+++ b/browser/base/content/sync/utils.js
@@ -71,17 +71,17 @@ let gSyncUtils = {
     // Just re-show the dialog if it's already open
     let openedDialog = Services.wm.getMostRecentWindow("Sync:" + type);
     if (openedDialog != null) {
       openedDialog.focus();
       return;
     }
 
     // Open up the change dialog
-    let changeXUL = "chrome://browser/content/syncGenericChange.xul";
+    let changeXUL = "chrome://browser/content/sync/genericChange.xul";
     let changeOpt = "centerscreen,chrome,resizable=no";
     Services.ww.activeWindow.openDialog(changeXUL, "", changeOpt,
                                         type, duringSetup);
   },
 
   changePassword: function () {
     if (Weave.Utils.ensureMPUnlocked())
       this.openChange("ChangePassword");
@@ -120,17 +120,17 @@ let gSyncUtils = {
    * @param elid : ID of the form element containing the passphrase.
    * @param callback : Function called once the iframe has loaded.
    */
   _preparePPiframe: function(elid, callback) {
     let pp = document.getElementById(elid).value;
 
     // Create an invisible iframe whose contents we can print.
     let iframe = document.createElement("iframe");
-    iframe.setAttribute("src", "chrome://browser/content/syncKey.xhtml");
+    iframe.setAttribute("src", "chrome://browser/content/sync/key.xhtml");
     iframe.collapsed = true;
     document.documentElement.appendChild(iframe);
     iframe.contentWindow.addEventListener("load", function() {
       iframe.contentWindow.removeEventListener("load", arguments.callee, false);
 
       // Insert the Sync Key into the page.
       let el = iframe.contentDocument.getElementById("synckey");
       el.firstChild.nodeValue = pp;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1413,17 +1413,19 @@
           ]]>
         </body>
       </method>
 
       <method name="warnAboutClosingTabs">
       <parameter name="aAll"/>
       <body>
         <![CDATA[
-          var tabsToClose = (aAll ? this.tabs.length : this.visibleTabs.length - 1)
+          var tabsToClose = (aAll ?
+                               this.tabs.length - this._removingTabs.length :
+                               this.visibleTabs.length - 1)
                             - gBrowser._numPinnedTabs;
           if (tabsToClose <= 1)
             return true;
 
           const pref = "browser.tabs.warnOnClose";
           var shouldPrompt = Services.prefs.getBoolPref(pref);
 
           if (!shouldPrompt)
@@ -1521,16 +1523,17 @@
             if (!aTab.pinned && !aTab.hidden && aTab._fullyOpen && byMouse)
               this.tabContainer._lockTabSizing(aTab);
             else
               this.tabContainer._unlockTabSizing();
 
             if (!animate /* the caller didn't opt in */ ||
                 isLastTab ||
                 aTab.pinned ||
+                aTab.hidden ||
                 this._removingTabs.length > 3 /* don't want lots of concurrent animations */ ||
                 aTab.getAttribute("fadein") != "true" /* fade-in transition hasn't been triggered yet */ ||
                 window.getComputedStyle(aTab).maxWidth == "0.1px" /* fade-in transition hasn't moved yet */ ||
                 !Services.prefs.getBoolPref("browser.tabs.animate")) {
               this._endRemoveTab(aTab);
               return;
             }
 
--- a/browser/base/content/test/browser_homeDrop.js
+++ b/browser/base/content/test/browser_homeDrop.js
@@ -23,48 +23,33 @@ function test() {
     ok(true, "dialog appeared in response to home button drop");
     domwindow.document.documentElement.cancelDialog();
     Services.wm.removeListener(dialogListener);
 
     // Now trigger the invalid URI test
     executeSoon(function () {
       let consoleListener = {
         observe: function (m) {
-          info("m.message: " + m.message + "\n");
           if (m.message.indexOf("NS_ERROR_DOM_BAD_URI") > -1) {
             ok(true, "drop was blocked");
             executeSoon(finish);
           }
         }
       }
       Services.console.registerListener(consoleListener);
       registerCleanupFunction(function () {
         Services.console.unregisterListener(consoleListener);
       });
 
       executeSoon(function () {
         info("Attempting second drop, of a javascript: URI");
         // The drop handler throws an exception when dragging URIs that inherit
         // principal, e.g. javascript:
         expectUncaughtException();
-        let originalHandler = homeButtonObserver.onDrop;
-        homeButtonObserver.onDrop = function (aEvent) {
-          info("homeButtonObserver.onDrop called");
-          try {
-            originalHandler(aEvent);
-          } catch (ex) {
-            info("originalHandler threw an exception: " + ex);
-            throw ex;
-          }
-        };
-        registerCleanupFunction(function () {
-          homeButtonObserver.onDrop = originalHandler;
-        });
         chromeUtils.synthesizeDrop(homeButton, homeButton, [[{type: "text/plain", data: "javascript:8888"}]], "copy", window, EventUtils);
-        info("Triggered the second drop of a javascript: URI");
       });
     })
   });
 
   Services.wm.addListener(dialogListener);
 
   chromeUtils.synthesizeDrop(homeButton, homeButton, [[{type: "text/plain", data: "http://mochi.test:8888/"}]], "copy", window, EventUtils);
 }
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -36,51 +36,51 @@ browser.jar:
 *       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/pageInfo.xml         (content/pageinfo/pageInfo.xml)
 *       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)
+#ifdef MOZ_SERVICES_SYNC
+*       content/browser/sync/aboutSyncTabs.xul        (content/sync/aboutSyncTabs.xul)
+        content/browser/sync/aboutSyncTabs.js         (content/sync/aboutSyncTabs.js)
+        content/browser/sync/aboutSyncTabs.css        (content/sync/aboutSyncTabs.css)
+*       content/browser/sync/aboutSyncTabs-bindings.xml  (content/sync/aboutSyncTabs-bindings.xml)
+*       content/browser/sync/setup.xul                (content/sync/setup.xul)
+        content/browser/sync/addDevice.js             (content/sync/addDevice.js)
+*       content/browser/sync/addDevice.xul            (content/sync/addDevice.xul)
+        content/browser/sync/setup.js                 (content/sync/setup.js)
+*       content/browser/sync/genericChange.xul        (content/sync/genericChange.xul)
+        content/browser/sync/genericChange.js         (content/sync/genericChange.js)
+*       content/browser/sync/key.xhtml                (content/sync/key.xhtml)
+*       content/browser/sync/notification.xml         (content/sync/notification.xml)
+*       content/browser/sync/quota.xul                (content/sync/quota.xul)
+        content/browser/sync/quota.js                 (content/sync/quota.js)
+        content/browser/sync/utils.js                 (content/sync/utils.js)
+        content/browser/sync/progress.js              (content/sync/progress.js)
+*       content/browser/sync/progress.xhtml           (content/sync/progress.xhtml)
+#endif
 *       content/browser/openLocation.js               (content/openLocation.js)
 *       content/browser/openLocation.xul              (content/openLocation.xul)
 *       content/browser/safeMode.js                   (content/safeMode.js)
 *       content/browser/safeMode.xul                  (content/safeMode.xul)
 *       content/browser/sanitize.js                   (content/sanitize.js)
 *       content/browser/sanitize.xul                  (content/sanitize.xul)
 *       content/browser/sanitizeDialog.js             (content/sanitizeDialog.js)
         content/browser/sanitizeDialog.css            (content/sanitizeDialog.css)
 *       content/browser/tabbrowser.css                (content/tabbrowser.css)
 *       content/browser/tabbrowser.xml                (content/tabbrowser.xml)
 *       content/browser/urlbarBindings.xml            (content/urlbarBindings.xml)
 *       content/browser/utilityOverlay.js             (content/utilityOverlay.js)
 *       content/browser/web-panels.js                 (content/web-panels.js)
 *       content/browser/web-panels.xul                (content/web-panels.xul)
 *       content/browser/baseMenuOverlay.xul           (content/baseMenuOverlay.xul)
 *       content/browser/nsContextMenu.js              (content/nsContextMenu.js)
-#ifdef MOZ_SERVICES_SYNC
-*       content/browser/aboutSyncTabs.xul             (content/aboutSyncTabs.xul)
-        content/browser/aboutSyncTabs.js              (content/aboutSyncTabs.js)
-        content/browser/aboutSyncTabs.css             (content/aboutSyncTabs.css)
-*       content/browser/aboutSyncTabs-bindings.xml    (content/aboutSyncTabs-bindings.xml)
-*       content/browser/syncSetup.xul                 (content/syncSetup.xul)
-        content/browser/syncAddDevice.js              (content/syncAddDevice.js)
-*       content/browser/syncAddDevice.xul             (content/syncAddDevice.xul)
-        content/browser/syncSetup.js                  (content/syncSetup.js)
-*       content/browser/syncGenericChange.xul         (content/syncGenericChange.xul)
-        content/browser/syncGenericChange.js          (content/syncGenericChange.js)
-*       content/browser/syncKey.xhtml                 (content/syncKey.xhtml)
-*       content/browser/syncNotification.xml          (content/syncNotification.xml)
-*       content/browser/syncQuota.xul                 (content/syncQuota.xul)
-        content/browser/syncQuota.js                  (content/syncQuota.js)
-        content/browser/syncUtils.js                  (content/syncUtils.js)
-        content/browser/syncProgress.js               (content/syncProgress.js)
-*       content/browser/syncProgress.xhtml            (content/syncProgress.xhtml)
-#endif
 # XXX: We should exclude this one as well (bug 71895)
 *       content/browser/hiddenWindow.xul              (content/hiddenWindow.xul)
 #ifdef XP_MACOSX
 *       content/browser/macBrowserOverlay.xul         (content/macBrowserOverlay.xul)
 *       content/browser/downloadManagerOverlay.xul    (content/downloadManagerOverlay.xul)
 *       content/browser/jsConsoleOverlay.xul          (content/jsConsoleOverlay.xul)
 *       content/browser/softwareUpdateOverlay.xul  (content/softwareUpdateOverlay.xul)
 #endif
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -92,19 +92,19 @@ static RedirEntry kRedirMap[] = {
     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 },
 #ifdef MOZ_SERVICES_SYNC
-  { "sync-progress", "chrome://browser/content/syncProgress.xhtml",
+  { "sync-progress", "chrome://browser/content/sync/progress.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
-  { "sync-tabs", "chrome://browser/content/aboutSyncTabs.xul",
+  { "sync-tabs", "chrome://browser/content/sync/aboutSyncTabs.xul",
     nsIAboutModule::ALLOW_SCRIPT },
 #endif
   { "home", "chrome://browser/content/aboutHome.xhtml",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT },
   { "newtab", "chrome://browser/content/newtab/newTab.xul",
     nsIAboutModule::ALLOW_SCRIPT },
   { "permissions", "chrome://browser/content/preferences/aboutPermissions.xul",
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1,8 +1,9 @@
+# -*- indent-tabs-mode: nil -*-
 # ***** 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/
 #
@@ -769,51 +770,94 @@ BrowserGlue.prototype = {
 
 #ifdef MOZ_TELEMETRY_REPORTING
   _showTelemetryNotification: function BG__showTelemetryNotification() {
     const PREF_TELEMETRY_PROMPTED = "toolkit.telemetry.prompted";
     const PREF_TELEMETRY_ENABLED  = "toolkit.telemetry.enabled";
     const PREF_TELEMETRY_REJECTED  = "toolkit.telemetry.rejected";
     const PREF_TELEMETRY_INFOURL  = "toolkit.telemetry.infoURL";
     const PREF_TELEMETRY_SERVER_OWNER = "toolkit.telemetry.server_owner";
+    const PREF_TELEMETRY_ENABLED_BY_DEFAULT = "toolkit.telemetry.enabledByDefault";
+    const PREF_TELEMETRY_NOTIFIED_OPTOUT = "toolkit.telemetry.notifiedOptOut";
     // This is used to reprompt users when privacy message changes
     const TELEMETRY_PROMPT_REV = 2;
 
-    function appendTelemetryNotification(notifyBox, message, buttons, hideclose) {
+    // Stick notifications onto the selected tab of the active browser window.
+    var win = this.getMostRecentBrowserWindow();
+    var tabbrowser = win.gBrowser;
+    var notifyBox = tabbrowser.getNotificationBox();
+
+    var browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+    var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
+    var productName = brandBundle.GetStringFromName("brandFullName");
+    var serverOwner = Services.prefs.getCharPref(PREF_TELEMETRY_SERVER_OWNER);
+
+    function appendTelemetryNotification(message, buttons, hideclose) {
       let notification = notifyBox.appendNotification(message, "telemetry", null,
-						      notifyBox.PRIORITY_INFO_LOW,
-						      buttons);
-      notification.setAttribute("hideclose", hideclose);
+                                                      notifyBox.PRIORITY_INFO_LOW,
+                                                      buttons);
+      if (hideclose)
+        notification.setAttribute("hideclose", hideclose);
       notification.persistence = -1;  // Until user closes it
       return notification;
     }
 
+    function appendLearnMoreLink(notification) {
+      let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+      let link = notification.ownerDocument.createElementNS(XULNS, "label");
+      link.className = "text-link telemetry-text-link";
+      link.setAttribute("value", browserBundle.GetStringFromName("telemetryLinkLabel"));
+      let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText");
+      description.appendChild(link);
+      return link;
+    }
+
+    var telemetryEnabledByDefault = false;
+    try {
+      telemetryEnabledByDefault = Services.prefs.getBoolPref(PREF_TELEMETRY_ENABLED_BY_DEFAULT);
+    } catch(e) {}
+    if (telemetryEnabledByDefault) {
+      var telemetryNotifiedOptOut = false;
+      try {
+        telemetryNotifiedOptOut = Services.prefs.getBoolPref(PREF_TELEMETRY_NOTIFIED_OPTOUT);
+      } catch(e) {}
+      if (telemetryNotifiedOptOut)
+        return;
+
+      var telemetryPrompt = browserBundle.formatStringFromName("telemetryOptOutPrompt",
+                                                               [productName, serverOwner, productName], 3);
+
+      Services.prefs.setBoolPref(PREF_TELEMETRY_NOTIFIED_OPTOUT, true);
+
+      let notification = appendTelemetryNotification(telemetryPrompt, null, false);
+      let link = appendLearnMoreLink(notification);
+      link.addEventListener('click', function() {
+        // Open the learn more url in a new tab
+        let url = Services.urlFormatter.formatURLPref("app.support.baseURL");
+        url += "how-can-i-help-submitting-performance-data";
+        tabbrowser.selectedTab = tabbrowser.addTab(url);
+        // Remove the notification on which the user clicked
+        notification.parentNode.removeNotification(notification, true);
+      }, false);
+      return;
+    }
+
     var telemetryPrompted = null;
     try {
       telemetryPrompted = Services.prefs.getIntPref(PREF_TELEMETRY_PROMPTED);
     } catch(e) {}
     // If the user has seen the latest telemetry prompt, do not prompt again
     // else clear old prefs and reprompt
     if (telemetryPrompted === TELEMETRY_PROMPT_REV)
       return;
     
     Services.prefs.clearUserPref(PREF_TELEMETRY_PROMPTED);
     Services.prefs.clearUserPref(PREF_TELEMETRY_ENABLED);
     
-    // Stick the notification onto the selected tab of the active browser window.
-    var win = this.getMostRecentBrowserWindow();
-    var browser = win.gBrowser; // for closure in notification bar callback
-    var notifyBox = browser.getNotificationBox();
-
-    var browserBundle   = Services.strings.createBundle("chrome://browser/locale/browser.properties");
-    var brandBundle     = Services.strings.createBundle("chrome://branding/locale/brand.properties");
-
-    var productName        = brandBundle.GetStringFromName("brandFullName");
-    var serverOwner        = Services.prefs.getCharPref(PREF_TELEMETRY_SERVER_OWNER);
-    var telemetryPrompt    = browserBundle.formatStringFromName("telemetryPrompt", [productName, serverOwner], 2);
+    var telemetryPrompt = browserBundle.formatStringFromName("telemetryPrompt", [productName, serverOwner], 2);
 
     var buttons = [
                     {
                       label:     browserBundle.GetStringFromName("telemetryYesButtonLabel2"),
                       accessKey: browserBundle.GetStringFromName("telemetryYesButtonAccessKey"),
                       popup:     null,
                       callback:  function(aNotificationBar, aButton) {
                         Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
@@ -827,33 +871,27 @@ BrowserGlue.prototype = {
                         Services.prefs.setBoolPref(PREF_TELEMETRY_REJECTED, true);
                       }
                     }
                   ];
 
     // Set pref to indicate we've shown the notification.
     Services.prefs.setIntPref(PREF_TELEMETRY_PROMPTED, TELEMETRY_PROMPT_REV);
 
-    let notification = appendTelemetryNotification(notifyBox, telemetryPrompt,
-						   buttons, true);
-    let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-    let link = notification.ownerDocument.createElementNS(XULNS, "label");
-    link.className = "text-link telemetry-text-link";
-    link.setAttribute("value", browserBundle.GetStringFromName("telemetryLinkLabel"));
+    let notification = appendTelemetryNotification(telemetryPrompt, buttons, true);
+    let link = appendLearnMoreLink(notification);
     link.addEventListener('click', function() {
       // Open the learn more url in a new tab
-      browser.selectedTab = browser.addTab(Services.prefs.getCharPref(PREF_TELEMETRY_INFOURL));
+      tabbrowser.selectedTab = tabbrowser.addTab(Services.prefs.getCharPref(PREF_TELEMETRY_INFOURL));
       // Remove the notification on which the user clicked
       notification.parentNode.removeNotification(notification, true);
       // Add a new notification to that tab, with no "Learn more" link
-      notifyBox = browser.getNotificationBox();
-      appendTelemetryNotification(notifyBox, telemetryPrompt, buttons, true);
+      notifyBox = tabbrowser.getNotificationBox();
+      appendTelemetryNotification(telemetryPrompt, buttons, true);
     }, false);
-    let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText");
-    description.appendChild(link);
   },
 #endif
 
   _showPluginUpdatePage: function BG__showPluginUpdatePage() {
     Services.prefs.setBoolPref(PREF_PLUGINS_NOTIFYUSER, false);
 
     var formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
                     getService(Ci.nsIURLFormatter);
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -431,25 +431,25 @@ var BookmarkPropertiesPanel = {
         break;
     }
   },
 
   _beginBatch: function BPP__beginBatch() {
     if (this._batching)
       return;
 
-    PlacesUIUtils.ptm.beginBatch();
+    PlacesUtils.transactionManager.beginBatch();
     this._batching = true;
   },
 
   _endBatch: function BPP__endBatch() {
     if (!this._batching)
       return;
 
-    PlacesUIUtils.ptm.endBatch();
+    PlacesUtils.transactionManager.endBatch();
     this._batching = false;
   },
 
   _fillEditProperties: function BPP__fillEditProperties() {
     gEditItemOverlay.initPanel(this._itemId,
                                { hiddenRows: this._hiddenRows,
                                  forceReadOnly: this._readOnly });
   },
@@ -509,17 +509,17 @@ var BookmarkPropertiesPanel = {
 
   onDialogCancel: function BPP_onDialogCancel() {
     // The order here is important! We have to uninit the panel first, otherwise
     // changes done as part of Undo may change the panel contents and by
     // that force it to commit more transactions.
     gEditItemOverlay.uninitPanel(true);
     gEditItemOverlay = null;
     this._endBatch();
-    PlacesUIUtils.ptm.undoTransaction();
+    PlacesUtils.transactionManager.undoTransaction();
     window.arguments[0].performed = false;
   },
 
   /**
    * This method checks to see if the input fields are in a valid state.
    *
    * @returns  true if the input is valid, false otherwise
    */
@@ -572,54 +572,69 @@ var BookmarkPropertiesPanel = {
    * various fields and opening arguments of the dialog.
    */
   _getCreateNewBookmarkTransaction:
   function BPP__getCreateNewBookmarkTransaction(aContainer, aIndex) {
     var annotations = [];
     var childTransactions = [];
 
     if (this._description) {
-      childTransactions.push(
-        PlacesUIUtils.ptm.editItemDescription(-1, this._description));
+      let annoObj = { name   : PlacesUIUtils.DESCRIPTION_ANNO,
+                      type   : Ci.nsIAnnotationService.TYPE_STRING,
+                      flags  : 0,
+                      value  : this._description,
+                      expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
+      let editItemTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
+      childTransactions.push(editItemTxn);
     }
 
     if (this._loadInSidebar) {
-      childTransactions.push(
-        PlacesUIUtils.ptm.setLoadInSidebar(-1, this._loadInSidebar));
+      let annoObj = { name   : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
+                      type   : Ci.nsIAnnotationService.TYPE_INT32,
+                      flags  : 0,
+                      value  : this._loadInSidebar,
+                      expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
+      let setLoadTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
+      childTransactions.push(setLoadTxn);
     }
 
     if (this._postData) {
-      childTransactions.push(
-        PlacesUIUtils.ptm.editBookmarkPostData(-1, this._postData));
+      let postDataTxn = new PlacesEditBookmarkPostDataTransaction(-1, this._postData);
+      childTransactions.push(postDataTxn);
     }
 
     //XXX TODO: this should be in a transaction!
     if (this._charSet)
       PlacesUtils.history.setCharsetForURI(this._uri, this._charSet);
 
-    var transactions = [PlacesUIUtils.ptm.createItem(this._uri,
-                                                     aContainer, aIndex,
-                                                     this._title, this._keyword,
-                                                     annotations,
-                                                     childTransactions)];
+    let createTxn = new PlacesCreateBookmarkTransaction(this._uri,
+                                                        aContainer,
+                                                        aIndex,
+                                                        this._title,
+                                                        this._keyword,
+                                                        annotations,
+                                                        childTransactions);
 
-    return PlacesUIUtils.ptm.aggregateTransactions(this._getDialogTitle(),
-                                                   transactions);
+    return new PlacesAggregatedTransaction(this._getDialogTitle(),
+                                           [createTxn]);
   },
 
   /**
    * Returns a childItems-transactions array representing the URIList with
    * which the dialog has been opened.
    */
   _getTransactionsForURIList: function BPP__getTransactionsForURIList() {
     var transactions = [];
     for (var i = 0; i < this._URIs.length; ++i) {
       var uri = this._URIs[i];
       var title = this._getURITitleFromHistory(uri);
-      transactions.push(PlacesUIUtils.ptm.createItem(uri, -1, -1, title));
+      var createTxn = new PlacesCreateBookmarkTransaction(uri, -1, 
+                                                          PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                                          title);
+      transactions.push(createTxn);
     }
     return transactions; 
   },
 
   /**
    * Returns a transaction for creating a new folder item representing the
    * various fields and opening arguments of the dialog.
    */
@@ -628,29 +643,30 @@ var BookmarkPropertiesPanel = {
     var annotations = [];
     var childItemsTransactions;
     if (this._URIs.length)
       childItemsTransactions = this._getTransactionsForURIList();
 
     if (this._description)
       annotations.push(this._getDescriptionAnnotation(this._description));
 
-    return PlacesUIUtils.ptm.createFolder(this._title, aContainer, aIndex,
-                                          annotations, childItemsTransactions);
+    return new PlacesCreateFolderTransaction(this._title, aContainer,
+                                             aIndex, annotations,
+                                             childItemsTransactions);
   },
 
   /**
    * Returns a transaction for creating a new live-bookmark item representing
    * the various fields and opening arguments of the dialog.
    */
   _getCreateNewLivemarkTransaction:
   function BPP__getCreateNewLivemarkTransaction(aContainer, aIndex) {
-    return PlacesUIUtils.ptm.createLivemark(this._feedURI, this._siteURI,
-                                            this._title,
-                                            aContainer, aIndex);
+    return new PlacesCreateLivemarkTransaction(this._feedURI, this._siteURI,
+                                               this._title,
+                                               aContainer, aIndex);
   },
 
   /**
    * Dialog-accept code-path for creating a new item (any type)
    */
   _createNewItem: function BPP__getCreateItemTransaction() {
     var [container, index] = this._getInsertionPointDetails();
     var txn;
@@ -661,12 +677,12 @@ var BookmarkPropertiesPanel = {
         break;
       case LIVEMARK_CONTAINER:
         txn = this._getCreateNewLivemarkTransaction(container, index);
         break;      
       default: // BOOKMARK_ITEM
         txn = this._getCreateNewBookmarkTransaction(container, index);
     }
 
-    PlacesUIUtils.ptm.doTransaction(txn);
+    PlacesUtils.transactionManager.doTransaction(txn);
     this._itemId = PlacesUtils.bookmarks.getIdForItemAt(container, index);
   }
 };
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -1853,23 +1853,26 @@ PlacesMenu.prototype = {
         this._onPopupHidden(aEvent);
         break;
     }
   },
 
   _onPopupHidden: function PM__onPopupHidden(aEvent) {
     // Avoid handling popuphidden of inner views.
     let popup = aEvent.originalTarget;
-    if (!popup._placesNode || PlacesUIUtils.getViewForNode(popup) != this)
+    let placesNode = popup._placesNode;
+    if (!placesNode || PlacesUIUtils.getViewForNode(popup) != this)
       return;
 
     // UI performance: folder queries are cheap, keep the resultnode open
     // so we don't rebuild its contents whenever the popup is reopened.
-    if (!PlacesUtils.nodeIsFolder(popup._placesNode))
-      popup._placesNode.containerOpen = false;
+    // Though, we want to always close feed containers so their expiration
+    // status will be checked at next opening.
+    if (!PlacesUtils.nodeIsFolder(placesNode) || placesNode._feedURI)
+      placesNode.containerOpen = false;
 
     // The autoopened attribute is set for folders which have been
     // automatically opened when dragged over.  Turn off this attribute
     // when the folder closes because it is no longer applicable.
     popup.removeAttribute("autoopened");
     popup.removeAttribute("dragstart");
   }
 };
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -152,19 +152,19 @@ PlacesController.prototype = {
     // filters out other commands that we do _not_ support (see 329587).
     const CMD_PREFIX = "placesCmd_";
     return (aCommand.substr(0, CMD_PREFIX.length) == CMD_PREFIX);
   },
 
   isCommandEnabled: function PC_isCommandEnabled(aCommand) {
     switch (aCommand) {
     case "cmd_undo":
-      return PlacesUIUtils.ptm.numberOfUndoItems > 0;
+      return PlacesUtils.transactionManager.numberOfUndoItems > 0;
     case "cmd_redo":
-      return PlacesUIUtils.ptm.numberOfRedoItems > 0;
+      return PlacesUtils.transactionManager.numberOfRedoItems > 0;
     case "cmd_cut":
     case "placesCmd_cut":
       var nodes = this._view.selectedNodes;
       // If selection includes history nodes there's no reason to allow cut.
       for (var i = 0; i < nodes.length; i++) {
         if (nodes[i].itemId == -1)
           return false;
       }
@@ -225,20 +225,20 @@ PlacesController.prototype = {
     default:
       return false;
     }
   },
 
   doCommand: function PC_doCommand(aCommand) {
     switch (aCommand) {
     case "cmd_undo":
-      PlacesUIUtils.ptm.undoTransaction();
+      PlacesUtils.transactionManager.undoTransaction();
       break;
     case "cmd_redo":
-      PlacesUIUtils.ptm.redoTransaction();
+      PlacesUtils.transactionManager.redoTransaction();
       break;
     case "cmd_cut":
     case "placesCmd_cut":
       this.cut();
       break;
     case "cmd_copy":
     case "placesCmd_copy":
       this.copy();
@@ -780,18 +780,18 @@ PlacesController.prototype = {
 
   /**
    * Create a new Bookmark separator somewhere.
    */
   newSeparator: function PC_newSeparator() {
     var ip = this._view.insertionPoint;
     if (!ip)
       throw Cr.NS_ERROR_NOT_AVAILABLE;
-    var txn = PlacesUIUtils.ptm.createSeparator(ip.itemId, ip.index);
-    PlacesUIUtils.ptm.doTransaction(txn);
+    var txn = new PlacesCreateSeparatorTransaction(ip.itemId, ip.index);
+    PlacesUtils.transactionManager.doTransaction(txn);
     // select the new item
     var insertedNodeId = PlacesUtils.bookmarks
                                     .getIdForItemAt(ip.itemId, ip.index);
     this._view.selectItems([insertedNodeId], false);
   },
 
   /**
    * Opens a dialog for moving the selected nodes.
@@ -802,18 +802,18 @@ PlacesController.prototype = {
                       this._view.selectedNodes);
   },
 
   /**
    * Sort the selected folder by name
    */
   sortFolderByName: function PC_sortFolderByName() {
     var itemId = PlacesUtils.getConcreteItemId(this._view.selectedNode);
-    var txn = PlacesUIUtils.ptm.sortFolderByName(itemId);
-    PlacesUIUtils.ptm.doTransaction(txn);
+    var txn = new PlacesSortFolderByNameTransaction(itemId);
+    PlacesUtils.transactionManager.doTransaction(txn);
   },
 
   /**
    * Walk the list of folders we're removing in this delete operation, and
    * see if the selected node specified is already implicitly being removed
    * because it is a child of that folder.
    * @param   node
    *          Node to check for containment.
@@ -867,30 +867,33 @@ PlacesController.prototype = {
       if (this._shouldSkipNode(node, removedFolders))
         continue;
 
       if (PlacesUtils.nodeIsTagQuery(node.parent)) {
         // This is a uri node inside a tag container.  It needs a special
         // untag transaction.
         var tagItemId = PlacesUtils.getConcreteItemId(node.parent);
         var uri = NetUtil.newURI(node.uri);
-        transactions.push(PlacesUIUtils.ptm.untagURI(uri, [tagItemId]));
+        let txn = new PlacesUntagURITransaction(uri, [tagItemId]);
+        transactions.push(txn);
       }
       else if (PlacesUtils.nodeIsTagQuery(node) && node.parent &&
                PlacesUtils.nodeIsQuery(node.parent) &&
                PlacesUtils.asQuery(node.parent).queryOptions.resultType ==
                  Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY) {
         // This is a tag container.
         // Untag all URIs tagged with this tag only if the tag container is
         // child of the "Tags" query in the library, in all other places we
         // must only remove the query node.
         var tag = node.title;
         var URIs = PlacesUtils.tagging.getURIsForTag(tag);
-        for (var j = 0; j < URIs.length; j++)
-          transactions.push(PlacesUIUtils.ptm.untagURI(URIs[j], [tag]));
+        for (var j = 0; j < URIs.length; j++) {
+          let txn = new PlacesUntagURITransaction(URIs[j], [tag]);
+          transactions.push(txn);
+        }
       }
       else if (PlacesUtils.nodeIsURI(node) &&
                PlacesUtils.nodeIsQuery(node.parent) &&
                PlacesUtils.asQuery(node.parent).queryOptions.queryType ==
                  Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY) {
         // This is a uri node inside an history query.
         PlacesUtils.bhistory.removePage(NetUtil.newURI(node.uri));
         // History deletes are not undoable, so we don't have a transaction.
@@ -907,17 +910,18 @@ PlacesController.prototype = {
       }
       else {
         // This is a common bookmark item.
         if (PlacesUtils.nodeIsFolder(node)) {
           // If this is a folder we add it to our array of folders, used
           // to skip nodes that are children of an already removed folder.
           removedFolders.push(node);
         }
-        transactions.push(PlacesUIUtils.ptm.removeItem(node.itemId));
+        let txn = new PlacesRemoveItemTransaction(node.itemId);
+        transactions.push(txn);
       }
     }
   },
 
   /**
    * Removes the set of selected ranges from bookmarks.
    * @param   txnName
    *          See |remove|.
@@ -926,18 +930,18 @@ PlacesController.prototype = {
     var ranges = this._view.removableSelectionRanges;
     var transactions = [];
     var removedFolders = [];
 
     for (var i = 0; i < ranges.length; i++)
       this._removeRange(ranges[i], transactions, removedFolders);
 
     if (transactions.length > 0) {
-      var txn = PlacesUIUtils.ptm.aggregateTransactions(txnName, transactions);
-      PlacesUIUtils.ptm.doTransaction(txn);
+      var txn = new PlacesAggregatedTransaction(txnName, transactions);
+      PlacesUtils.transactionManager.doTransaction(txn);
     }
   },
 
   /**
    * Removes the set of selected ranges from history.
    *
    * @note history deletes are not undoable.
    */
@@ -1273,37 +1277,35 @@ PlacesController.prototype = {
     }
 
     let transactions = [];
     let insertionIndex = ip.index;
     for (let i = 0; i < items.length; ++i) {
       if (ip.isTag) {
         // Pasting into a tag container means tagging the item, regardless of
         // the requested action.
-        transactions.push(
-          new PlacesTagURITransaction(NetUtil.newURI(items[i].uri),
-                                      [ip.itemId])
-        );
+        let tagTxn = new PlacesTagURITransaction(NetUtil.newURI(items[i].uri),
+                                                 [ip.itemId]);
+        transactions.push(tagTxn);
         continue;
       }
 
       // Adjust index to make sure items are pasted in the correct position.
       // If index is DEFAULT_INDEX, items are just appended.
       if (ip.index != PlacesUtils.bookmarks.DEFAULT_INDEX)
         insertionIndex = ip.index + i;
 
       transactions.push(
         PlacesUIUtils.makeTransaction(items[i], type, ip.itemId,
                                       insertionIndex, action == "copy")
       );
     }
  
-    PlacesUtils.transactionManager.doTransaction(
-      new PlacesAggregatedTransaction("Paste", transactions)
-    );
+    let aggregatedTxn = new PlacesAggregatedTransaction("Paste", transactions);
+    PlacesUtils.transactionManager.doTransaction(aggregatedTxn);
 
     // Cut/past operations are not repeatable, so clear the clipboard.
     if (action == "cut") {
       this._clearClipboard();
     }
 
     // Select the pasted items, they should be consecutive.
     let insertedNodeIds = [];
@@ -1543,27 +1545,28 @@ let PlacesControllerDragHelper = {
       if (index != -1 && dragginUp)
         index+= movedCount++;
 
       // If dragging over a tag container we should tag the item.
       if (insertionPoint.isTag &&
           insertionPoint.orientation == Ci.nsITreeView.DROP_ON) {
         let uri = NetUtil.newURI(unwrapped.uri);
         let tagItemId = insertionPoint.itemId;
-        transactions.push(PlacesUIUtils.ptm.tagURI(uri,[tagItemId]));
+        let tagTxn = new PlacesTagURITransaction(uri, [tagItemId]);
+        transactions.push(tagTxn);
       }
       else {
         transactions.push(PlacesUIUtils.makeTransaction(unwrapped,
                           flavor, insertionPoint.itemId,
                           index, doCopy));
       }
     }
 
-    let txn = PlacesUIUtils.ptm.aggregateTransactions("DropItems", transactions);
-    PlacesUIUtils.ptm.doTransaction(txn);
+    let txn = new PlacesAggregatedTransaction("DropItems", transactions);
+    PlacesUtils.transactionManager.doTransaction(txn);
   },
 
   /**
    * Checks if we can insert into a container.
    * @param   aContainer
    *          The container were we are want to drop
    */
   disallowInsertion: function(aContainer) {
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -430,25 +430,28 @@ var gEditItemOverlay = {
         if (tags.indexOf(currentTags[i]) == -1)
           tagsToRemove.push(currentTags[i]);
       }
       for (var i = 0; i < tags.length; i++) {
         if (currentTags.indexOf(tags[i]) == -1)
           tagsToAdd.push(tags[i]);
       }
 
-      if (tagsToRemove.length > 0)
-        txns.push(PlacesUIUtils.ptm.untagURI(this._uri, tagsToRemove));
-      if (tagsToAdd.length > 0)
-        txns.push(PlacesUIUtils.ptm.tagURI(this._uri, tagsToAdd));
+      if (tagsToRemove.length > 0) {
+        let untagTxn = new PlacesUntagURITransaction(this._uri, tagsToRemove);
+        txns.push(untagTxn);
+      }
+      if (tagsToAdd.length > 0) {
+        let tagTxn = new PlacesTagURITransaction(this._uri, tagsToAdd);
+        txns.push(tagTxn);
+      }
 
       if (txns.length > 0) {
-        var aggregate = PlacesUIUtils.ptm.aggregateTransactions("Update tags",
-                                                                txns);
-        PlacesUIUtils.ptm.doTransaction(aggregate);
+        let aggregate = new PlacesAggregatedTransaction("Update tags", txns);
+        PlacesUtils.transactionManager.doTransaction(aggregate);
 
         // Ensure the tagsField is in sync, clean it up from empty tags
         var tags = PlacesUtils.tagging.getTagsForURI(this._uri).join(", ");
         this._initTextField("tagsField", tags, false);
         return true;
       }
     }
     return false;
@@ -490,105 +493,116 @@ var gEditItemOverlay = {
         tagsToAdd[i] = [];
         for (var j = 0; j < tags.length; j++) {
           if (this._tags[i].indexOf(tags[j]) == -1)
             tagsToAdd[i].push(tags[j]);
         }
       }
 
       if (tagsToAdd.length > 0) {
-        for (i = 0; i < this._uris.length; i++) {
-          if (tagsToAdd[i].length > 0)
-            txns.push(PlacesUIUtils.ptm.tagURI(this._uris[i], tagsToAdd[i]));
+        for (let i = 0; i < this._uris.length; i++) {
+          if (tagsToAdd[i].length > 0) {
+            let tagTxn = new PlacesTagURITransaction(this._uris[i],
+                                                     tagsToAdd[i]);
+            txns.push(tagTxn);
+          }
         }
       }
       if (tagsToRemove.length > 0) {
-        for (var i = 0; i < this._uris.length; i++)
-          txns.push(PlacesUIUtils.ptm.untagURI(this._uris[i], tagsToRemove));
+        for (let i = 0; i < this._uris.length; i++) {
+          let untagTxn = new PlacesUntagURITransaction(this._uris[i],
+                                                       tagsToRemove);
+          txns.push(untagTxn);
+        }
       }
 
       if (txns.length > 0) {
-        var aggregate = PlacesUIUtils.ptm.aggregateTransactions("Update tags",
-                                                                txns);
-        PlacesUIUtils.ptm.doTransaction(aggregate);
+        let aggregate = new PlacesAggregatedTransaction("Update tags", txns);
+        PlacesUtils.transactionManager.doTransaction(aggregate);
 
         this._allTags = tags;
         this._tags = [];
-        for (i = 0; i < this._uris.length; i++)
+        for (let i = 0; i < this._uris.length; i++) {
           this._tags[i] = PlacesUtils.tagging.getTagsForURI(this._uris[i]);
+        }
 
         // Ensure the tagsField is in sync, clean it up from empty tags
         this._initTextField("tagsField", tags, false);
         return true;
       }
     }
     return false;
   },
 
   onNamePickerChange: function EIO_onNamePickerChange() {
     if (this._itemId == -1)
       return;
 
     var namePicker = this._element("namePicker")
-    var txns = [];
-    const ptm = PlacesUIUtils.ptm;
 
     // Here we update either the item title or its cached static title
     var newTitle = namePicker.value;
     if (!newTitle &&
         PlacesUtils.bookmarks.getFolderIdForItem(this._itemId) == PlacesUtils.tagsFolderId) {
       // We don't allow setting an empty title for a tag, restore the old one.
       this._initNamePicker();
     }
     else if (this._getItemStaticTitle() != newTitle) {
       this._mayUpdateFirstEditField("namePicker");
-      txns.push(ptm.editItemTitle(this._itemId, newTitle));
+      let txn = new PlacesEditItemTitleTransaction(this._itemId, newTitle);
+      PlacesUtils.transactionManager.doTransaction(txn);
     }
-
-    var aggregate = ptm.aggregateTransactions("Edit Item Title", txns);
-    ptm.doTransaction(aggregate);
   },
 
   onDescriptionFieldBlur: function EIO_onDescriptionFieldBlur() {
     var description = this._element("descriptionField").value;
     if (description != PlacesUIUtils.getItemDescription(this._itemId)) {
-      var txn = PlacesUIUtils.ptm
-                             .editItemDescription(this._itemId, description);
-      PlacesUIUtils.ptm.doTransaction(txn);
+      var annoObj = { name   : PlacesUIUtils.DESCRIPTION_ANNO,
+                      type   : Ci.nsIAnnotationService.TYPE_STRING,
+                      flags  : 0,
+                      value  : description,
+                      expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
+      var txn = new PlacesSetItemAnnotationTransaction(this._itemId, annoObj);
+      PlacesUtils.transactionManager.doTransaction(txn);
     }
   },
 
   onLocationFieldBlur: function EIO_onLocationFieldBlur() {
     var uri;
     try {
       uri = PlacesUIUtils.createFixedURI(this._element("locationField").value);
     }
     catch(ex) { return; }
 
     if (!this._uri.equals(uri)) {
-      var txn = PlacesUIUtils.ptm.editBookmarkURI(this._itemId, uri);
-      PlacesUIUtils.ptm.doTransaction(txn);
+      var txn = new PlacesEditBookmarkURITransaction(this._itemId, uri);
+      PlacesUtils.transactionManager.doTransaction(txn);
       this._uri = uri;
     }
   },
 
   onKeywordFieldBlur: function EIO_onKeywordFieldBlur() {
     var keyword = this._element("keywordField").value;
     if (keyword != PlacesUtils.bookmarks.getKeywordForBookmark(this._itemId)) {
-      var txn = PlacesUIUtils.ptm.editBookmarkKeyword(this._itemId, keyword);
-      PlacesUIUtils.ptm.doTransaction(txn);
+      var txn = new PlacesEditBookmarkKeywordTransaction(this._itemId, keyword);
+      PlacesUtils.transactionManager.doTransaction(txn);
     }
   },
 
   onLoadInSidebarCheckboxCommand:
   function EIO_onLoadInSidebarCheckboxCommand() {
     var loadInSidebarChecked = this._element("loadInSidebarCheckbox").checked;
-    var txn = PlacesUIUtils.ptm.setLoadInSidebar(this._itemId,
-                                                 loadInSidebarChecked);
-    PlacesUIUtils.ptm.doTransaction(txn);
+    var annoObj = { name   : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
+                    type   : Ci.nsIAnnotationService.TYPE_INT32,
+                    flags  : 0,
+                    value  : loadInSidebarChecked,
+                    expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
+    var txn = new PlacesSetItemAnnotationTransaction(this._itemId,
+                                                     annoObj);
+    PlacesUtils.transactionManager.doTransaction(txn);
   },
 
   toggleFolderTreeVisibility: function EIO_toggleFolderTreeVisibility() {
     var expander = this._element("foldersExpander");
     var folderTreeRow = this._element("folderTreeRow");
     if (!folderTreeRow.collapsed) {
       expander.className = "expander-down";
       expander.setAttribute("tooltiptext",
@@ -667,18 +681,20 @@ var gEditItemOverlay = {
       // menulist right away
       setTimeout(function(self) self.toggleFolderTreeVisibility(), 100, this);
       return;
     }
 
     // Move the item
     var container = this._getFolderIdFromMenuList();
     if (PlacesUtils.bookmarks.getFolderIdForItem(this._itemId) != container) {
-      var txn = PlacesUIUtils.ptm.moveItem(this._itemId, container, -1);
-      PlacesUIUtils.ptm.doTransaction(txn);
+      var txn = new PlacesMoveItemTransaction(this._itemId, 
+                                              container, 
+                                              PlacesUtils.bookmarks.DEFAULT_INDEX);
+      PlacesUtils.transactionManager.doTransaction(txn);
 
       // Mark the containing folder as recently-used if it isn't in the
       // static list
       if (container != PlacesUtils.unfiledBookmarksFolderId &&
           container != PlacesUtils.toolbarFolderId &&
           container != PlacesUtils.bookmarksMenuFolderId)
         this._markFolderAsRecentlyUsed(container);
     }
@@ -715,25 +731,27 @@ var gEditItemOverlay = {
   _markFolderAsRecentlyUsed:
   function EIO__markFolderAsRecentlyUsed(aFolderId) {
     var txns = [];
 
     // Expire old unused recent folders
     var anno = this._getLastUsedAnnotationObject(false);
     while (this._recentFolders.length > MAX_FOLDER_ITEM_IN_MENU_LIST) {
       var folderId = this._recentFolders.pop().folderId;
-      txns.push(PlacesUIUtils.ptm.setItemAnnotation(folderId, anno));
+      let annoTxn = new PlacesSetItemAnnotationTransaction(folderId, anno);
+      txns.push(annoTxn);
     }
 
     // Mark folder as recently used
     anno = this._getLastUsedAnnotationObject(true);
-    txns.push(PlacesUIUtils.ptm.setItemAnnotation(aFolderId, anno));
+    let annoTxn = new PlacesSetItemAnnotationTransaction(aFolderId, anno);
+    txns.push(annoTxn);
 
-    var aggregate = PlacesUIUtils.ptm.aggregateTransactions("Update last used folders", txns);
-    PlacesUIUtils.ptm.doTransaction(aggregate);
+    let aggregate = new PlacesAggregatedTransaction("Update last used folders", txns);
+    PlacesUtils.transactionManager.doTransaction(aggregate);
   },
 
   /**
    * Returns an object which could then be used to set/unset the
    * LAST_USED_ANNO annotation for a folder.
    *
    * @param aLastUsed
    *        Whether to set or unset the LAST_USED_ANNO annotation.
@@ -835,18 +853,18 @@ var gEditItemOverlay = {
     if (!ip || ip.itemId == PlacesUIUtils.allBookmarksFolderId) {
         ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
                                 PlacesUtils.bookmarks.DEFAULT_INDEX,
                                 Ci.nsITreeView.DROP_ON);
     }
 
     // XXXmano: add a separate "New Folder" string at some point...
     var defaultLabel = this._element("newFolderButton").label;
-    var txn = PlacesUIUtils.ptm.createFolder(defaultLabel, ip.itemId, ip.index);
-    PlacesUIUtils.ptm.doTransaction(txn);
+    var txn = new PlacesCreateFolderTransaction(defaultLabel, ip.itemId, ip.index);
+    PlacesUtils.transactionManager.doTransaction(txn);
     this._folderTree.focus();
     this._folderTree.selectItems([this._lastNewItem]);
     this._folderTree.startEditing(this._folderTree.view.selection.currentIndex,
                                   this._folderTree.columns.getFirstColumn());
   },
 
   // nsIDOMEventListener
   handleEvent: function EIO_nsIDOMEventListener(aEvent) {
--- a/browser/components/places/content/moveBookmarks.js
+++ b/browser/components/places/content/moveBookmarks.js
@@ -62,23 +62,25 @@ var gMoveBookmarksDialog = {
     var selectedFolderID = PlacesUtils.getConcreteItemId(selectedNode);
 
     var transactions = [];
     for (var i=0; i < this._nodes.length; i++) {
       // Nothing to do if the node is already under the selected folder
       if (this._nodes[i].parent.itemId == selectedFolderID)
         continue;
 
-      transactions.push(new
-        PlacesUIUtils.ptm.moveItem(this._nodes[i].itemId, selectedFolderID, -1));
+      let txn = new PlacesMoveItemTransaction(this._nodes[i].itemId,
+                                              selectedFolderID,
+                                              PlacesUtils.bookmarks.DEFAULT_INDEX);
+      transactions.push(txn);
     }
 
     if (transactions.length != 0) {
-      var txn = PlacesUIUtils.ptm.aggregateTransactions("Move Items", transactions);
-      PlacesUIUtils.ptm.doTransaction(txn);
+      let txn = new PlacesAggregatedTransaction("Move Items", transactions);
+      PlacesUtils.transactionManager.doTransaction(txn);
     }
   },
 
   newFolder: function MBD_newFolder() {
     // The command is disabled when the tree is not focused
     this.foldersTree.focus();
     goDoCommand("placesCmd_new:folder");
   }
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -823,21 +823,21 @@ var PlacesOrganizer = {
     var input = {value: defaultText};
     var save = prompts.prompt(null, title, inputLabel, input, null, check);
 
     // Don't add the query if the user cancels or clears the seach name.
     if (!save || input.value == "")
      return;
 
     // Add the place: uri as a bookmark under the bookmarks root.
-    var txn = PlacesUIUtils.ptm.createItem(placeURI,
-                                           PlacesUtils.bookmarksMenuFolderId,
-                                           PlacesUtils.bookmarks.DEFAULT_INDEX,
-                                           input.value);
-    PlacesUIUtils.ptm.doTransaction(txn);
+    var txn = new PlacesCreateBookmarkTransaction(placeURI,
+                                                  PlacesUtils.bookmarksMenuFolderId,
+                                                  PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                                  input.value);
+    PlacesUtils.transactionManager.doTransaction(txn);
 
     // select and load the new query
     this._places.selectPlaceURI(placeSpec);
   }
 };
 
 /**
  * A set of utilities relating to search within Bookmarks and History.
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -1655,18 +1655,18 @@ PlacesTreeView.prototype = {
 
     return true;
   },
 
   setCellText: function PTV_setCellText(aRow, aColumn, aText) {
     // We may only get here if the cell is editable.
     let node = this._rows[aRow];
     if (node.title != aText) {
-      let txn = PlacesUIUtils.ptm.editItemTitle(node.itemId, aText);
-      PlacesUIUtils.ptm.doTransaction(txn);
+      let txn = new PlacesEditItemTitleTransaction(node.itemId, aText);
+      PlacesUtils.transactionManager.doTransaction(txn);
     }
   },
 
   selectionChanged: function() { },
   cycleCell: function(aRow, aColumn) { },
   isSelectable: function(aRow, aColumn) { return false; },
   performAction: function(aAction) { },
   performActionOnRow: function(aAction, aRow) { },
--- a/browser/components/places/tests/browser/Makefile.in
+++ b/browser/components/places/tests/browser/Makefile.in
@@ -59,17 +59,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_history_sidebar_search.js \
 	browser_bookmarksProperties.js \
 	$(warning browser_forgetthissite_single.js temporarily disabled because of very frequent oranges, see bug 551540) \
 	browser_library_left_pane_commands.js \
 	browser_drag_bookmarks_on_toolbar.js \
 	browser_library_middleclick.js \
 	browser_library_views_liveupdate.js \
 	browser_views_liveupdate.js \
-	browser_sidebarpanels_click.js \
+	$(warning browser_sidebarpanels_click.js temporarily disabled cause it breaks the treeview, see bug 658744) \
 	sidebarpanels_click_test_page.html \
 	browser_library_infoBox.js \
 	browser_markPageAsFollowedLink.js \
 	framedPage.html \
 	frameLeft.html \
 	frameRight.html \
 	browser_toolbar_migration.js \
 	browser_library_batch_delete.js \
--- a/browser/components/places/tests/browser/browser_425884.js
+++ b/browser/components/places/tests/browser/browser_425884.js
@@ -81,40 +81,40 @@ function test() {
   folderANode.containerOpen = false;
 
   var transaction = PlacesUIUtils.makeTransaction(rawNode,
                                                   PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
                                                   testRootId,
                                                   -1,
                                                   true);
   ok(transaction, "create transaction");
-  PlacesUIUtils.ptm.doTransaction(transaction);
+  PlacesUtils.transactionManager.doTransaction(transaction);
   // confirm copy
   is(testRootNode.childCount, 2, "create test folder via copy");
 
   // validate the copy
   var folderBNode = testRootNode.getChild(1);
   validate(folderBNode);
 
   // undo the transaction, confirm the removal
-  PlacesUIUtils.ptm.undoTransaction();
+  PlacesUtils.transactionManager.undoTransaction();
   is(testRootNode.childCount, 1, "confirm undo removed the copied folder");
 
   // redo the transaction
-  PlacesUIUtils.ptm.redoTransaction();
+  PlacesUtils.transactionManager.redoTransaction();
   is(testRootNode.childCount, 2, "confirm redo re-copied the folder");
   folderBNode = testRootNode.getChild(1);
   validate(folderBNode);
 
   // Close containers, cleaning up their observers.
   testRootNode.containerOpen = false;
   toolbarNode.containerOpen = false;
 
   // clean up
-  PlacesUIUtils.ptm.undoTransaction();
+  PlacesUtils.transactionManager.undoTransaction();
   PlacesUtils.bookmarks.removeItem(folderAId);
 }
 
 function populate(aFolderId) {
   var folderId = PlacesUtils.bookmarks.createFolder(aFolderId, "test folder", -1);
   PlacesUtils.bookmarks.insertBookmark(folderId, PlacesUtils._uri("http://foo"), -1, "test bookmark");
   PlacesUtils.bookmarks.insertSeparator(folderId, -1);
 }
--- a/browser/components/places/tests/browser/browser_457473_no_copy_guid.js
+++ b/browser/components/places/tests/browser/browser_457473_no_copy_guid.js
@@ -80,43 +80,43 @@ function test() {
   // Create a copy transaction from the serialization.
   // this exercises the guid-filtering
   var transaction = PlacesUIUtils.makeTransaction(rawNode,
                                                   PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER,
                                                   testRootId, -1, true);
   ok(transaction, "create transaction");
 
   // execute it, copying to the test root folder
-  PlacesUIUtils.ptm.doTransaction(transaction);
+  PlacesUtils.transactionManager.doTransaction(transaction);
   is(testRootNode.childCount, 2, "create test folder via copy");
 
   // check GUIDs are different
   var folderBNode = testRootNode.getChild(1);
   ok(checkGUIDs(folderBNode, folderAGUIDs, false), "confirm folder A GUIDs don't match folder B GUIDs");
   var folderBGUIDs = getGUIDs(folderBNode);
   ok(checkGUIDs(folderBNode, folderBGUIDs, true), "confirm test of new GUIDs");
 
   // undo the transaction, confirm the removal
-  PlacesUIUtils.ptm.undoTransaction();
+  PlacesUtils.transactionManager.undoTransaction();
   is(testRootNode.childCount, 1, "confirm undo removed the copied folder");
 
   // redo the transaction
   // confirming GUIDs persist through undo/redo
-  PlacesUIUtils.ptm.redoTransaction();
+  PlacesUtils.transactionManager.redoTransaction();
   is(testRootNode.childCount, 2, "confirm redo re-copied the folder");
   folderBNode = testRootNode.getChild(1);
   ok(checkGUIDs(folderBNode, folderAGUIDs, false), "folder B GUIDs after undo/redo don't match folder A GUIDs"); // sanity check
   ok(checkGUIDs(folderBNode, folderBGUIDs, true), "folder B GUIDs after under/redo should match pre-undo/redo folder B GUIDs");
 
   // Close containers, cleaning up their observers.
   testRootNode.containerOpen = false;
   toolbarNode.containerOpen = false;
 
   // clean up
-  PlacesUIUtils.ptm.undoTransaction();
+  PlacesUtils.transactionManager.undoTransaction();
   PlacesUtils.bookmarks.removeItem(testRootId);
 }
 
 function getGUIDs(aNode) {
   PlacesUtils.asContainer(aNode);
   aNode.containerOpen = true;
   var GUIDs = {
     folder: PlacesUtils.bookmarks.getItemGUID(aNode.itemId),
--- a/browser/components/places/tests/unit/xpcshell.ini
+++ b/browser/components/places/tests/unit/xpcshell.ini
@@ -14,11 +14,9 @@ tail =
 [test_browserGlue_distribution.js]
 [test_browserGlue_migrate.js]
 [test_browserGlue_prefs.js]
 [test_browserGlue_restore.js]
 [test_browserGlue_shutdown.js]
 [test_browserGlue_smartBookmarks.js]
 [test_clearHistory_shutdown.js]
 [test_leftpane_corruption_handling.js]
-[test_placesTxn.js]
 [test_PUIU_makeTransaction.js]
-[test_txnGUIDs.js]
--- a/browser/components/preferences/sync.js
+++ b/browser/components/preferences/sync.js
@@ -152,40 +152,40 @@ let gSyncPane = {
    *          "pair"  -- pair a device first
    *          "reset" -- reset sync
    */
   openSetup: function (wizardType) {
     var win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
     if (win)
       win.focus();
     else {
-      window.openDialog("chrome://browser/content/syncSetup.xul",
+      window.openDialog("chrome://browser/content/sync/setup.xul",
                         "weaveSetup", "centerscreen,chrome,resizable=no",
                         wizardType);
     }
   },
 
   openQuotaDialog: function () {
     let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
     if (win)
       win.focus();
     else 
-      window.openDialog("chrome://browser/content/syncQuota.xul", "",
+      window.openDialog("chrome://browser/content/sync/quota.xul", "",
                         "centerscreen,chrome,dialog,modal");
   },
 
   openAddDevice: function () {
     if (!Weave.Utils.ensureMPUnlocked())
       return;
     
     let win = Services.wm.getMostRecentWindow("Sync:AddDevice");
     if (win)
       win.focus();
     else 
-      window.openDialog("chrome://browser/content/syncAddDevice.xul",
+      window.openDialog("chrome://browser/content/sync/addDevice.xul",
                         "syncAddDevice", "centerscreen,chrome,resizable=no");
   },
 
   resetSync: function () {
     this.openSetup("reset");
   }
 }
 
--- a/browser/components/preferences/sync.xul
+++ b/browser/components/preferences/sync.xul
@@ -64,17 +64,17 @@
       <preference id="engine.prefs"     name="services.sync.engine.prefs"     type="bool"/>
       <preference id="engine.passwords" name="services.sync.engine.passwords" type="bool"/>
     </preferences>
 
 
     <script type="application/javascript"
             src="chrome://browser/content/preferences/sync.js"/>
     <script type="application/javascript"
-            src="chrome://browser/content/syncUtils.js"/>
+            src="chrome://browser/content/sync/utils.js"/>
 
 
       <deck id="weavePrefsDeck">
         <vbox id="noAccount" align="center">
           <spacer flex="1"/>
           <description id="syncDesc">
             &weaveDesc.label;
           </description>
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -37,30 +37,35 @@
 # ***** END LICENSE BLOCK *****
 
 MOZ_APP_BASENAME=Firefox
 MOZ_APP_VENDOR=Mozilla
 MOZ_UPDATER=1
 MOZ_PHOENIX=1
 
 if test "$OS_ARCH" = "WINNT"; then
-  MOZ_VERIFY_MAR_SIGNATURE=1
   if ! test "$HAVE_64BIT_OS"; then
+    MOZ_VERIFY_MAR_SIGNATURE=1
     MOZ_MAINTENANCE_SERVICE=1
   fi
 fi
 
 MOZ_CHROME_FILE_FORMAT=omni
 MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_SYNC=1
 MOZ_APP_VERSION=$FIREFOX_VERSION
 MOZ_EXTENSIONS_DEFAULT=" gnomevfs"
 # MOZ_APP_DISPLAYNAME will be set by branding/configure.sh
-# Changing either of these values requires a clobber to ensure correct results,
+# Changing MOZ_*BRANDING_DIRECTORY requires a clobber to ensure correct results,
 # because branding dependencies are broken.
+# MOZ_BRANDING_DIRECTORY is the default branding directory used when none is
+# specified. It should never point to the "official" branding directory.
+# For mozilla-beta, mozilla-release, or mozilla-central repositories, use
+# "nightly" branding (until bug 659568 is fixed).
+# For the mozilla-aurora repository, use "aurora".
 MOZ_BRANDING_DIRECTORY=browser/branding/nightly
 MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
 MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
 # This should usually be the same as the value MAR_CHANNEL_ID.
 # If more than one ID is needed, then you should use a comma separated list
 # of values.
 ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
 # The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
--- a/browser/devtools/sourceeditor/orion/orion.js
+++ b/browser/devtools/sourceeditor/orion/orion.js
@@ -6652,17 +6652,16 @@ define("orion/textview/textView", ['orio
 			this._viewDiv = viewDiv;
 			viewDiv.id = "viewDiv";
 			viewDiv.tabIndex = -1;
 			viewDiv.style.overflow = "auto";
 			viewDiv.style.position = "absolute";
 			viewDiv.style.top = "0px";
 			viewDiv.style.borderWidth = "0px";
 			viewDiv.style.margin = "0px";
-			viewDiv.style.MozOutline = "none";
 			viewDiv.style.outline = "none";
 			body.appendChild(viewDiv);
 				
 			var scrollDiv = frameDocument.createElement("DIV");
 			this._scrollDiv = scrollDiv;
 			scrollDiv.id = "scrollDiv";
 			scrollDiv.style.margin = "0px";
 			scrollDiv.style.borderWidth = "0px";
@@ -6695,17 +6694,16 @@ define("orion/textview/textView", ['orio
 			clientDiv.className = "viewContent";
 			this._clientDiv = clientDiv;
 			clientDiv.id = "clientDiv";
 			clientDiv.style.whiteSpace = "pre";
 			clientDiv.style.position = this._clipDiv ? "absolute" : "fixed";
 			clientDiv.style.borderWidth = "0px";
 			clientDiv.style.margin = "0px";
 			clientDiv.style.padding = "0px";
-			clientDiv.style.MozOutline = "none";
 			clientDiv.style.outline = "none";
 			clientDiv.style.zIndex = "1";
 			if (isPad) {
 				clientDiv.style.WebkitTapHighlightColor = "transparent";
 			}
 			(this._clipDiv || scrollDiv).appendChild(clientDiv);
 
 			if (isFirefox && !clientDiv.setCapture) {
@@ -8375,45 +8373,42 @@ define("orion/textview/textView", ['orio
 				this._hightlightRGB = "Highlight";
 				var selDiv1 = frameDocument.createElement("DIV");
 				this._selDiv1 = selDiv1;
 				selDiv1.id = "selDiv1";
 				selDiv1.style.position = this._clipDiv ? "absolute" : "fixed";
 				selDiv1.style.borderWidth = "0px";
 				selDiv1.style.margin = "0px";
 				selDiv1.style.padding = "0px";
-				selDiv1.style.MozOutline = "none";
 				selDiv1.style.outline = "none";
 				selDiv1.style.background = this._hightlightRGB;
 				selDiv1.style.width = "0px";
 				selDiv1.style.height = "0px";
 				selDiv1.style.zIndex = "0";
 				parent.appendChild(selDiv1);
 				var selDiv2 = frameDocument.createElement("DIV");
 				this._selDiv2 = selDiv2;
 				selDiv2.id = "selDiv2";
 				selDiv2.style.position = this._clipDiv ? "absolute" : "fixed";
 				selDiv2.style.borderWidth = "0px";
 				selDiv2.style.margin = "0px";
 				selDiv2.style.padding = "0px";
-				selDiv2.style.MozOutline = "none";
 				selDiv2.style.outline = "none";
 				selDiv2.style.background = this._hightlightRGB;
 				selDiv2.style.width = "0px";
 				selDiv2.style.height = "0px";
 				selDiv2.style.zIndex = "0";
 				parent.appendChild(selDiv2);
 				var selDiv3 = frameDocument.createElement("DIV");
 				this._selDiv3 = selDiv3;
 				selDiv3.id = "selDiv3";
 				selDiv3.style.position = this._clipDiv ? "absolute" : "fixed";
 				selDiv3.style.borderWidth = "0px";
 				selDiv3.style.margin = "0px";
 				selDiv3.style.padding = "0px";
-				selDiv3.style.MozOutline = "none";
 				selDiv3.style.outline = "none";
 				selDiv3.style.background = this._hightlightRGB;
 				selDiv3.style.width = "0px";
 				selDiv3.style.height = "0px";
 				selDiv3.style.zIndex = "0";
 				parent.appendChild(selDiv3);
 				
 				/*
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -150,16 +150,17 @@
 @BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 #ifdef MOZ_B2G_BT
 @BINPATH@/components/dom_bluetooth.xpt
 #endif
 @BINPATH@/components/dom_canvas.xpt
+@BINPATH@/components/dom_contacts.xpt
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
@@ -404,16 +405,19 @@
 @BINPATH@/components/SyncComponents.manifest
 @BINPATH@/components/Weave.js
 #endif
 @BINPATH@/components/TelemetryPing.js
 @BINPATH@/components/TelemetryPing.manifest
 @BINPATH@/components/messageWakeupService.js
 @BINPATH@/components/messageWakeupService.manifest
 
+@BINPATH@/components/ContactManager.js
+@BINPATH@/components/ContactManager.manifest
+
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
 @BINPATH@/components/nsSafebrowsingApplication.manifest
 @BINPATH@/components/nsSafebrowsingApplication.js
 @BINPATH@/components/nsURLClassifier.manifest
 @BINPATH@/components/nsUrlClassifierHashCompleter.js
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -328,8 +328,12 @@ syncPromoNotification.learnMoreLinkText=
 # LOCALIZATION NOTE (telemetryPrompt): %1$S will be replaced by brandFullName,
 # and %2$S by the value of the toolkit.telemetry.server_owner preference.
 telemetryPrompt = Will you help improve %1$S by sending anonymous information about performance, hardware characteristics, feature usage, and browser customizations to %2$S?
 telemetryLinkLabel = Learn More
 telemetryYesButtonLabel2 = Yes, I want to help
 telemetryYesButtonAccessKey = Y
 telemetryNoButtonLabel = No
 telemetryNoButtonAccessKey = N
+# Telemetry opt-out prompt for Aurora and Nightly
+# LOCALIZATION NOTE (telemetryOptOutPrompt): %1$S and %3$S will be replaced by
+# brandFullName, and %2$S by the value of the toolkit.telemetry.server_owner preference.
+telemetryOptOutPrompt = %1$S sends information about performance, hardware, usage and customizations back to %2$S to help improve %3$S.
--- a/browser/themes/gnomestripe/syncCommon.css
+++ b/browser/themes/gnomestripe/syncCommon.css
@@ -1,9 +1,9 @@
-/* The following are used by both syncSetup.xul and syncGenericChange.xul */
+/* The following are used by both sync/setup.xul and sync/genericChange.xul */
 .status {
   color: -moz-dialogtext;
 }
 
 .statusIcon {
   -moz-margin-start: 4px;
   max-height: 16px;
   max-width: 16px;
@@ -16,17 +16,17 @@
 .statusIcon[status="error"] {
   list-style-image: url("moz-icon://stock/gtk-dialog-error?size=menu");
 }
 
 .statusIcon[status="success"] {
   list-style-image: url("moz-icon://stock/gtk-dialog-info?size=menu");
 }
 
-/* .data is only used by syncGenericChange.xul, but it seems unnecessary to have
+/* .data is only used by sync/genericChange.xul, but it seems unnecessary to have
    a separate stylesheet for it. */
 .data {
   font-size: 90%;
   font-weight: bold;
 }
 
 dialog#change-dialog {
   width: 40em;
--- a/browser/themes/pinstripe/syncCommon.css
+++ b/browser/themes/pinstripe/syncCommon.css
@@ -1,9 +1,9 @@
-/* The following are used by both syncSetup.xul and syncGenericChange.xul */
+/* The following are used by both sync/setup.xul and sync/genericChange.xul */
 .status {
   color: -moz-dialogtext;
 }
 
 .statusIcon {
   -moz-margin-start: 4px;
   max-height: 16px;
   max-width: 16px;
@@ -16,17 +16,17 @@
 .statusIcon[status="error"] {
   list-style-image: url("chrome://global/skin/icons/error-16.png");
 }
 
 .statusIcon[status="success"] {
   list-style-image: url("chrome://global/skin/icons/information-16.png");
 }
 
-/* .data is only used by syncGenericChange.xul, but it seems unnecessary to have
+/* .data is only used by sync/genericChange.xul, but it seems unnecessary to have
    a separate stylesheet for it. */
 .data {
   font-size: 90%;
   font-weight: bold;
 }
 
 dialog#change-dialog {
   width: 40em;
--- a/browser/themes/winstripe/syncCommon.css
+++ b/browser/themes/winstripe/syncCommon.css
@@ -1,9 +1,9 @@
-/* The following are used by both syncSetup.xul and syncGenericChange.xul */
+/* The following are used by both sync/setup.xul and sync/genericChange.xul */
 .status {
   color: -moz-dialogtext;
 }
 
 .statusIcon {
   -moz-margin-start: 4px;
   max-height: 16px;
   max-width: 16px;
@@ -16,17 +16,17 @@
 .statusIcon[status="error"] {
   list-style-image: url("chrome://global/skin/icons/error-16.png");
 }
 
 .statusIcon[status="success"] {
   list-style-image: url("chrome://global/skin/icons/information-16.png");
 }
 
-/* .data is only used by syncGenericChange.xul, but it seems unnecessary to have
+/* .data is only used by sync/genericChange.xul, but it seems unnecessary to have
    a separate stylesheet for it. */
 .data {
   font-size: 90%;
   font-weight: bold;
 }
 
 dialog#change-dialog {
   width: 40em;
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -2,12 +2,12 @@ dnl Add compiler specific options
 
 AC_DEFUN([MOZ_COMPILER_OPTS],
 [
 if test "$CLANG_CXX"; then
     ## We disable return-type-c-linkage because jsval is defined as a C++ type but is
     ## returned by C functions. This is possible because we use knowledge about the ABI
     ## to typedef it to a C type with the same layout when the headers are included
     ## from C.
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-return-type-c-linkage"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
 fi
 ])
 
deleted file mode 100644
--- a/build/mobile/devicemanager-run-test.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is remote test framework.
-#
-# The Initial Developer of the Original Code is
-# the Mozilla Corporation.
-# Portions created by the Initial Developer are Copyright (C) 2010
-# 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 *****
-
-import devicemanager
-import devicemanagerUtils
-import sys
-import os
-
-def main():
-    ip_addr = os.environ.get("DEVICE_IP")
-    port = os.environ.get("DEVICE_PORT")
-    gre_path = os.environ.get("REMOTE_GRE_PATH").replace('\\','/')
-
-    if ip_addr == None:
-        print "Error: please define the environment variable DEVICE_IP before running this test"
-        sys.exit(1)
-
-    if port == None:
-        print "Error: please define the environment variable DEVICE_PORT before running this test"
-        sys.exit(1)
-
-    if gre_path == None:
-        print "Error: please define the environment variable REMOTE_GRE_PATH before running this test"
-        sys.exit(1)
-
-    dm = devicemanagerUtils.getDeviceManager(ip_addr, int(port))
-    if len(sys.argv) < 2:
-        print "usage python devicemanager-run-test.py <test program> [args1 [arg2..]]"
-        sys.exit(1)
-
-    cmd = sys.argv[1]
-    args = ' '
-    if len(sys.argv) > 2:
-        args = ' ' + ' '.join(sys.argv[2:])
-
-    dm.debug = 0
-    lastslash = cmd.rfind('/');
-    if lastslash == -1:
-        lastslash = 0
-    dm.pushFile(cmd, gre_path + cmd[lastslash:])
-    process = dm.launchProcess([gre_path  + cmd[lastslash:] + args])
-    output_list = dm.communicate(process)
-    ret = -1
-    if (output_list != None and output_list[0] != None):
-        try:
-            output = output_list[0]
-            index = output.find('exited with return code')
-            print output[0:index]
-            retstr = (output[index + 24 : output.find('\n', index)])
-            ret = int(retstr)
-        except ValueError:
-            ret = -1
-    sys.exit(ret)
-
-if __name__ == '__main__':
-    main()
--- a/build/mobile/devicemanager.py
+++ b/build/mobile/devicemanager.py
@@ -192,41 +192,16 @@ class DeviceManager:
     """
     external function
     DEPRECATED: Use shell() or launchApplication() for new code
     returns:
     success: output filename
     failure: None
     """
 
-  def communicate(self, process, timeout = 600, interval = 5):
-    """
-    loops until 'process' has exited or 'timeout' seconds is reached
-    loop sleeps for 'interval' seconds between iterations
-    external function
-    returns:
-    success: [file contents, None]
-    failure: [None, None]
-    """
-    
-    timed_out = True
-    if (timeout > 0):
-      total_time = 0
-      while total_time < timeout:
-        time.sleep(interval)
-        if self.processExist(process) == None:
-          timed_out = False
-          break
-        total_time += interval
-
-    if (timed_out == True):
-      return [None, None]
-
-    return [self.getFile(process, "temp.txt"), None]
-
   def processExist(self, appname):
     """
     iterates process list and returns pid if exists, otherwise None
     external function
     returns:
     success: pid
     failure: None
     """
@@ -596,24 +571,24 @@ def _pop_last_line(file):
   '''
   Utility function to get the last line from a file (shared between ADB and
   SUT device managers). Function also removes it from the file. Intended to
   strip off the return code from a shell command.
   '''
   bytes_from_end = 1
   file.seek(0, 2)
   length = file.tell() + 1
-  while bytes_from_end <= length:
+  while bytes_from_end < length:
     file.seek((-1)*bytes_from_end, 2)
     data = file.read()
 
-    if bytes_from_end == length and len(data) == 0: # no data, return None
+    if bytes_from_end == length-1 and len(data) == 0: # no data, return None
       return None
 
-    if data[0] == '\n' or bytes_from_end == length:
+    if data[0] == '\n' or bytes_from_end == length-1:
       # found the last line, which should have the return value
       if data[0] == '\n':
         data = data[1:]
 
       # truncate off the return code line
       file.truncate(length - bytes_from_end)
       file.seek(0,2)
       file.write('\0')
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -20,21 +20,27 @@ class DeviceManagerADB(DeviceManager):
     self.tempDir = None
     if packageName == None:
       if os.getenv('USER'):
         packageName = 'org.mozilla.fennec_' + os.getenv('USER')
       else:
         packageName = 'org.mozilla.fennec_'
     self.Init(packageName)
 
+  def __del__(self):
+    if self.host:
+      self.disconnectRemoteADB()
+
   def Init(self, packageName):
     # Initialization code that may fail: Catch exceptions here to allow
     # successful initialization even if, for example, adb is not installed.
     try:
       self.verifyADB()
+      if self.host:
+        self.connectRemoteADB()
       self.verifyRunAs(packageName)
     except:
       self.useRunAs = False
       self.packageName = packageName
     try:
       self.verifyZip()
     except:
       self.useZip = False
@@ -73,17 +79,17 @@ class DeviceManagerADB(DeviceManager):
       if arg.find(" ") or arg.find("(") or arg.find(")") or arg.find("\""):
         cmd[index] = '\'%s\'' % arg
 
     # This is more complex than you'd think because adb doesn't actually
     # return the return code from a process, so we have to capture the output
     # to get it
     # FIXME: this function buffers all output of the command into memory,
     # always. :(
-    cmdline = subprocess.list2cmdline(cmd) + "; echo $?"
+    cmdline = " ".join(cmd) + "; echo $?"
 
     # prepend cwd and env to command if necessary
     if cwd:
       cmdline = "cd %s; %s" % (cwd, cmdline)
     if env:
       envstr = '; '.join(map(lambda x: 'export %s=%s' % (x[0], x[1]), env.iteritems()))
       cmdline = envstr + "; " + cmdline
 
@@ -99,16 +105,22 @@ class DeviceManagerADB(DeviceManager):
       if m:
         return_code = m.group(1)
         outputfile.seek(-2, 2)
         outputfile.truncate() # truncate off the return code
         return return_code
 
     return None
 
+  def connectRemoteADB(self):
+    self.checkCmd(["connect", self.host + ":" + str(self.port)])
+
+  def disconnectRemoteADB(self):
+    self.checkCmd(["disconnect", self.host + ":" + str(self.port)])
+
   # external function
   # returns:
   #  success: True
   #  failure: False
   def pushFile(self, localname, destname):
     try:
       if (os.name == "nt"):
         destname = destname.replace('\\', '/')
@@ -432,31 +444,31 @@ class DeviceManagerADB(DeviceManager):
   # remote directory doesn't exist but also so that we don't call isDir
   # twice when recursing.
   # returns:
   #  success: list of files, string
   #  failure: None
   def getDirectory(self, remoteDir, localDir, checkDir=True):
     ret = []
     p = self.runCmd(["pull", remoteDir, localDir])
-    p.stderr.readline()
-    line = p.stderr.readline()
+    p.stdout.readline()
+    line = p.stdout.readline()
     while (line):
       els = line.split()
       f = els[len(els) - 1]
       i = f.find(localDir)
       if (i != -1):
         if (localDir[len(localDir) - 1] != '/'):
           i = i + 1
         f = f[i + len(localDir):]
       i = f.find("/")
       if (i > 0):
         f = f[0:i]
       ret.append(f)
-      line =  p.stderr.readline()
+      line =  p.stdout.readline()
     #the last line is a summary
     if (len(ret) > 0):
       ret.pop()
     return ret
 
 
 
   # true/false check if the two files have the same md5 sum
--- a/build/mobile/droid.py
+++ b/build/mobile/droid.py
@@ -34,16 +34,17 @@
 # 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 *****
 
 from devicemanagerADB import DeviceManagerADB
 from devicemanagerSUT import DeviceManagerSUT
+import StringIO
 
 class DroidMixin(object):
   """Mixin to extend DeviceManager with Android-specific functionality"""
 
   def launchApplication(self, app, activity="App",
                         intent="android.intent.action.VIEW", env=None,
                         url=None, extra_args=None):
     """
@@ -54,27 +55,27 @@ class DroidMixin(object):
     """
     # only one instance of an application may be running at once
     if self.processExist(app):
       return False
 
     acmd = [ "am", "start", "-a", intent, "-W", "-n", "%s/.%s" % (app, activity)]
 
     if extra_args:
-      acmd.extend(["--es", "args", " ".join(args)])
+      acmd.extend(["--es", "args", " ".join(extra_args)])
 
     if env:
       envCnt = 0
       # env is expected to be a dict of environment variables
       for envkey, envval in env.iteritems():
         acmd.extend(["--es", "env" + str(envCnt), envkey + "=" + envval])
         envCnt += 1
 
     if url:
-      acmd.extend(["-d", ''.join(['"', url, '"'])])
+      acmd.extend(["-d", ''.join(["'", url, "'"])])
 
     # shell output not that interesting and debugging logs should already
     # show what's going on here... so just create an empty memory buffer
     # and ignore
     shellOutput = StringIO.StringIO()
     if self.shell(acmd, shellOutput) == 0:
       return True
 
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -136,27 +136,27 @@ class RemoteAutomation(Automation):
 #TODO: figure out which platform require NO_EM_RESTART
 #        return app, ['--environ:NO_EM_RESTART=1'] + args
         return app, args
 
     def getLanIp(self):
         nettools = NetworkTools()
         return nettools.getLanIp()
 
-    def Process(self, cmd, stdout = None, stderr = None, env = None, cwd = '.'):
+    def Process(self, cmd, stdout = None, stderr = None, env = None, cwd = None):
         if stdout == None or stdout == -1 or stdout == subprocess.PIPE:
           stdout = self._remoteLog
 
         return self.RProcess(self._devicemanager, cmd, stdout, stderr, env, cwd)
 
     # be careful here as this inner class doesn't have access to outer class members    
     class RProcess(object):
         # device manager process
         dm = None
-        def __init__(self, dm, cmd, stdout = None, stderr = None, env = None, cwd = '.'):
+        def __init__(self, dm, cmd, stdout = None, stderr = None, env = None, cwd = None):
             self.dm = dm
             self.stdoutlen = 0
             self.proc = dm.launchProcess(cmd, stdout, cwd, env, True)
             if (self.proc is None):
               if cmd[0] == 'am':
                 self.proc = stdout
               else:
                 raise Exception("unable to launch process")
--- a/build/mobile/sutagent/android/DoCommand.java
+++ b/build/mobile/sutagent/android/DoCommand.java
@@ -62,16 +62,17 @@ import java.security.NoSuchAlgorithmExce
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.StringTokenizer;
 import java.util.TimeZone;
 import java.util.zip.Adler32;
 import java.util.zip.CheckedInputStream;
 import java.util.zip.CheckedOutputStream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
@@ -131,17 +132,17 @@ public class DoCommand {
 
     String    currentDir = "/";
     String    sErrorPrefix = "##AGENT-WARNING## ";
     boolean bTraceOn = false;
 
     String ffxProvider = "org.mozilla.ffxcp";
     String fenProvider = "org.mozilla.fencp";
 
-    private final String prgVersion = "SUTAgentAndroid Version 1.06";
+    private final String prgVersion = "SUTAgentAndroid Version 1.07";
 
     public enum Command
         {
         RUN ("run"),
         EXEC ("exec"),
         EXECCWD ("execcwd"),
         ENVRUN ("envrun"),
         KILL ("kill"),
@@ -2444,16 +2445,58 @@ private void CancelNotification()
                 {
                 if (lProcesses.get(lcv).processName.contains(sProcName))
                     {
                     sRet = sErrorPrefix + "Unable to kill " + nPID + " " + strProcName + "\n";
                     break;
                     }
                 }
             }
+        else
+            {
+            // To kill processes other than Java applications - processes
+            // like xpcshell - a different strategy is necessary: use ps
+            // to find the process' PID.
+            try
+                {
+                pProc = Runtime.getRuntime().exec("ps");
+                RedirOutputThread outThrd = new RedirOutputThread(pProc, null);
+                outThrd.start();
+                outThrd.join(10000);
+                sTmp = outThrd.strOutput;
+                StringTokenizer stokLines = new StringTokenizer(sTmp, "\n");
+                while(stokLines.hasMoreTokens())
+                    {
+                    String sLine = stokLines.nextToken();
+                    StringTokenizer stokColumns = new StringTokenizer(sLine, " \t\n");
+                    stokColumns.nextToken();
+                    String sPid = stokColumns.nextToken();
+                    stokColumns.nextToken();
+                    stokColumns.nextToken();
+                    stokColumns.nextToken();
+                    stokColumns.nextToken();
+                    stokColumns.nextToken();
+                    stokColumns.nextToken();
+                    String sName = null;
+                    if (stokColumns.hasMoreTokens())
+                        {
+                        sName = stokColumns.nextToken();
+                        if (sName.contains(sProcName))
+                            {
+                            NewKillProc(sPid, out);
+                            sRet = "Successfully killed " + sPid + " " + sName + "\n";
+                            }
+                        }
+                    }
+                }
+            catch (Exception e)
+                {
+                e.printStackTrace();
+                }
+            }
 
         return (sRet);
         }
 
     public boolean IsProcessDead(String sProcName)
         {
         boolean bRet = false;
         ActivityManager aMgr = (ActivityManager) contextWrapper.getSystemService(Activity.ACTIVITY_SERVICE);
@@ -2867,25 +2910,20 @@ private void CancelNotification()
             }
 
         return (sRet);
         }
 
     public String NewKillProc(String sProcId, OutputStream out)
         {
         String sRet = "";
-        String [] theArgs = new String [3];
-
-        theArgs[0] = "su";
-        theArgs[1] = "-c";
-        theArgs[2] = "kill " + sProcId;
 
         try
             {
-            pProc = Runtime.getRuntime().exec(theArgs);
+            pProc = Runtime.getRuntime().exec("kill "+sProcId);
             RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
             outThrd.start();
             outThrd.join(5000);
             }
         catch (IOException e)
             {
             sRet = e.getMessage();
             e.printStackTrace();
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -245,16 +245,18 @@ if not os.path.exists(source_dir):
     extract(unifdef_source_tar, source_dir)
     extract(mpc_source_tar, source_dir)
     extract(mpfr_source_tar, source_dir)
     extract(gmp_source_tar, source_dir)
     extract(gcc_source_tar, source_dir)
     patch('plugin_finish_decl.diff', 0, gcc_source_dir)
     patch('pr49911.diff', 1, gcc_source_dir)
     patch('r159628-r163231-r171807.patch', 1, gcc_source_dir)
+    patch('gcc-fixinc.patch', 1, gcc_source_dir)
+    patch('gcc-include.patch', 1, gcc_source_dir)
 
 if os.path.exists(build_dir):
     shutil.rmtree(build_dir)
 os.makedirs(build_dir)
 
 build_aux_tools(build_dir)
 
 stage1_dir = build_dir + '/stage1'
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/gcc-fixinc.patch
@@ -0,0 +1,12 @@
+diff -ru a/fixincludes/Makefile.in b/fixincludes/Makefile.in
+--- a/fixincludes/Makefile.in	2009-07-30 18:33:49.000000000 -0400
++++ b/fixincludes/Makefile.in	2012-02-27 14:59:09.371875951 -0500
+@@ -126,7 +126,7 @@
+ fixlib.o    : fixlib.c
+ 
+ fixinc.sh : fixinc.in mkfixinc.sh Makefile
+-	srcdir="$(srcdir)" $(SHELL) $(srcdir)/mkfixinc.sh $(target)
++	echo "#!/bin/sh" > $@
+ 
+ $(srcdir)/fixincl.x: @MAINT@ fixincl.tpl inclhack.def
+ 	cd $(srcdir) ; $(SHELL) ./genfixes
new file mode 100644
--- /dev/null
+++ b/build/unix/build-toolchain/gcc-include.patch
@@ -0,0 +1,24 @@
+diff -ru a/configure b/configure
+--- a/configure	2010-10-06 06:29:55.000000000 -0400
++++ b/configure	2012-02-27 20:46:26.303460301 -0500
+@@ -8047,7 +8047,7 @@
+ # being built; programs in there won't even run.
+ if test "${build}" = "${host}" && test -d ${srcdir}/gcc; then
+   # Search for pre-installed headers if nothing else fits.
+-  FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -B$(build_tooldir)/bin/ -B$(build_tooldir)/lib/ -isystem $(build_tooldir)/include -isystem $(build_tooldir)/sys-include'
++  FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -B$(exec_prefix)/bin/ -B$(exec_prefix)/lib/ -isystem $(exec_prefix)/include -isystem $(exec_prefix)/sys-include'
+ fi
+ 
+ if test "x${use_gnu_ld}" = x &&
+diff -ru a/configure.ac b/configure.ac
+--- a/configure.ac	2010-10-06 06:29:55.000000000 -0400
++++ b/configure.ac	2012-02-27 20:46:22.587442745 -0500
+@@ -3100,7 +3100,7 @@
+ # being built; programs in there won't even run.
+ if test "${build}" = "${host}" && test -d ${srcdir}/gcc; then
+   # Search for pre-installed headers if nothing else fits.
+-  FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -B$(build_tooldir)/bin/ -B$(build_tooldir)/lib/ -isystem $(build_tooldir)/include -isystem $(build_tooldir)/sys-include'
++  FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -B$(exec_prefix)/bin/ -B$(exec_prefix)/lib/ -isystem $(exec_prefix)/include -isystem $(exec_prefix)/sys-include'
+ fi
+ 
+ if test "x${use_gnu_ld}" = x &&
--- a/caps/src/nsSecurityManagerFactory.cpp
+++ b/caps/src/nsSecurityManagerFactory.cpp
@@ -68,41 +68,41 @@ nsSecurityNameSet::nsSecurityNameSet()
 
 nsSecurityNameSet::~nsSecurityNameSet()
 {
 }
 
 NS_IMPL_ISUPPORTS1(nsSecurityNameSet, nsIScriptExternalNameSet)
 
 static JSString *
-getStringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, uintN argc, jsval *argv)
+getStringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, unsigned argc, jsval *argv)
 {
     if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
         JS_ReportError(cx, "String argument expected");
         return nsnull;
     }
 
     /*
      * We don't want to use JS_ValueToString because we want to be able
      * to have an object to represent a target in subsequent versions.
      */
     return JSVAL_TO_STRING(argv[argNum]);
 }
 
 static bool
-getBytesArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, uintN argc, jsval *argv,
+getBytesArgument(JSContext *cx, JSObject *obj, PRUint16 argNum, unsigned argc, jsval *argv,
                  JSAutoByteString *bytes)
 {
     JSString *str = getStringArgument(cx, obj, argNum, argc, argv);
     return str && bytes->encode(cx, str);
 }
 
 static void
 getUTF8StringArgument(JSContext *cx, JSObject *obj, PRUint16 argNum,
-                      uintN argc, jsval *argv, nsCString& aRetval)
+                      unsigned argc, jsval *argv, nsCString& aRetval)
 {
     aRetval.Truncate();
 
     if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
         JS_ReportError(cx, "String argument expected");
         return;
     }
 
@@ -117,17 +117,17 @@ getUTF8StringArgument(JSContext *cx, JSO
     const PRUnichar *data = JS_GetStringCharsZ(cx, str);
     if (!data)
         return;
 
     CopyUTF16toUTF8(data, aRetval);
 }
 
 static JSBool
-netscape_security_isPrivilegeEnabled(JSContext *cx, uintN argc, jsval *vp)
+netscape_security_isPrivilegeEnabled(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     bool result = false;
     if (JSString *str = getStringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp))) {
         JSAutoByteString cap(cx, str);
@@ -148,17 +148,17 @@ netscape_security_isPrivilegeEnabled(JSC
         return JS_FALSE;
     }
     JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(result));
     return JS_TRUE;
 }
 
 
 static JSBool
-netscape_security_enablePrivilege(JSContext *cx, uintN argc, jsval *vp)
+netscape_security_enablePrivilege(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     JSAutoByteString cap;
     if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap))
         return JS_FALSE;
@@ -191,17 +191,17 @@ netscape_security_enablePrivilege(JSCont
     rv = securityManager->EnableCapability(cap.ptr());
     if (NS_FAILED(rv))
         return JS_FALSE;
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-netscape_security_disablePrivilege(JSContext *cx, uintN argc, jsval *vp)
+netscape_security_disablePrivilege(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     JSAutoByteString cap;
     if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap))
         return JS_FALSE;
@@ -217,17 +217,17 @@ netscape_security_disablePrivilege(JSCon
     rv = securityManager->DisableCapability(cap.ptr());
     if (NS_FAILED(rv))
         return JS_FALSE;
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-netscape_security_revertPrivilege(JSContext *cx, uintN argc, jsval *vp)
+netscape_security_revertPrivilege(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     JSAutoByteString cap;
     if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap))
         return JS_FALSE;
@@ -243,17 +243,17 @@ netscape_security_revertPrivilege(JSCont
     rv = securityManager->RevertCapability(cap.ptr());
     if (NS_FAILED(rv))
         return JS_FALSE;
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-netscape_security_setCanEnablePrivilege(JSContext *cx, uintN argc, jsval *vp)
+netscape_security_setCanEnablePrivilege(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     if (argc < 2) return JS_FALSE;
     nsCAutoString principalFingerprint;
     getUTF8StringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), principalFingerprint);
@@ -275,17 +275,17 @@ netscape_security_setCanEnablePrivilege(
                                                  nsIPrincipal::ENABLE_GRANTED);
     if (NS_FAILED(rv))
         return JS_FALSE;
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-netscape_security_invalidate(JSContext *cx, uintN argc, jsval *vp)
+netscape_security_invalidate(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsCAutoString principalFingerprint;
     getUTF8StringArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), principalFingerprint);
     if (principalFingerprint.IsEmpty())
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -53,17 +53,17 @@
 #include "nsIXMLHttpRequest.h"
 #include "prmem.h"
 #include "nsAutoPtr.h"
 #include "mozilla/dom/indexedDB/FileInfo.h"
 #include "mozilla/dom/indexedDB/FileManager.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 
 #include "mozilla/GuardObjects.h"
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
 class nsIBlobBuilder;
 
 nsresult NS_NewBlobBuilder(nsISupports* *aSupports);
 
--- a/content/base/public/nsIObjectLoadingContent.idl
+++ b/content/base/public/nsIObjectLoadingContent.idl
@@ -37,26 +37,27 @@
 
 #include "nsISupports.idl"
 
 interface nsIFrame;
 interface nsIObjectFrame;
 interface nsIPluginTag;
 interface nsIDOMElement;
 interface nsIDOMClientRect;
+interface nsIURI;
 
 %{C++
 #include "nsNPAPIPluginInstance.h"
 %}
 [ptr] native nsNPAPIPluginInstancePtr(nsNPAPIPluginInstance);
 
 /**
  * This interface represents a content node that loads objects.
  */
-[scriptable, uuid(6D8914C7-0E22-4452-8962-11B69BBE84D7)]
+[scriptable, uuid(3FF07AB3-5BAC-4D98-9549-5BD15CCEBCD3)]
 interface nsIObjectLoadingContent : nsISupports
 {
   const unsigned long TYPE_LOADING  = 0;
   const unsigned long TYPE_IMAGE    = 1;
   const unsigned long TYPE_PLUGIN   = 2;
   const unsigned long TYPE_DOCUMENT = 3;
   const unsigned long TYPE_NULL     = 4;
 
@@ -75,16 +76,24 @@ interface nsIObjectLoadingContent : nsIS
   /**
    * Gets the content type that corresponds to the give MIME type.  See the
    * constants above for the list of possible values.  If nothing else fits,
    * TYPE_NULL will be returned.
    */
   unsigned long getContentTypeForMIMEType(in AUTF8String aMimeType);
 
   /**
+  * Gets the base URI to be used for this object. This differs from
+  * nsIContent::GetBaseURI in that it takes codebase attributes into
+  * account. The MIME type is required as some plugins (java) calculate
+  * this differently.
+  */
+  nsIURI GetObjectBaseURI(in ACString aMimeType);
+
+  /**
    * Returns the plugin instance if it has already been instantiated. This
    * will never instantiate the plugin and so is safe to call even when
    * content script must not execute.
    */
   [noscript] readonly attribute nsNPAPIPluginInstancePtr pluginInstance;
 
   /**
    * Tells the content about an associated object frame.
--- a/content/base/src/nsContentAreaDragDrop.cpp
+++ b/content/base/src/nsContentAreaDragDrop.cpp
@@ -403,19 +403,20 @@ DragDataProducer::Produce(nsDOMDataTrans
   nsCOMPtr<nsISelection> selection;
   nsIContent* editingElement = mSelectionTargetNode->IsEditable() ?
                                mSelectionTargetNode->GetEditingHost() : nsnull;
   nsCOMPtr<nsITextControlElement> textControl(do_QueryInterface(editingElement));
   if (textControl) {
     nsISelectionController* selcon = textControl->GetSelectionController();
     if (selcon) {
       selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
-      if (!selection)
-        return NS_OK;
     }
+
+    if (!selection)
+      return NS_OK;
   }
   else {
     mWindow->GetSelection(getter_AddRefs(selection));
     if (!selection)
       return NS_OK;
 
     // Check if the node is inside a form control. Don't set aCanDrag to false
     //however, as we still want to allow the drag.
@@ -444,21 +445,24 @@ DragDataProducer::Produce(nsDOMDataTrans
     }
   }
 
   // In chrome shells, only allow dragging inside editable areas.
   if (isChromeShell && !editingElement)
     return NS_OK;
 
   if (isChromeShell && textControl) {
-    // Only use the selection if it isn't collapsed.
-    bool isCollapsed = false;
-    selection->GetIsCollapsed(&isCollapsed);
-    if (!isCollapsed)
-      selection.swap(*aSelection);
+    // Only use the selection if the target node is in the selection.
+    bool selectionContainsTarget = false;
+    nsCOMPtr<nsIDOMNode> targetNode = do_QueryInterface(mSelectionTargetNode);
+    selection->ContainsNode(targetNode, false, &selectionContainsTarget);
+    if (!selectionContainsTarget)
+      return NS_OK;
+
+    selection.swap(*aSelection);
   }
   else {
     // In content shells, a number of checks are made below to determine
     // whether an image or a link is being dragged. If so, add additional
     // data to the data transfer. This is also done for chrome shells, but
     // only when in a non-textbox editor.
 
     bool haveSelectedContent = false;
--- a/content/base/src/nsDOMBlobBuilder.h
+++ b/content/base/src/nsDOMBlobBuilder.h
@@ -36,17 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsDOMBlobBuilder_h
 #define nsDOMBlobBuilder_h
 
 #include "nsDOMFile.h"
 #include "CheckedInt.h"
 
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
 
 class nsDOMMultipartFile : public nsDOMFileBase
 {
 public:
   // Create as a file
   nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -152,16 +152,18 @@
 #include "prprf.h"
 
 #include "nsSVGFeatures.h"
 #include "nsDOMMemoryReporter.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsCycleCollector.h"
 #include "xpcpublic.h"
 #include "xpcprivate.h"
+#include "nsLayoutStatics.h"
+#include "mozilla/Telemetry.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID);
 
 PRInt32 nsIContent::sTabFocusModel = eTabFocus_any;
 bool nsIContent::sTabFocusModelAppliesToXUL = false;
@@ -171,17 +173,17 @@ nsresult NS_NewContentIterator(nsIConten
 
 void
 nsWrapperCache::RemoveExpandoObject()
 {
   JSObject *expando = GetExpandoObjectPreserveColor();
   if (expando) {
     JSCompartment *compartment = js::GetObjectCompartment(expando);
     xpc::CompartmentPrivate *priv =
-      static_cast<xpc::CompartmentPrivate *>(js_GetCompartmentPrivate(compartment));
+      static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
     priv->RemoveDOMExpandoObject(expando);
   }
 }
 
 //----------------------------------------------------------------------
 
 nsINode::nsSlots::~nsSlots()
 {
@@ -4369,48 +4371,145 @@ nsINode::IsEqualNode(nsIDOMNode* aOther,
 }
 
 //----------------------------------------------------------------------
 
 // nsISupports implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericElement)
 
+#define SUBTREE_UNBINDINGS_PER_RUNNABLE 500
+
+class ContentUnbinder : public nsRunnable
+{
+public:
+  ContentUnbinder()
+  {
+    nsLayoutStatics::AddRef();
+    mLast = this;
+  }
+
+  ~ContentUnbinder()
+  {
+    Run();
+    nsLayoutStatics::Release();
+  }
+
+  void UnbindSubtree(nsIContent* aNode)
+  {
+    if (aNode->NodeType() != nsIDOMNode::ELEMENT_NODE &&
+        aNode->NodeType() != nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
+      return;  
+    }
+    nsGenericElement* container = static_cast<nsGenericElement*>(aNode);
+    PRUint32 childCount = container->mAttrsAndChildren.ChildCount();
+    if (childCount) {
+      while (childCount-- > 0) {
+        // Hold a strong ref to the node when we remove it, because we may be
+        // the last reference to it.  We need to call TakeChildAt() and
+        // update mFirstChild before calling UnbindFromTree, since this last
+        // can notify various observers and they should really see consistent
+        // tree state.
+        nsCOMPtr<nsIContent> child =
+          container->mAttrsAndChildren.TakeChildAt(childCount);
+        if (childCount == 0) {
+          container->mFirstChild = nsnull;
+        }
+        UnbindSubtree(child);
+        child->UnbindFromTree();
+      }
+    }
+  }
+
+  NS_IMETHOD Run()
+  {
+    nsAutoScriptBlocker scriptBlocker;
+    PRUint32 len = mSubtreeRoots.Length();
+    if (len) {
+      PRTime start = PR_Now();
+      for (PRUint32 i = 0; i < len; ++i) {
+        UnbindSubtree(mSubtreeRoots[i]);
+      }
+      mSubtreeRoots.Clear();
+      Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_CONTENT_UNBIND,
+                            PRUint32(PR_Now() - start) / PR_USEC_PER_MSEC);
+    }
+    if (this == sContentUnbinder) {
+      sContentUnbinder = nsnull;
+      if (mNext) {
+        nsRefPtr<ContentUnbinder> next;
+        next.swap(mNext);
+        sContentUnbinder = next;
+        next->mLast = mLast;
+        mLast = nsnull;
+        NS_DispatchToMainThread(next);
+      }
+    }
+    return NS_OK;
+  }
+
+  static void Append(nsIContent* aSubtreeRoot)
+  {
+    if (!sContentUnbinder) {
+      sContentUnbinder = new ContentUnbinder();
+      nsCOMPtr<nsIRunnable> e = sContentUnbinder;
+      NS_DispatchToMainThread(e);
+    }
+
+    if (sContentUnbinder->mLast->mSubtreeRoots.Length() >=
+        SUBTREE_UNBINDINGS_PER_RUNNABLE) {
+      sContentUnbinder->mLast->mNext = new ContentUnbinder();
+      sContentUnbinder->mLast = sContentUnbinder->mLast->mNext;
+    }
+    sContentUnbinder->mLast->mSubtreeRoots.AppendElement(aSubtreeRoot);
+  }
+
+private:
+  nsAutoTArray<nsCOMPtr<nsIContent>,
+               SUBTREE_UNBINDINGS_PER_RUNNABLE> mSubtreeRoots;
+  nsRefPtr<ContentUnbinder>                     mNext;
+  ContentUnbinder*                              mLast;
+  static ContentUnbinder*                       sContentUnbinder;
+};
+
+ContentUnbinder* ContentUnbinder::sContentUnbinder = nsnull;
+
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement)
   nsINode::Unlink(tmp);
 
   if (tmp->HasProperties() && tmp->IsXUL()) {
     tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
     tmp->DeleteProperty(nsGkAtoms::popuplistener);
   }
 
   // Unlink child content (and unbind our subtree).
-  {
+  if (UnoptimizableCCNode(tmp) || !nsCCUncollectableMarker::sGeneration) {
     PRUint32 childCount = tmp->mAttrsAndChildren.ChildCount();
     if (childCount) {
       // Don't allow script to run while we're unbinding everything.
       nsAutoScriptBlocker scriptBlocker;
       while (childCount-- > 0) {
-        // Once we have XPCOMGC we shouldn't need to call UnbindFromTree.
-        // We could probably do a non-deep unbind here when IsInDoc is false
-        // for better performance.
-
         // Hold a strong ref to the node when we remove it, because we may be
         // the last reference to it.  We need to call TakeChildAt() and
         // update mFirstChild before calling UnbindFromTree, since this last
         // can notify various observers and they should really see consistent
         // tree state.
         nsCOMPtr<nsIContent> child = tmp->mAttrsAndChildren.TakeChildAt(childCount);
         if (childCount == 0) {
           tmp->mFirstChild = nsnull;
         }
         child->UnbindFromTree();
       }
     }
-  }  
+  } else if (!tmp->GetParent() && tmp->mAttrsAndChildren.ChildCount()) {
+    ContentUnbinder::Append(tmp);
+  } /* else {
+    The subtree root will end up to a ContentUnbinder, and that will
+    unbind the child nodes.
+  } */
 
   // Unlink any DOM slots of interest.
   {
     nsDOMSlots *slots = tmp->GetExistingDOMSlots();
     if (slots) {
       slots->Unlink(tmp->IsXUL());
     }
   }
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -77,16 +77,17 @@ class nsIDOMCSSStyleDeclaration;
 class nsIURI;
 class nsINodeInfo;
 class nsIControllers;
 class nsEventListenerManager;
 class nsIScrollableFrame;
 class nsAttrValueOrString;
 class nsContentList;
 class nsDOMTokenList;
+class ContentUnbinder;
 struct nsRect;
 
 typedef PRUptrdiff PtrBits;
 
 /**
  * Class that implements the nsIDOMNodeList interface (a list of children of
  * the content), by holding a reference to the content and delegating GetLength
  * and Item to its existing child list.
@@ -951,16 +952,17 @@ protected:
    *
    * Note: for HTML this gets the value of the 'target' attribute; for XLink
    * this gets the value of the xlink:_moz_target attribute, or failing that,
    * the value of xlink:show, converted to a suitably equivalent named target
    * (e.g. _blank).
    */
   virtual void GetLinkTarget(nsAString& aTarget);
 
+  friend class ContentUnbinder;
   /**
    * Array containing all attributes and children for this element
    */
   nsAttrAndChildArray mAttrsAndChildren;
 
 private:
   /**
    * Get this element's client area rect in app units.
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -593,17 +593,17 @@ nsObjectLoadingContent::InstantiatePlugi
   // of this method.
   nsCOMPtr<nsIObjectLoadingContent> kungFuDeathGrip = this;
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   nsCOMPtr<nsIURI> baseURI;
   if (!aURI) {
     // We need some URI. If we have nothing else, use the base URI.
     // XXX(biesi): The code used to do this. Not sure why this is correct...
-    GetObjectBaseURI(thisContent, getter_AddRefs(baseURI));
+    GetObjectBaseURI(nsCString(aMimeType), getter_AddRefs(baseURI));
     aURI = baseURI;
   }
 
   // Flush layout so that the plugin is initialized with the latest information.
   nsIDocument* doc = thisContent->GetCurrentDoc();
   if (!doc) {
     return NS_ERROR_FAILURE;
   }
@@ -1158,17 +1158,17 @@ nsObjectLoadingContent::LoadObject(const
 
   // Avoid StringToURI in order to use the codebase attribute as base URI
   nsCOMPtr<nsIContent> thisContent = 
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   NS_ASSERTION(thisContent, "must be a content");
 
   nsIDocument* doc = thisContent->OwnerDoc();
   nsCOMPtr<nsIURI> baseURI;
-  GetObjectBaseURI(thisContent, getter_AddRefs(baseURI));
+  GetObjectBaseURI(aTypeHint, getter_AddRefs(baseURI));
 
   nsCOMPtr<nsIURI> uri;
   nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
                                             aURI, doc,
                                             baseURI);
   // If URI creation failed, fallback immediately - this only happens for
   // malformed URIs
   if (!uri) {
@@ -1189,16 +1189,61 @@ nsObjectLoadingContent::UpdateFallbackSt
   // Notify the UI and update the fallback state
   PluginSupportState state = GetPluginSupportState(aContent, aTypeHint);
   if (state != ePluginOtherState) {
     fallback.SetPluginState(state);
     FirePluginError(aContent, state);
   }
 }
 
+bool
+nsObjectLoadingContent::IsFileCodebaseAllowable(nsIURI* aBaseURI, nsIURI* aOriginURI)
+{
+  nsCOMPtr<nsIFileURL> baseFileURL(do_QueryInterface(aBaseURI));
+  nsCOMPtr<nsIFileURL> originFileURL(do_QueryInterface(aOriginURI));
+
+  // get IFile handles and normalize
+  nsCOMPtr<nsIFile> originFile;
+  nsCOMPtr<nsIFile> baseFile;
+  if (!originFileURL || !baseFileURL ||
+      NS_FAILED(originFileURL->GetFile(getter_AddRefs(originFile))) ||
+      NS_FAILED(baseFileURL->GetFile(getter_AddRefs(baseFile))) ||
+      NS_FAILED(baseFile->Normalize()) ||
+      NS_FAILED(originFile->Normalize())) {
+    return false;
+  }
+
+  // If the origin is a directory, it should contain/equal baseURI
+  // Otherwise, its parent directory should contain/equal baseURI
+  bool origin_is_dir;
+  bool contained = false;
+  nsresult rv = originFile->IsDirectory(&origin_is_dir);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  if (origin_is_dir) {
+    // originURI is a directory, ensure it contains the baseURI
+    rv = originFile->Contains(baseFile, true, &contained);
+    if (NS_SUCCEEDED(rv) && !contained) {
+      rv = originFile->Equals(baseFile, &contained);
+    }
+  } else {
+    // originURI is a file, ensure its parent contains the baseURI
+    nsCOMPtr<nsIFile> originParent;
+    rv = originFile->GetParent(getter_AddRefs(originParent));
+    if (NS_SUCCEEDED(rv) && originParent) {
+      rv = originParent->Contains(baseFile, true, &contained);
+      if (NS_SUCCEEDED(rv) && !contained) {
+        rv = originParent->Equals(baseFile, &contained);
+      }
+    }
+  }
+
+  return NS_SUCCEEDED(rv) && contained;
+}
+
 nsresult
 nsObjectLoadingContent::LoadObject(nsIURI* aURI,
                                    bool aNotify,
                                    const nsCString& aTypeHint,
                                    bool aForceLoad)
 {
   // Only do a URI equality check for things that aren't stopped plugins.
   // This is because we still need to load again if the plugin has been stopped.
@@ -1286,16 +1331,38 @@ nsObjectLoadingContent::LoadObject(nsIUR
                                 nsnull, //extra
                                 &shouldLoad,
                                 nsContentUtils::GetContentPolicy(),
                                 secMan);
     if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
       HandleBeingBlockedByContentPolicy(rv, shouldLoad);
       return NS_OK;
     }
+
+    // If this is a file:// URI, require that the codebase (baseURI)
+    // is contained within the same folder as the document origin (originURI)
+    // or within the document origin, if it is a folder.
+    // No originURI implies chrome, which bypasses the check
+    // -- bug 406541
+    nsCOMPtr<nsIURI> originURI;
+    nsCOMPtr<nsIURI> baseURI;
+    GetObjectBaseURI(aTypeHint, getter_AddRefs(baseURI));
+    rv = thisContent->NodePrincipal()->GetURI(getter_AddRefs(originURI));
+    if (NS_FAILED(rv)) {
+      Fallback(aNotify);
+      return NS_OK;
+    }
+    if (originURI) {
+      bool isfile;
+      if (NS_FAILED(originURI->SchemeIs("file", &isfile)) ||
+          (isfile && !IsFileCodebaseAllowable(baseURI, originURI))) {
+        Fallback(aNotify);
+        return NS_OK;
+      }
+    }
   }
 
   nsresult rv = NS_ERROR_UNEXPECTED;
   // This fallback variable MUST be declared after the notifier variable. Do NOT
   // change the order of the declarations!
   AutoFallback fallback(this, &rv);
 
   PRUint32 caps = GetCapabilities();
@@ -1403,17 +1470,17 @@ nsObjectLoadingContent::LoadObject(nsIUR
 
     if (isSupportedClassID) {
       // Use the classid's type
       NS_ASSERTION(!typeForID.IsEmpty(), "Must have a real type!");
       mContentType = typeForID;
       // XXX(biesi). The plugin instantiation code used to pass the base URI
       // here instead of the plugin URI for instantiation via class ID, so I
       // continue to do so. Why that is, no idea...
-      GetObjectBaseURI(thisContent, getter_AddRefs(mURI));
+      GetObjectBaseURI(mContentType, getter_AddRefs(mURI));
       if (!mURI) {
         mURI = aURI;
       }
     }
 
     // rv is references by a stack-based object, need to assign here
     rv = AsyncStartPluginInstance();
 
@@ -1780,35 +1847,39 @@ nsObjectLoadingContent::TypeForClassID(c
       aType.AssignLiteral("application/oleobject");
       return NS_OK;
     }
   }
 
   return NS_ERROR_NOT_AVAILABLE;
 }
 
-void
-nsObjectLoadingContent::GetObjectBaseURI(nsIContent* thisContent, nsIURI** aURI)
+NS_IMETHODIMP
+nsObjectLoadingContent::GetObjectBaseURI(const nsACString & aMimeType, nsIURI** aURI)
 {
-  // We want to use swap(); since this is just called from this file,
-  // we can assert this (callers use comptrs)
-  NS_PRECONDITION(*aURI == nsnull, "URI must be inited to zero");
+  nsCOMPtr<nsIContent> thisContent =
+    do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   // For plugins, the codebase attribute is the base URI
   nsCOMPtr<nsIURI> baseURI = thisContent->GetBaseURI();
   nsAutoString codebase;
   thisContent->GetAttr(kNameSpaceID_None, nsGkAtoms::codebase,
                        codebase);
-  if (!codebase.IsEmpty()) {
-    nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
-                                              thisContent->OwnerDoc(),
-                                              baseURI);
-  } else {
-    baseURI.swap(*aURI);
+
+  if (codebase.IsEmpty() && aMimeType.Equals("application/x-java-vm")) {
+    // bug 406541
+    // Java resolves codebase="" as "/" -- so we replicate that quirk, to ensure
+    // we run security checks against the same path.
+    codebase.AssignLiteral("/");
   }
+
+  nsContentUtils::NewURIWithDocumentCharset(aURI, codebase,
+                                            thisContent->OwnerDoc(),
+                                            baseURI);
+  return NS_OK;
 }
 
 nsObjectFrame*
 nsObjectLoadingContent::GetExistingFrame()
 {
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
   nsIFrame* frame = thisContent->GetPrimaryFrame();
   nsIObjectFrame* objFrame = do_QueryFrame(frame);
@@ -2057,20 +2128,23 @@ nsObjectLoadingContent::StopPluginInstan
     if (NS_SUCCEEDED(inst->GetMIMEType(&mime)) && mime) {
       if (strcmp(mime, "audio/x-pn-realaudio-plugin") == 0) {
         delayedStop = true;
       }      
     }
   }
 #endif
 
-  DoStopPlugin(mInstanceOwner, delayedStop);
-
+  // DoStopPlugin can process events and there may be pending InDocCheckEvent
+  // events which can drop in underneath us and destroy the instance we are
+  // about to destroy. Make sure this doesn't happen via this temp ref ptr and
+  // the !mInstanceOwner check above.
+  nsRefPtr<nsPluginInstanceOwner> instOwner = mInstanceOwner;
   mInstanceOwner = nsnull;
-
+  DoStopPlugin(instOwner, delayedStop);
   return NS_OK;
 }
 
 void
 nsObjectLoadingContent::NotifyContentObjectWrapper()
 {
   nsCOMPtr<nsIContent> thisContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -249,16 +249,22 @@ class nsObjectLoadingContent : public ns
     void NotifyContentObjectWrapper();
 
     /**
      * Check whether the given request represents a successful load.
      */
     static bool IsSuccessfulRequest(nsIRequest* aRequest);
 
     /**
+     * Check if the given baseURI is contained in the same directory as the
+     * aOriginURI (or a child thereof)
+     */
+    static bool IsFileCodebaseAllowable(nsIURI* aBaseURI, nsIURI* aOriginURI);
+
+    /**
      * Check whether the URI can be handled internally.
      */
     static bool CanHandleURI(nsIURI* aURI);
 
     /**
      * Checks whether the given type is a supported document type.
      */
     bool IsSupportedDocument(const nsCString& aType);
@@ -295,24 +301,16 @@ class nsObjectLoadingContent : public ns
      * For a classid, returns the MIME type that can be used to instantiate
      * a plugin for this ID.
      *
      * @return NS_ERROR_NOT_AVAILABLE Unsupported class ID.
      */
     nsresult TypeForClassID(const nsAString& aClassID, nsACString& aType);
 
     /**
-     * Gets the base URI to be used for this object. This differs from
-     * nsIContent::GetBaseURI in that it takes codebase attributes into
-     * account.
-     */
-    void GetObjectBaseURI(nsIContent* thisContent, nsIURI** aURI);
-
-
-    /**
      * Gets the frame that's associated with this content node.
      * Does not flush.
      */
     nsObjectFrame* GetExistingFrame();
 
     /**
      * Handle being blocked by a content policy.  aStatus is the nsresult
      * return value of the Should* call, while aRetval is what it returned in
--- a/content/canvas/crashtests/crashtests.list
+++ b/content/canvas/crashtests/crashtests.list
@@ -1,6 +1,6 @@
 load 360293-1.html
 load 421715-1.html
 load 553938-1.html
 load 647480.html
 load 0px-size-font-667225.html
-skip-if(cocoaWidget&&layersGPUAccelerated) load 729116.html # bug 731117
+load 729116.html
--- a/content/canvas/src/CustomQS_Canvas2D.h
+++ b/content/canvas/src/CustomQS_Canvas2D.h
@@ -241,17 +241,17 @@ GetImageDataDimensions(JSContext *cx, JS
         return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
 
     *width = uint32_t(wi);
     *height = uint32_t(hi);
     return true;
 }
 
 static JSBool
-nsIDOMCanvasRenderingContext2D_CreateImageData(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMCanvasRenderingContext2D_CreateImageData(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
 
     /* Note: this doesn't need JS_THIS_OBJECT */
 
     if (argc < 1)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
@@ -287,17 +287,17 @@ nsIDOMCanvasRenderingContext2D_CreateIma
     int32_t hi = JS_DoubleToInt32(height);
 
     uint32_t w = NS_ABS(wi);
     uint32_t h = NS_ABS(hi);
     return CreateImageData(cx, w, h, NULL, 0, 0, vp);
 }
 
 static JSBool
-nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
 
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsIDOMCanvasRenderingContext2D *self;
@@ -344,17 +344,17 @@ nsIDOMCanvasRenderingContext2D_GetImageD
         y -= h;
     } else {
         h = hi;
     }
     return CreateImageData(cx, w, h, self, x, y, vp);
 }
 
 static JSBool
-nsIDOMCanvasRenderingContext2D_PutImageData(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMCanvasRenderingContext2D_PutImageData(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
 
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -78,17 +78,17 @@ helper_isFloat32Array(JSObject *obj) {
 
 /*
  * BufferData takes:
  *    BufferData (int, int, int)
  *    BufferData_buf (int, js::ArrayBuffer *, int)
  *    BufferData_array (int, js::TypedArray *, int)
  */
 static JSBool
-nsIDOMWebGLRenderingContext_BufferData(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_BufferData(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsIDOMWebGLRenderingContext *self;
     xpc_qsSelfRef selfref;
@@ -151,17 +151,17 @@ nsIDOMWebGLRenderingContext_BufferData(J
 }
 
 /*
  * BufferSubData takes:
  *    BufferSubData (int, int, js::ArrayBuffer *)
  *    BufferSubData_array (int, int, js::TypedArray *)
  */
 static JSBool
-nsIDOMWebGLRenderingContext_BufferSubData(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_BufferSubData(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsIDOMWebGLRenderingContext *self;
     xpc_qsSelfRef selfref;
@@ -223,17 +223,17 @@ nsIDOMWebGLRenderingContext_BufferSubDat
     return JS_TRUE;
 }
 
 /*
  * CompressedTexImage2D takes:
  *    CompressedTexImage2D(uint, int, uint, int, int, int, ArrayBufferView)
  */
 static JSBool
-nsIDOMWebGLRenderingContext_CompressedTexImage2D(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_CompressedTexImage2D(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
@@ -273,17 +273,17 @@ nsIDOMWebGLRenderingContext_CompressedTe
     return JS_TRUE;
 }
 
 /*
  * CompressedTexSubImage2D takes:
  *    CompressedTexSubImage2D(uint, int, int, int, int, int, uint, ArrayBufferView)
  */
 static JSBool
-nsIDOMWebGLRenderingContext_CompressedTexSubImage2D(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_CompressedTexSubImage2D(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
@@ -324,17 +324,17 @@ nsIDOMWebGLRenderingContext_CompressedTe
     return JS_TRUE;
 }
 
 /*
  * ReadPixels takes:
  *    ReadPixels(int, int, int, int, uint, uint, ArrayBufferView)
  */
 static JSBool
-nsIDOMWebGLRenderingContext_ReadPixels(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_ReadPixels(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
@@ -384,17 +384,17 @@ nsIDOMWebGLRenderingContext_ReadPixels(J
 
 /*
  * TexImage2D takes:
  *    TexImage2D(uint, int, uint, int, int, int, uint, uint, ArrayBufferView)
  *    TexImage2D(uint, int, uint, uint, uint, nsIDOMElement)
  *    TexImage2D(uint, int, uint, uint, uint, ImageData)
  */
 static JSBool
-nsIDOMWebGLRenderingContext_TexImage2D(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_TexImage2D(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
@@ -505,17 +505,17 @@ nsIDOMWebGLRenderingContext_TexImage2D(J
 }
 
 /* TexSubImage2D takes:
  *    TexSubImage2D(uint, int, int, int, int, int, uint, uint, ArrayBufferView)
  *    TexSubImage2D(uint, int, int, int, uint, uint, nsIDOMElement)
  *    TexSubImage2D(uint, int, int, int, uint, uint, ImageData)
  */
 static JSBool
-nsIDOMWebGLRenderingContext_TexSubImage2D(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_TexSubImage2D(JSContext *cx, unsigned argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
@@ -616,17 +616,17 @@ nsIDOMWebGLRenderingContext_TexSubImage2
         return xpc_qsThrowMethodFailed(cx, rv, vp);
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 
 /* NOTE: There is a TN version of this below, update it as well */
 static inline JSBool
-helper_nsIDOMWebGLRenderingContext_Uniform_x_iv(JSContext *cx, uintN argc, jsval *vp, int nElements)
+helper_nsIDOMWebGLRenderingContext_Uniform_x_iv(JSContext *cx, unsigned argc, jsval *vp, int nElements)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
@@ -690,17 +690,17 @@ helper_nsIDOMWebGLRenderingContext_Unifo
         return xpc_qsThrowMethodFailed(cx, rv, vp);
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 
 /* NOTE: There is a TN version of this below, update it as well */
 static inline JSBool
-helper_nsIDOMWebGLRenderingContext_Uniform_x_fv(JSContext *cx, uintN argc, jsval *vp, int nElements)
+helper_nsIDOMWebGLRenderingContext_Uniform_x_fv(JSContext *cx, unsigned argc, jsval *vp, int nElements)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsresult rv;
 
@@ -764,17 +764,17 @@ helper_nsIDOMWebGLRenderingContext_Unifo
         return xpc_qsThrowMethodFailed(cx, rv, vp);
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 
 /* NOTE: There is a TN version of this below, update it as well */
 static inline JSBool
-helper_nsIDOMWebGLRenderingContext_UniformMatrix_x_fv(JSContext *cx, uintN argc, jsval *vp, int nElements)
+helper_nsIDOMWebGLRenderingContext_UniformMatrix_x_fv(JSContext *cx, unsigned argc, jsval *vp, int nElements)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsIDOMWebGLRenderingContext *self;
     xpc_qsSelfRef selfref;
@@ -837,17 +837,17 @@ helper_nsIDOMWebGLRenderingContext_Unifo
     if (NS_FAILED(rv))
         return xpc_qsThrowMethodFailed(cx, rv, vp);
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 
 static inline JSBool
-helper_nsIDOMWebGLRenderingContext_VertexAttrib_x_fv(JSContext *cx, uintN argc, jsval *vp, int nElements)
+helper_nsIDOMWebGLRenderingContext_VertexAttrib_x_fv(JSContext *cx, unsigned argc, jsval *vp, int nElements)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
 
     nsIDOMWebGLRenderingContext *self;
     xpc_qsSelfRef selfref;
@@ -905,96 +905,96 @@ helper_nsIDOMWebGLRenderingContext_Verte
     if (NS_FAILED(rv))
         return xpc_qsThrowMethodFailed(cx, rv, vp);
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_Uniform1iv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_Uniform1iv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_Uniform_x_iv(cx, argc, vp, 1);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_Uniform2iv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_Uniform2iv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_Uniform_x_iv(cx, argc, vp, 2);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_Uniform3iv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_Uniform3iv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_Uniform_x_iv(cx, argc, vp, 3);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_Uniform4iv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_Uniform4iv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_Uniform_x_iv(cx, argc, vp, 4);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_Uniform1fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_Uniform1fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_Uniform_x_fv(cx, argc, vp, 1);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_Uniform2fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_Uniform2fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_Uniform_x_fv(cx, argc, vp, 2);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_Uniform3fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_Uniform3fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_Uniform_x_fv(cx, argc, vp, 3);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_Uniform4fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_Uniform4fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_Uniform_x_fv(cx, argc, vp, 4);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_UniformMatrix2fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_UniformMatrix2fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_UniformMatrix_x_fv(cx, argc, vp, 2);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_UniformMatrix3fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_UniformMatrix3fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_UniformMatrix_x_fv(cx, argc, vp, 3);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_UniformMatrix4fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_UniformMatrix4fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_UniformMatrix_x_fv(cx, argc, vp, 4);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_VertexAttrib1fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_VertexAttrib1fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_VertexAttrib_x_fv(cx, argc, vp, 1);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_VertexAttrib2fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_VertexAttrib2fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_VertexAttrib_x_fv(cx, argc, vp, 2);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_VertexAttrib3fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_VertexAttrib3fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_VertexAttrib_x_fv(cx, argc, vp, 3);
 }
 
 static JSBool
-nsIDOMWebGLRenderingContext_VertexAttrib4fv(JSContext *cx, uintN argc, jsval *vp)
+nsIDOMWebGLRenderingContext_VertexAttrib4fv(JSContext *cx, unsigned argc, jsval *vp)
 {
     return helper_nsIDOMWebGLRenderingContext_VertexAttrib_x_fv(cx, argc, vp, 4);
 }
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -59,16 +59,20 @@
 #include "nsIJSNativeInitializer.h"
 #include "nsContentUtils.h"
 
 #include "GLContextProvider.h"
 #include "Layers.h"
 
 #include "CheckedInt.h"
 
+#ifdef XP_MACOSX
+#include "ForceDiscreteGPUHelperCGL.h"
+#endif
+
 /* 
  * Minimum value constants defined in 6.2 State Tables of OpenGL ES - 2.0.25
  *   https://bugzilla.mozilla.org/show_bug.cgi?id=686732
  * 
  * Exceptions: some of the following values are set to higher values than in the spec because
  * the values in the spec are ridiculously low. They are explicitly marked below
 */
 #define MINVALUE_GL_MAX_TEXTURE_SIZE                  1024  // Different from the spec, which sets it to 64 on page 162
@@ -938,16 +942,26 @@ protected:
     nsCOMPtr<nsITimer> mContextRestorer;
     bool mAllowRestore;
     bool mRobustnessTimerRunning;
     bool mDrawSinceRobustnessTimerSet;
     ContextStatus mContextStatus;
     bool mContextLostErrorSet;
     bool mContextLostDueToTest;
 
+#ifdef XP_MACOSX
+    // see bug 713305. This RAII helper guarantees that we're on the discrete GPU, during its lifetime
+    // Debouncing note: we don't want to switch GPUs too frequently, so try to not create and destroy
+    // these objects at high frequency. Having WebGLContext's hold one such object seems fine,
+    // because WebGLContext objects only go away during GC, which shouldn't happen too frequently.
+    // If in the future GC becomes much more frequent, we may have to revisit then (maybe use a timer).
+    ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
+#endif
+
+
 public:
     // console logging helpers
     static void LogMessage(const char *fmt, ...);
     static void LogMessage(const char *fmt, va_list ap);
     void LogMessageIfVerbose(const char *fmt, ...);
     void LogMessageIfVerbose(const char *fmt, va_list ap);
 
     friend class WebGLTexture;
--- a/content/canvas/test/webgl/test_webgl_conformance_test_suite.html
+++ b/content/canvas/test/webgl/test_webgl_conformance_test_suite.html
@@ -89,16 +89,36 @@ function start() {
     is106orHigher = (kDarwinVersion >= 10.0);
     if (!is106orHigher) {
       dump("WebGL mochitest disabled on Mac OSX versions older than 10.6\n");
       SimpleTest.finish();
       return;
     }
   }
 
+  // we currently disable this test on version of Mac OSX older than 10.6,
+  // due to various weird failures, including one making getRenderbufferParameter tests
+  // on DEPTH_STENCIL fail
+  var kDarwinVersion = 0;
+  if (kIsMac) {
+    // code borrowed from browser/modules/test/browser_taskbar_preview.js
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    kDarwinVersion = parseFloat(Components.classes["@mozilla.org/system-info;1"]
+                                          .getService(Components.interfaces.nsIPropertyBag2)
+                                          .getProperty("version"));
+    // the next line is correct: Mac OSX 10.6 corresponds to Darwin version 10 !
+    // Mac OSX 10.5 would be Darwin version 9. the |version| string we've got here
+    // is the Darwin version.
+    if (kDarwinVersion < 10.0) {
+      todo(false, "Test disabled on Mac OSX versions older than 10.6.");
+      SimpleTest.finish();
+      return;
+    }
+  }
+
   function getEnv(env) {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
     var envsvc = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment);
     var val = envsvc.get(env);
     if (val == "")
       return null;
     return val;
   }
@@ -125,45 +145,72 @@ function start() {
     var node = reporter.localDoc.createTextNode('');
     li.appendChild(ul);
     div.appendChild(node);
     this.totalsElem = node;
     this.resultElem = ul;
     this.elem = li;
   };
 
-  Page.prototype.isExpectedToFullyPass = function() {
-    return testsExpectedToFail.indexOf(this.url) == -1 && testsToIgnore.indexOf(this.url) == -1;
+  /**
+   * Indicates whether this test page results are not to be ignored.
+   */
+  Page.prototype.shouldBeAccountedFor = function() {
+    return testsToIgnore.indexOf(this.url) == -1;
   }
 
-  Page.prototype.errormsg = function(msg) {
-    return msg + ' (URL: ' + this.url + ')';
+  /**
+   * Indicates whether all this test page results are expected not to fail,
+   * if not ignored.
+   */
+  Page.prototype.isExpectedToFullyPass = function() {
+    return this.shouldBeAccountedFor() &&
+           testsExpectedToFail.indexOf(this.url) == -1;
   }
 
+  /**
+   * Returns log message with added test page url.
+   */
+  Page.prototype.logMsg = function(msg) {
+    return '[' + this.url + '] ' + msg;
+  }
+
+  /**
+   * Reports an individual test result of test page.
+   */
   Page.prototype.addResult = function(msg, success) {
     ++this.totalTests;
     if (success === undefined) {
       ++this.totalTimeouts;
       var result = "timeout";
       var css = "timeout";
       // only few timeouts are actually caught here --- most are caught in finishPage().
       if (this.isExpectedToFullyPass()) {
-        ok(false, this.errormsg('Test timed out, "' + msg + '"'));
+        ok(false, this.logMsg('Test timed out'), msg);
+      } else {
+        todo(false, this.logMsg('Test timed out'), msg);
       }
     } else if (success) {
       ++this.totalSuccessful;
       var result = "success";
       var css = "success";
-      // don't report success.
+      if (this.shouldBeAccountedFor()) {
+        ok(true, this.logMsg('Test passed'), msg);
+      } else {
+        todo(false, this.logMsg('Test passed, but is ignored'), msg);
+      }
+      // Don't report individual success to UI, to keep it light.
       return;
     } else {
       var result = "failed";
       var css = "fail";
       if (this.isExpectedToFullyPass()) {
-        ok(false, this.errormsg('Test failed, "' + msg + '"'));
+        ok(false, this.logMsg('Test failed'), msg);
+      } else {
+        todo(false, this.logMsg('Test failed'), msg);
       }
     }
 
     var node = this.reporter.localDoc.createTextNode(result + ': ' + msg);
     var li = this.reporter.localDoc.createElement('li');
     li.appendChild(node);
     li.setAttribute('class', css);
     this.resultElem.appendChild(li);
@@ -176,41 +223,52 @@ function start() {
     // remove previous results.
     while (this.resultElem.hasChildNodes()) {
       this.resultElem.removeChild(this.resultElem.childNodes[0]);
     }
     this.totalsElem.textContent = '';
     return true;
   };
 
+  /**
+   * Reports test page result summary.
+   */
   Page.prototype.finishPage = function(success) {
     var msg = ' (' + this.totalSuccessful + ' of ' +
               this.totalTests + ' passed)';
     if (success === undefined) {
       var css = 'testpagetimeout';
       msg = '(*timeout*)';
       ++this.totalTests;
       ++this.totalTimeouts;
+      // Most timeouts are only caught here --- though a few are (already) caught in addResult().
       if (this.isExpectedToFullyPass()) {
-        ok(false, this.errormsg('Unexpected timeout in this test page'));
-        window.dump('WebGL test error: test page timeout: ' + this.url + '\n');
+        ok(false, this.logMsg('Timeout in this test page'));
+      } else {
+        todo(false, this.logMsg('Timeout in this test page'));
       }
     } else if (this.totalSuccessful != this.totalTests) {
       var css = 'testpagefail';
+      var totalFailed = this.totalTests - this.totalTimeouts - this.totalSuccessful;
       if (this.isExpectedToFullyPass()) {
-        window.dump('WebGL test error: test page failure: ' + this.url + '\n');
+        ok(false, this.logMsg("(WebGL test error) " + totalFailed + ' failure(s) and ' + this.totalTimeouts + ' timeout(s)'));
+      } else {
+        todo(false, this.logMsg("(WebGL test error) " + totalFailed + ' failure(s) and ' + this.totalTimeouts + ' timeout(s)'));
       }
-      // failures have already been reported for the sub-tests
     } else {
       var css = 'testpagesuccess';
       if (this.isExpectedToFullyPass()) {
-        ok(true, this.errormsg('Successful test page'));
+        ok(true, this.logMsg('All ' + this.totalSuccessful + ' test(s) passed'));
+      } else {
+        if (this.shouldBeAccountedFor()) {
+          todo(true, this.logMsg('Test page expected to fail, but all ' + this.totalSuccessful + ' tests passed'));
+        } else {
+          todo(false, this.logMsg('All ' + this.totalSuccessful + ' test(s) passed, but test page is ignored'));
+        }
       }
-      window.dump('WebGL test page successful: ' + this.url + '\n');
-      testsSuccessful.push(this.url);
     }
     this.elem.setAttribute('class', css);
     this.totalsElem.textContent = msg;
   };
 
   var Reporter = function() {
     this.localDoc = document;
 
@@ -241,17 +299,17 @@ function start() {
   Reporter.prototype.addPage = function(url) {
     this.currentPage = new Page(this, url, this.resultElem);
     this.resultElem.appendChild(this.currentPage.elem);
     ++this.totalPages;
     this.pagesByURL[url] = this.currentPage;
   };
 
   Reporter.prototype.startPage = function(url) {
-    dump('WebGL mochitest: starting page ' + url + '\n');
+    info("[" + url + "] (WebGL mochitest) Starting test page");
 
     // Calling garbageCollect before each test page fixes intermittent failures with
     // out-of-memory errors, often failing to create a WebGL context.
     // The explanation is that the JS engine keeps unreferenced WebGL contexts around
     // for too long before GCing (bug 617453), so that during this mochitest dozens of unreferenced
     // WebGL contexts can accumulate at a given time.
     SpecialPowers.DOMWindowUtils.garbageCollect();
 
@@ -261,24 +319,21 @@ function start() {
     expectedtofailTextNode.textContent = testsExpectedToFail.length +
                                          ' test pages are expected to fail out of ' +
                                          this.totalPages;
     ignoredtestsTextNode.textContent = testsToIgnore.length +
                                          ' test pages have their results ignored';
     return page.startPage();
   };
 
-  Reporter.prototype.totalFailed = function() {
-    return this.totalTests - this.totalSuccessful;
-  };
-
   Reporter.prototype.displayStats = function() {
+    var totalFailed = this.totalTests - this.totalTimeouts - this.totalSuccessful;
     this.fullResultsNode.textContent =
       this.totalSuccessful + ' passed, ' +
-      this.totalFailed() + ' failed, ' +
+      totalFailed + ' failed, ' +
       this.totalTimeouts + ' timed out';
   };
 
   Reporter.prototype.addResult = function(msg, success) {
     if (this.currentPage != null) {
       this.currentPage.addResult(msg, success);
     }
   };
@@ -290,19 +345,16 @@ function start() {
       this.totalSuccessful += this.currentPage.totalSuccessful;
       this.totalTimeouts += this.currentPage.totalTimeouts;
       this.currentPage = null;
       this.displayStats();
     }
   };
 
   Reporter.prototype.finishedTestSuite = function() {
-      for (var i = 0; i < testsExpectedToFail.length; ++i)
-        if (testsSuccessful.indexOf(testsExpectedToFail[i]) != -1)
-          todo(true, 'Test expected to fail, but passed: ' + testsExpectedToFail[i]);
       statusTextNode.textContent = 'Finished';
       SimpleTest.finish();
   }
 
   Reporter.prototype.ready = function() {
     statusTextNode.textContent = 'Loaded test lists. Starting tests...';
     window.webglTestHarness.runTests();
   }
@@ -348,20 +400,22 @@ function start() {
   getURLOptions(OPTIONS);
 
   function runTestSuite() {
     var reporter = new Reporter();
 
     // try to create a dummy WebGL context, just to catch context creation failures once here,
     // rather than having them result in 100's of failures (one in each test page)
     var canvas = document.getElementById("webglcheck-default");
-    var ctx = null;
+    var ctx;
     try {
         ctx = canvas.getContext("experimental-webgl");
-    } catch(e) {}
+    } catch(e) {
+        ok(false, "canvas.getContext() failed", e);
+    }
 
     if (ctx) {
         statusTextNode.textContent = 'Loading test lists...';
         var iframe = document.getElementById("testframe");
         var testHarness = new WebGLTestHarnessModule.TestHarness(
             iframe,
             '00_test_list.txt',
             function(type, msg, success) {
@@ -430,18 +484,16 @@ function start() {
 
   if (kIsMac && kDarwinVersion >= 11.0) {
     testsExpectedToFail.push('conformance/textures/texture-mips.html');
     testsExpectedToFail.push('conformance/textures/texture-npot.html');
   }
 
   var testsToIgnore = [];
 
-  var testsSuccessful = [];
-
   runTestSuite();
 }
 
 </script>
 </head>
 <body onload="start();">
 <p id="display"></p>
 <div id="content" style="display: none">
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -116,16 +116,18 @@
 #include "mozAutoDocUpdate.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentUtils.h"
 #include "nsRadioVisitor.h"
 
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Util.h" // DebugOnly
 
+#include "nsIIDNService.h"
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // XXX align=left, hspace, vspace, border? other nav4 attrs
 
 static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
 
 // First bits are needed for the control type.
@@ -3913,28 +3915,44 @@ nsHTMLInputElement::IsValidEmailAddressL
 
   return !tokenizer.lastTokenEndedWithSeparator();
 }
 
 //static
 bool
 nsHTMLInputElement::IsValidEmailAddress(const nsAString& aValue)
 {
+  nsCAutoString value = NS_ConvertUTF16toUTF8(aValue);
   PRUint32 i = 0;
-  PRUint32 length = aValue.Length();
+  PRUint32 length = value.Length();
+
+  // Puny-encode the string if needed before running the validation algorithm.
+  nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
+  if (idnSrv) {
+    bool ace;
+    if (NS_SUCCEEDED(idnSrv->IsACE(value, &ace)) && !ace) {
+      nsCAutoString punyCodedValue;
+      if (NS_SUCCEEDED(idnSrv->ConvertUTF8toACE(value, punyCodedValue))) {
+        value = punyCodedValue;
+        length = value.Length();
+      }
+    }
+  } else {
+    NS_ERROR("nsIIDNService isn't present!");
+  }
 
   // If the email address is empty, begins with a '@' or ends with a '.',
   // we know it's invalid.
-  if (length == 0 || aValue[0] == '@' || aValue[length-1] == '.') {
+  if (length == 0 || value[0] == '@' || value[length-1] == '.') {
     return false;
   }
 
   // Parsing the username.
-  for (; i < length && aValue[i] != '@'; ++i) {
-    PRUnichar c = aValue[i];
+  for (; i < length && value[i] != '@'; ++i) {
+    PRUnichar c = value[i];
 
     // The username characters have to be in this list to be valid.
     if (!(nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) ||
           c == '.' || c == '!' || c == '#' || c == '$' || c == '%' ||
           c == '&' || c == '\''|| c == '*' || c == '+' || c == '-' ||
           c == '/' || c == '=' || c == '?' || c == '^' || c == '_' ||
           c == '`' || c == '{' || c == '|' || c == '}' || c == '~' )) {
       return false;
@@ -3943,27 +3961,27 @@ nsHTMLInputElement::IsValidEmailAddress(
 
   // There is no domain name (or it's one-character long),
   // that's not a valid email address.
   if (++i >= length) {
     return false;
   }
 
   // The domain name can't begin with a dot.
-  if (aValue[i] == '.') {
+  if (value[i] == '.') {
     return false;
   }
 
   // Parsing the domain name.
   for (; i < length; ++i) {
-    PRUnichar c = aValue[i];
+    PRUnichar c = value[i];
 
     if (c == '.') {
       // A dot can't follow a dot.
-      if (aValue[i-1] == '.') {
+      if (value[i-1] == '.') {
         return false;
       }
     } else if (!(nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) ||
                  c == '-')) {
       // The domain characters have to be in this list to be valid.
       return false;
     }
   }
--- a/content/html/content/test/form_submit_server.sjs
+++ b/content/html/content/test/form_submit_server.sjs
@@ -38,27 +38,28 @@ function handleRequest(request, response
 
         let headers = {};
         let headerEnd = s.indexOf("\r\n\r\n");
         s.substr(2, headerEnd-2).split("\r\n").forEach(function(s) {
           // We're assuming UTF8 for now
           let [name, value] = s.split(': ');
           headers[name] = utf8decode(value);
         });
-	let body = s.substring(headerEnd + 4, s.length - 2);
-	if (!headers["Content-Type"] || headers["Content-Type"] == "text/plain") {
+
+        let body = s.substring(headerEnd + 4, s.length - 2);
+        if (!headers["Content-Type"] || headers["Content-Type"] == "text/plain") {
           // We're assuming UTF8 for now
-	  body = utf8decode(body);
-	}
-	result.push({ headers: headers, body: body});
+          body = utf8decode(body);
+        }
+        result.push({ headers: headers, body: body});
       });
     }
     if (contentTypeParams[''] == "text/plain" &&
         request.queryString == "plain") {
-      result = requestBody;
+      result = utf8decode(requestBody);
     }
     if (contentTypeParams[''] == "application/x-www-form-urlencoded" &&
         request.queryString == "url") {
       result = requestBody;
     }
   }
   else if (request.method == "GET") {
     result = request.queryString;
--- a/content/html/content/test/forms/test_input_email.html
+++ b/content/html/content/test/forms/test_input_email.html
@@ -82,16 +82,17 @@ var values = [
   [ '\n\n \r\rfoo@bar.com\n\n   \r\r', true ],
   [ '\n\r \n\rfoo@bar.com\n\r   \n\r', true ],
   [ 'tulip', false ],
   // Some checks on the user part of the address.
   [ '@bar.com', false ],
   [ 'f\noo@bar.com', true ],
   [ 'f\roo@bar.com', true ],
   [ 'f\r\noo@bar.com', true ],
+  [ 'fü@foo.com', true ],
   // Some checks for the domain part.
   [ 'foo@bar', true ],
   [ 'foo@b', true ],
   [ 'foo@', false ],
   [ 'foo@bar.', false ],
   [ 'foo@foo.bar', true ],
   [ 'foo@foo..bar', false ],
   [ 'foo@.bar', false ],
@@ -99,16 +100,21 @@ var values = [
   [ 'foo@tulip.foo-bar', true ],
   [ 'foo@1.2', true ],
   [ 'foo@127.0.0.1', true ],
   [ 'foo@1.2.3', true ],
   [ 'foo@b\nar.com', true ],
   [ 'foo@b\rar.com', true ],
   [ 'foo@b\r\nar.com', true ],
   [ 'foo@.', false ],
+  [ 'foo@fü.com', true ],
+  [ 'foo@fu.cüm', true ],
+  // Long strings with UTF-8.
+  [ 'this.is.email.should.be.longer.than.sixty.four.characters.föö@mözillä.tld', true ],
+  [ 'this-is-email-should-be-longer-than-sixty-four-characters-föö@mözillä.tld', true, true ],
 ];
 
 // Multiple values, we don't check e-mail validity, only multiple stuff.
 var multipleValues = [
   [ 'foo@bar.com, foo@bar.com', true ],
   [ 'foo@bar.com,foo@bar.com', true ],
   [ 'foo@bar.com,foo@bar.com,foo@bar.com', true ],
   [ '     foo@bar.com     ,     foo@bar.com    ', true ],
@@ -165,18 +171,23 @@ for each (c in legalCharacters) {
 values.push(["foo@bar.com" + legalCharacters, true]);
 
 // Add domain illegal characters.
 illegalCharacters = "()<>[]:;@\\,!#$%&'*+/=?^_`{|}~ \t";
 for each (c in illegalCharacters) {
   values.push(['foo@foo.ba' + c + 'r', false]);
 }
 
-values.forEach(function([value, valid]) {
-  testEmailAddress(email, value, false, valid);
+values.forEach(function([value, valid, todo]) {
+  if (todo === true) {
+    email.value = value;
+    todo_is(email.validity.valid, true, "value should be valid");
+  } else {
+    testEmailAddress(email, value, false, valid);
+  }
 });
 
 multipleValues.forEach(function([value, valid]) {
   testEmailAddress(email, value, true, valid);
 });
 
 // Make sure setting multiple changes the value.
 email.multiple = false;
--- a/content/html/content/test/forms/test_input_url.html
+++ b/content/html/content/test/forms/test_input_url.html
@@ -1,33 +1,24 @@
 <!DOCTYPE HTML>
 <html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=344615
--->
 <head>
-  <title>Test for Bug 344615</title>
+  <title>Tests for &lt;input type='url'&gt; validity</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-  <style>
-    input { background-color: rgb(0,0,0) !important; }
-    input:valid   { background-color: rgb(0,255,0) !important; }
-    input:invalid { background-color: rgb(255,0,0) !important; }
-  </style>
 </head>
 <body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=344615">Mozilla Bug 344615</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   <input type='url' id='i' oninvalid='invalidEventHandler(event);'>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
-/** Test for Bug 344615 **/
+/** Tests for <input type='url'> validity **/
 
 // More checks are done in test_bug551670.html.
 
 var gInvalid = false;
 
 function invalidEventHandler(e)
 {
   is(e.type, "invalid", "Invalid event type should be invalid");
@@ -39,60 +30,60 @@ function checkValidURL(element)
   gInvalid = false;
   ok(!element.validity.typeMismatch,
     "Element should not suffer from type mismatch");
   ok(element.validity.valid, "Element should be valid");
   ok(element.checkValidity(), "Element should be valid");
   ok(!gInvalid, "The invalid event should not have been thrown");
   is(element.validationMessage, '',
     "Validation message should be the empty string");
-  is(window.getComputedStyle(element, null).getPropertyValue('background-color'),
-     "rgb(0, 255, 0)", ":valid pseudo-class should apply");
+  ok(element.mozMatchesSelector(":valid"), ":valid pseudo-class should apply");
 }
 
 function checkInvalidURL(element)
 {
   gInvalid = false;
   ok(element.validity.typeMismatch,
     "Element should suffer from type mismatch");
   ok(!element.validity.valid, "Element should not be valid");
   ok(!element.checkValidity(), "Element should not be valid");
   ok(gInvalid, "The invalid event should have been thrown");
   is(element.validationMessage, "Please enter a URL.",
     "Validation message should be related to invalid URL");
-  is(window.getComputedStyle(element, null).getPropertyValue('background-color'),
-     "rgb(255, 0, 0)", ":invalid pseudo-class should apply");
+  ok(element.mozMatchesSelector(":invalid"),
+     ":invalid pseudo-class should apply");
 }
 
 var url = document.getElementById('i');
-is(url.type, 'url', "url state should be recognized");
-
-// The empty string should not be considered as invalid.
-url.value = '';
-checkValidURL(url);
-
-// We are only testing obviously (in)valid URI's because the function used
-// to check if an URI is valid is not specific to this functionality.
-url.value = 'foo';
-checkInvalidURL(url);
-
-url.value = 'http://mozilla.com/';
-checkValidURL(url);
 
-url.value = 'http://mozil\nla\r.com/';
-checkValidURL(url);
-
-url.value = '  http://mozilla.com/  ';
-checkValidURL(url);
+var values = [
+  // [ value, validity ]
+  // The empty string should be considered as valid.
+  [ "", true ],
+  [ "foo", false ],
+  [ "http://mozilla.com/", true ],
+  [ "http://mozilla.com", true ],
+  [ "http://mozil\nla\r.com/", true ],
+  [ "  http://mozilla.com/  ", true ],
+  [ "\r  http://mozilla.com/  \n", true ],
+  [ "file:///usr/bin/tulip", true ],
+  [ "../../bar.html", false ],
+  [ "http://mozillá.org", true ],
+  [ "https://mózillä.org", true ],
+  [ "http://mózillä.órg", true ],
+  [ "ht://mózillä.órg", true ],
+  [ "httŭ://mózillä.órg", false ],
+];
 
-url.value = '\r  http://mozilla.com/  \n';
-checkValidURL(url);
+values.forEach(function([value, valid]) {
+  url.value = value;
 
-url.value = 'file:///usr/bin/tulip';
-checkValidURL(url);
-
-url.value = '../../bar.html';
-checkInvalidURL(url);
+  if (valid) {
+    checkValidURL(url);
+  } else {
+    checkInvalidURL(url);
+  }
+});
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/test_formSubmission.html
+++ b/content/html/content/test/test_formSubmission.html
@@ -2,16 +2,17 @@
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=523771
 -->
 <head>
   <title>Test for Bug 523771</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=523771">Mozilla Bug 523771</a>
 <p id="display"></p>
 <iframe name="target_iframe" id="target_iframe"></iframe>
 <form action="form_submit_server.sjs" target="target_iframe" id="form"
       method="POST" enctype="multipart/form-data">
   <table>
@@ -221,16 +222,42 @@ https://bugzilla.mozilla.org/show_bug.cg
       <td><button type=foobar name="n18_2" value=""></button></td>
       <td><button type=foobar name="n18_3"></button></td>
       <td><button type=foobar name="" value="v18_4"></button></td>
       <td><button type=foobar value="v18_5"></button></td>
       <td><button type=foobar ></button></td>
       <td><button type=foobar name="n18_7_&#13;_&#10;_&#13;&#10;_ _&quot;"
                   value="v18_7_&#13;_&#10;_&#13;&#10;_ _&quot;"></button></td>
     </tr>
+    <tr>
+      <td>&lt;input type='url'&gt;</td>
+      <td><input type=url name="n19_1" value="http://v19_1.org"></td>
+      <td><input type=url name="n19_2" value=""></td>
+      <td><input type=url name="n19_3"></td>
+      <td><input type=url name="" value="http://v19_4.org"></td>
+      <td><input type=url value="http://v19_5.org"></td>
+      <td><input type=url ></td>
+      <td><input type=url name="n19_7_&#13;_&#10;_&#13;&#10;__&quot;"
+                 value="http://v19_7_&#13;_&#10;_&#13;&#10;__&quot;">
+          <!-- Put UTF-8 value in the "strange" column. -->
+          <input type=url name="n19_8" value="http://m&#xf3;zill&auml;.&#xf3;rg"></td>
+    </tr>
+    <tr>
+      <td>&lt;input type='email'&gt;</td>
+      <td><input type=email name="n20_1" value="v20_1@bar"></td>
+      <td><input type=email name="n20_2" value=""></td>
+      <td><input type=email name="n20_3"></td>
+      <td><input type=email name="" value="v20_4@bar"></td>
+      <td><input type=email value="v20_5@bar"></td>
+      <td><input type=email ></td>
+      <td><input type=email name="n20_7_&#13;_&#10;_&#13;&#10;__&quot;"
+                 value="v20_7_&#13;_&#10;_&#13;&#10;__&quot;@bar">
+          <!-- Put UTF-8 value is the "strange" column. -->
+          <input type=email name="n20_8" value="foo@mózillä.órg"></td>
+    </tr>
   </table>
   
   <p>
     File input:
     <input type=file name="file_1" class="setfile">
     <input type=file name="file_2">
     <input type=file name="" class="setfile">
     <input type=file name="">
@@ -447,16 +474,28 @@ var expectedSub = [
   // Button input
   // Image input
   // Reset input
   // Unknown input
   { name: "n13_1", value: "v13_1" },
   { name: "n13_2", value: "" },
   { name: "n13_3", value: "" },
   { name: "n13_7_\r\n_\r\n_\r\n_ _\"", value: "v13_7____ _\"" },
+  // <input type='url'>
+  { name: "n19_1", value: "http://v19_1.org" },
+  { name: "n19_2", value: "" },
+  { name: "n19_3", value: "" },
+  { name: "n19_7_\r\n_\r\n_\r\n__\"", value: "http://v19_7_____\"" },
+  { name: "n19_8", value: "http://m\xf3zill\xe4.\xf3rg" },
+  // <input type='email'>
+  { name: "n20_1", value: "v20_1@bar" },
+  { name: "n20_2", value: "" },
+  { name: "n20_3", value: "" },
+  { name: "n20_7_\r\n_\r\n_\r\n__\"", value: "v20_7_____\"@bar" },
+  { name: "n20_8", value: "foo@mózillä.órg" },
   // Default button
   // Submit button
   // Button button
   // Reset button
   // Unknown button
   // File
   { name: "file_1", value: myFile1 },
   { name: "file_2", value: emptyFile },
@@ -580,19 +619,25 @@ function checkMPSubmission(sub, expected
           "Wrong number of headers in " + test);
       is(sub[i].body,
          expected[i].value,
          "Correct value in " + test);
     }
   }
 }
 
+function utf8encode(s) {
+  return unescape(encodeURIComponent(s));
+}
+
 function checkURLSubmission(sub, expected) {
   function urlEscape(s) {
-    return escape(s).replace("%20", "+", "g");
+    return escape(utf8encode(s)).replace("%20", "+", "g")
+                                .replace("/", "%2F", "g")
+                                .replace("@", "%40", "g");
   }
 
   subItems = sub.split("&");
   is(subItems.length, expected.length,
      "Correct number of url items");
   var i;
   for (i = 0; i < expected.length; ++i) {
     let expect = urlEscape(expected[i].name) + "=" +
@@ -651,19 +696,20 @@ function runTest() {
   };
   expectedSub.forEach(fileFixup);
   expectedAugment.forEach(fileFixup);
 
   var form = $("form");
 
   // multipart/form-data
 
-  // Make normal submission
   var iframe = $("target_iframe");
   iframe.onload = function() { gen.next(); };
+
+  // Make normal submission
   form.submit();
   yield; // Wait for iframe to load as a result of the submission
   var submission = JSON.parse(iframe.contentDocument.documentElement.textContent);
   checkMPSubmission(submission, expectedSub, "normal submission");
 
   // Disabled controls
   setDisabled(document.querySelectorAll("input, select, textarea"), true);
   form.submit();
--- a/content/media/VideoUtils.cpp
+++ b/content/media/VideoUtils.cpp
@@ -34,17 +34,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "VideoUtils.h"
 #include "nsMathUtils.h"
 #include "prtypes.h"
 
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 
 // Converts from number of audio frames to microseconds, given the specified
 // audio rate.
 CheckedInt64 FramesToUsecs(PRInt64 aFrames, PRUint32 aRate) {
   return (CheckedInt64(aFrames) * USECS_PER_S) / aRate;
 }
 
 // Converts from microseconds to number of audio frames, given the specified
--- a/content/media/nsBuiltinDecoderReader.cpp
+++ b/content/media/nsBuiltinDecoderReader.cpp
@@ -41,17 +41,17 @@
 #include "nsClassHashtable.h"
 #include "nsTArray.h"
 #include "nsBuiltinDecoder.h"
 #include "nsBuiltinDecoderReader.h"
 #include "nsBuiltinDecoderStateMachine.h"
 #include "VideoUtils.h"
 
 #include "mozilla/mozalloc.h"
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
 using mozilla::layers::ImageContainer;
 using mozilla::layers::PlanarYCbCrImage;
 
 // Verify these values are sane. Once we've checked the frame sizes, we then
 // can do less integer overflow checking.
 PR_STATIC_ASSERT(MAX_VIDEO_WIDTH < PlanarYCbCrImage::MAX_DIMENSION);
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -43,17 +43,17 @@
 #include "nsBuiltinDecoderReader.h"
 #include "nsBuiltinDecoderStateMachine.h"
 #include "mozilla/mozalloc.h"
 #include "VideoUtils.h"
 #include "nsTimeRanges.h"
 #include "nsDeque.h"
 
 #include "mozilla/Preferences.h"
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 #include "mozilla/Util.h"
 
 using namespace mozilla;
 using namespace mozilla::layers;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gBuiltinDecoderLog;
 #define LOG(type, msg) PR_LOG(gBuiltinDecoderLog, type, msg)
--- a/content/media/nsMediaCache.cpp
+++ b/content/media/nsMediaCache.cpp
@@ -2155,26 +2155,28 @@ nsMediaCacheStream::Read(char* aBuffer, 
     return NS_ERROR_FAILURE;
 
   PRUint32 count = 0;
   // Read one block (or part of a block) at a time
   while (count < aCount) {
     PRUint32 streamBlock = PRUint32(mStreamOffset/BLOCK_SIZE);
     PRUint32 offsetInStreamBlock =
       PRUint32(mStreamOffset - streamBlock*BLOCK_SIZE);
-    PRInt32 size = NS_MIN(aCount - count, BLOCK_SIZE - offsetInStreamBlock);
+    PRInt64 size = NS_MIN(aCount - count, BLOCK_SIZE - offsetInStreamBlock);
 
     if (mStreamLength >= 0) {
       // Don't try to read beyond the end of the stream
       PRInt64 bytesRemaining = mStreamLength - mStreamOffset;
       if (bytesRemaining <= 0) {
         // Get out of here and return NS_OK
         break;
       }
-      size = NS_MIN(size, PRInt32(bytesRemaining));
+      size = NS_MIN(size, bytesRemaining);
+      // Clamp size until 64-bit file size issues (bug 500784) are fixed.
+      size = NS_MIN(size, PRInt64(PR_INT32_MAX));
     }
 
     PRInt32 bytes;
     PRInt32 cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1;
     if (cacheBlock < 0) {
       // We don't have a complete cached block here.
 
       if (count > 0) {
@@ -2219,17 +2221,18 @@ nsMediaCacheStream::Read(char* aBuffer, 
         return NS_ERROR_FAILURE;
       }
       continue;
     }
 
     gMediaCache->NoteBlockUsage(this, cacheBlock, mCurrentMode, TimeStamp::Now());
 
     PRInt64 offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock;
-    nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, size, &bytes);
+    NS_ABORT_IF_FALSE(size >= 0 && size <= PR_INT32_MAX, "Size out of range.");
+    nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, PRInt32(size), &bytes);
     if (NS_FAILED(rv)) {
       if (count == 0)
         return rv;
       // If we did successfully read some data, may as well return it
       break;
     }
     mStreamOffset += bytes;
     count += bytes;
@@ -2257,25 +2260,27 @@ nsMediaCacheStream::ReadFromCache(char* 
 
   // Read one block (or part of a block) at a time
   PRUint32 count = 0;
   PRInt64 streamOffset = aOffset;
   while (count < aCount) {
     PRUint32 streamBlock = PRUint32(streamOffset/BLOCK_SIZE);
     PRUint32 offsetInStreamBlock =
       PRUint32(streamOffset - streamBlock*BLOCK_SIZE);
-    PRInt32 size = NS_MIN<PRInt64>(aCount - count, BLOCK_SIZE - offsetInStreamBlock);
+    PRInt64 size = NS_MIN<PRInt64>(aCount - count, BLOCK_SIZE - offsetInStreamBlock);
 
     if (mStreamLength >= 0) {
       // Don't try to read beyond the end of the stream
       PRInt64 bytesRemaining = mStreamLength - streamOffset;
       if (bytesRemaining <= 0) {
         return NS_ERROR_FAILURE;
       }
-      size = NS_MIN(size, PRInt32(bytesRemaining));
+      size = NS_MIN(size, bytesRemaining);
+      // Clamp size until 64-bit file size issues (bug 500784) are fixed.
+      size = NS_MIN(size, PRInt64(PR_INT32_MAX));
     }
 
     PRInt32 bytes;
     PRUint32 channelBlock = PRUint32(mChannelOffset/BLOCK_SIZE);
     PRInt32 cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1;
     if (channelBlock == streamBlock && streamOffset < mChannelOffset) {
       // We can just use the data in mPartialBlockBuffer. In fact we should
       // use it rather than waiting for the block to fill and land in
@@ -2284,17 +2289,18 @@ nsMediaCacheStream::ReadFromCache(char* 
       memcpy(aBuffer + count,
         reinterpret_cast<char*>(mPartialBlockBuffer) + offsetInStreamBlock, bytes);
     } else {
       if (cacheBlock < 0) {
         // We expect all blocks to be cached! Fail!
         return NS_ERROR_FAILURE;
       }
       PRInt64 offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock;
-      nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, size, &bytes);
+      NS_ABORT_IF_FALSE(size >= 0 && size <= PR_INT32_MAX, "Size out of range.");
+      nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, PRInt32(size), &bytes);
       if (NS_FAILED(rv)) {
         return rv;
       }
     }
     streamOffset += bytes;
     count += bytes;
   }
 
--- a/content/media/ogg/nsOggCodecState.cpp
+++ b/content/media/ogg/nsOggCodecState.cpp
@@ -39,17 +39,17 @@
 #include "nsDebug.h"
 #include "nsOggCodecState.h"
 #include "nsOggDecoder.h"
 #include <string.h>
 #include "nsTraceRefcnt.h"
 #include "VideoUtils.h"
 #include "nsBuiltinDecoderReader.h"
 
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gBuiltinDecoderLog;
 #define LOG(type, msg) PR_LOG(gBuiltinDecoderLog, type, msg)
 #else
 #define LOG(type, msg)
 #endif
 
--- a/content/media/ogg/nsOggCodecState.h
+++ b/content/media/ogg/nsOggCodecState.h
@@ -46,17 +46,17 @@
 #else
 #include <vorbis/codec.h>
 #endif
 #include <nsDeque.h>
 #include <nsTArray.h>
 #include <nsClassHashtable.h>
 #include "VideoUtils.h"
 
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 
 // Uncomment the following to validate that we're predicting the number
 // of Vorbis samples in each packet correctly.
 #define VALIDATE_VORBIS_SAMPLE_CALCULATION
 #ifdef  VALIDATE_VORBIS_SAMPLE_CALCULATION
 #include <map>
 #endif
 
--- a/content/media/wave/nsWaveReader.cpp
+++ b/content/media/wave/nsWaveReader.cpp
@@ -38,17 +38,17 @@
 #include "nsError.h"
 #include "nsBuiltinDecoderStateMachine.h"
 #include "nsBuiltinDecoder.h"
 #include "MediaResource.h"
 #include "nsWaveReader.h"
 #include "nsTimeRanges.h"
 #include "VideoUtils.h"
 
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
 
 // Un-comment to enable logging of seek bisections.
 //#define SEEK_LOGGING
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gBuiltinDecoderLog;
--- a/content/media/webm/nsWebMReader.h
+++ b/content/media/webm/nsWebMReader.h
@@ -34,17 +34,17 @@
  * 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 ***** */
 #if !defined(nsWebMReader_h_)
 #define nsWebMReader_h_
 
-#include "mozilla/StdInt.h"
+#include "mozilla/StandardInteger.h"
 
 #include "nsDeque.h"
 #include "nsBuiltinDecoderReader.h"
 #include "nsWebMBufferedParser.h"
 #include "nsAutoRef.h"
 #include "nestegg/nestegg.h"
 
 #define VPX_DONT_DEFINE_STDINT_TYPES
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -111,17 +111,17 @@ XBLFinalize(JSContext *cx, JSObject *obj
     static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(obj));
   NS_RELEASE(docInfo);
   
   nsXBLJSClass* c = static_cast<nsXBLJSClass*>(::JS_GetClass(obj));
   c->Drop();
 }
 
 static JSBool
-XBLResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
+XBLResolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
            JSObject **objp)
 {
   // Note: if we get here, that means that the implementation for some binding
   // was installed, which means that AllowScripts() tested true.  Hence no need
   // to do checks like that here.
   
   // Default to not resolving things.
   NS_ASSERTION(*objp, "Must have starting object");
--- a/content/xbl/src/nsXBLProtoImplField.h
+++ b/content/xbl/src/nsXBLProtoImplField.h
@@ -75,12 +75,12 @@ public:
   const PRUnichar* GetName() const { return mName; }
 
 protected:
   nsXBLProtoImplField* mNext;
   PRUnichar* mName;
   PRUnichar* mFieldText;
   PRUint32 mFieldTextLength;
   PRUint32 mLineNumber;
-  uintN mJSAttributes;
+  unsigned mJSAttributes;
 };
 
 #endif // nsXBLProtoImplField_h__
--- a/content/xbl/src/nsXBLProtoImplProperty.h
+++ b/content/xbl/src/nsXBLProtoImplProperty.h
@@ -92,16 +92,16 @@ protected:
 
   union {
     // The raw text for the setter (prior to compilation).
     nsXBLTextWithLineNumber* mSetterText;
     // The JS object for the setter (after compilation)
     JSObject *               mJSSetterObject;
   };
   
-  uintN mJSAttributes;          // A flag for all our JS properties (getter/setter/readonly/shared/enum)
+  unsigned mJSAttributes;          // A flag for all our JS properties (getter/setter/readonly/shared/enum)
 
 #ifdef DEBUG
   bool mIsCompiled;
 #endif
 };
 
 #endif // nsXBLProtoImplProperty_h__
--- a/dom/Makefile.in
+++ b/dom/Makefile.in
@@ -42,16 +42,17 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= dom
 
 DIRS = \
   interfaces/base \
   interfaces/canvas \
+  interfaces/contacts \
   interfaces/core \
   interfaces/html \
   interfaces/events \
   interfaces/stylesheets \
   interfaces/sidebar \
   interfaces/css \
   interfaces/traversal \
   interfaces/range \
@@ -72,16 +73,17 @@ ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 DIRS += \
   interfaces/apps \
   $(NULL)
 endif
 
 DIRS += \
   base \
   battery \
+  contacts \
   power \
   sms \
   src \
   locales \
   network \
   plugins/base \
   plugins/ipc \
   indexedDB \
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -679,21 +679,16 @@ protected:
 
   virtual ~IDBEventTargetSH()
   { }
 
 public:
   NS_IMETHOD PreCreate(nsISupports *aNativeObj, JSContext *aCx,
                        JSObject *aGlobalObj, JSObject **aParentObj);
 
-  NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *aWrapper, JSContext *aCx,
-                         JSObject *aObj, jsid aId, jsval *aVp, bool *aRetval);
-
-  virtual void PreserveWrapper(nsISupports *aNative);
-
   static nsIClassInfo *doCreate(nsDOMClassInfoData *aData)
   {
     return new IDBEventTargetSH(aData);
   }
 };
 
 } // anonymous namespace
 
@@ -5147,16 +5142,21 @@ nsWindowSH::PreCreate(nsISupports *nativ
   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeObj));
   NS_ASSERTION(sgo, "nativeObj not a global object!");
 
   nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj);
   NS_ASSERTION(win->IsInnerWindow(), "Should be inner window.");
 
   JSObject *winObj = win->FastGetGlobalJSObject();
   if (!winObj) {
+
+    // See bug 691178 comment 11 for why this is necessary.
+    if (win->IsClosedOrClosing())
+      return NS_ERROR_FAILURE;
+
     NS_ASSERTION(win->GetOuterWindowInternal()->IsCreatingInnerWindow(),
                  "should have a JS object by this point");
     return NS_OK;
   }
 
   *parentObj = winObj;
   return NS_OK;
 }
@@ -5235,17 +5235,17 @@ GetDocument(JSObject *obj)
 {
   return static_cast<nsHTMLDocument*>(
     static_cast<nsIHTMLDocument*>(::JS_GetPrivate(obj)));
 }
 
 // static
 JSBool
 nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
-                                          jsid id, uintN flags,
+                                          jsid id, unsigned flags,
                                           JSObject **objp)
 {
   if (flags & (JSRESOLVE_ASSIGNING | JSRESOLVE_DECLARING |
                JSRESOLVE_CLASSNAME | JSRESOLVE_QUALIFIED) ||
       !JSID_IS_STRING(id)) {
     // Nothing to do here if we're either assigning or declaring,
     // resolving a class name, doing a qualified resolve, or
     // resolving a number.
@@ -5541,17 +5541,17 @@ FindConstructorFunc(const nsDOMClassInfo
     }
   }
   return nsnull;
 }
 
 static nsresult
 BaseStubConstructor(nsIWeakReference* aWeakOwner,
                     const nsGlobalNameStruct *name_struct, JSContext *cx,
-                    JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+                    JSObject *obj, unsigned argc, jsval *argv, jsval *rval)
 {
   nsresult rv;
   nsCOMPtr<nsISupports> native;
   if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     const nsDOMClassInfoData* ci_data =
       &sClassInfoData[name_struct->mDOMClassInfoID];
     const char *contractid = FindConstructorContractID(ci_data);
     if (contractid) {
@@ -6635,17 +6635,17 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
   }
 
   return rv;
 }
 
 // Native code for window._content getter, this simply maps
 // window._content to window.content for backwards compatibility only.
 static JSBool
-ContentWindowGetter(JSContext *cx, uintN argc, jsval *vp)
+ContentWindowGetter(JSContext *cx, unsigned argc, jsval *vp)
 {
   JSObject *obj = JS_THIS_OBJECT(cx, vp);
   if (!obj)
     return JS_FALSE;
 
   return ::JS_GetProperty(cx, obj, "content", vp);
 }
 
@@ -7695,35 +7695,16 @@ IDBEventTargetSH::PreCreate(nsISupports 
                             JSObject *aGlobalObj, JSObject **aParentObj)
 {
   IDBWrapperCache *target = IDBWrapperCache::FromSupports(aNativeObj);
   JSObject *parent = target->GetParentObject();
   *aParentObj = parent ? parent : aGlobalObj;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-IDBEventTargetSH::AddProperty(nsIXPConnectWrappedNative *aWrapper,
-                              JSContext *aCx, JSObject *aObj, jsid aId,
-                              jsval *aVp, bool *aRetval)
-{
-  if (aId != sAddEventListener_id) {
-    IDBEventTargetSH::PreserveWrapper(GetNative(aWrapper, aObj));
-  }
-
-  return NS_OK;
-}
-
-void
-IDBEventTargetSH::PreserveWrapper(nsISupports *aNative)
-{
-  IDBWrapperCache *target = IDBWrapperCache::FromSupports(aNative);
-  nsContentUtils::PreserveWrapper(aNative, target);
-}
-
 // Element helper
 
 static bool
 GetBindingURL(Element *aElement, nsIDocument *aDocument,
               nsCSSValue::URL **aResult)
 {
   // If we have a frame the frame has already loaded the binding.  And
   // otherwise, don't do anything else here unless we're dealing with
@@ -8896,17 +8877,17 @@ nsHTMLDocumentSH::DocumentAllGetProperty
     *vp = JSVAL_VOID;
   }
 
   return JS_TRUE;
 }
 
 JSBool
 nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsid id,
-                                        uintN flags, JSObject **objp)
+                                        unsigned flags, JSObject **objp)
 {
   if (flags & JSRESOLVE_ASSIGNING) {
     // Nothing to do here if we're assigning
 
     return JS_TRUE;
   }
 
   jsval v = JSVAL_VOID;
@@ -8966,17 +8947,17 @@ void
 nsHTMLDocumentSH::ReleaseDocument(JSContext *cx, JSObject *obj)
 {
   nsIHTMLDocument *doc = (nsIHTMLDocument *)::JS_GetPrivate(obj);
 
   NS_IF_RELEASE(doc);
 }
 
 JSBool
-nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, uintN argc, jsval *vp)
+nsHTMLDocumentSH::CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp)
 {
   // Handle document.all("foo") style access to document.all.
 
   if (argc != 1) {
     // XXX: Should throw NS_ERROR_XPC_NOT_ENOUGH_ARGS for argc < 1,
     // and create a new NS_ERROR_XPC_TOO_MANY_ARGS for argc > 1? IE
     // accepts nothing other than one arg.
     nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_INVALID_ARG);
@@ -9092,17 +9073,17 @@ nsHTMLDocumentSH::DocumentAllHelperGetPr
     }
   }
 
   return JS_TRUE;
 }
 
 JSBool
 nsHTMLDocumentSH::DocumentAllHelperNewResolve(JSContext *cx, JSObject *obj,
-                                              jsid id, uintN flags,
+                                              jsid id, unsigned flags,
                                               JSObject **objp)
 {
   if (id == nsDOMClassInfo::sAll_id) {
     // document.all is resolved for the first time. Define it.
     JSObject *helper = GetDocumentAllHelper(obj);
 
     if (helper) {
       if (!::JS_DefineProperty(cx, helper, "all", JSVAL_VOID, nsnull, nsnull,
@@ -9115,17 +9096,17 @@ nsHTMLDocumentSH::DocumentAllHelperNewRe
   }
 
   return JS_TRUE;
 }
 
 
 JSBool
 nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
-                                            jsid id, uintN flags,
+                                            jsid id, unsigned flags,
                                             JSObject **objp)
 {
   if (JSID_IS_STRING(id)) {
     nsDocument *doc = GetDocument(obj);
 
     JSObject *proto = ::JS_GetPrototype(obj);
     if (NS_UNLIKELY(!proto)) {
       return JS_TRUE;
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -420,17 +420,17 @@ public:
                         JSObject *obj, jsid id, PRUint32 flags,
                         JSObject **objp, bool *_retval);
   NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                       JSObject *obj);
   NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                          JSObject * obj, JSObject * *_retval);
 
   static JSBool GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
-                                              jsid id, uintN flags,
+                                              jsid id, unsigned flags,
                                               JSObject **objp);
   static JSBool GlobalScopePolluterGetProperty(JSContext *cx, JSObject *obj,
                                                jsid id, jsval *vp);
   static JSBool SecurityCheckOnAddDelProp(JSContext *cx, JSObject *obj, jsid id,
                                           jsval *vp);
   static JSBool SecurityCheckOnSetProp(JSContext *cx, JSObject *obj, jsid id,
                                        JSBool strict, jsval *vp);
   static void InvalidateGlobalScopePolluter(JSContext *cx, JSObject *obj);
@@ -858,26 +858,26 @@ protected:
   static JSBool GetDocumentAllNodeList(JSContext *cx, JSObject *obj,
                                        nsDocument *doc,
                                        nsContentList **nodeList);
 
 public:
   static JSBool DocumentAllGetProperty(JSContext *cx, JSObject *obj, jsid id,
                                        jsval *vp);
   static JSBool DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsid id,
-                                      uintN flags, JSObject **objp);
+                                      unsigned flags, JSObject **objp);
   static void ReleaseDocument(JSContext *cx, JSObject *obj);
-  static JSBool CallToGetPropMapper(JSContext *cx, uintN argc, jsval *vp);
+  static JSBool CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp);
   static JSBool DocumentAllHelperGetProperty(JSContext *cx, JSObject *obj,
                                              jsid id, jsval *vp);
   static JSBool DocumentAllHelperNewResolve(JSContext *cx, JSObject *obj,
-                                            jsid id, uintN flags,
+                                            jsid id, unsigned flags,
                                             JSObject **objp);
   static JSBool DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj,
-                                          jsid id, uintN flags,
+                                          jsid id, unsigned flags,
                                           JSObject **objp);
 
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, PRUint32 flags,
                         JSObject **objp, bool *_retval);
   NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp, bool *_retval);
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1222,58 +1222,18 @@ nsGlobalWindow::ClearControllers()
       if (context)
         context->SetCommandContext(nsnull);
     }
 
     mControllers = nsnull;
   }
 }
 
-// static
 void
-nsGlobalWindow::TryClearWindowScope(nsISupports *aWindow)
-{
-  nsGlobalWindow *window =
-          static_cast<nsGlobalWindow *>(static_cast<nsIDOMWindow*>(aWindow));
-
-  // This termination function might be called when any script evaluation in our
-  // context terminated, even if there are other scripts in the stack. Thus, we
-  // have to check again if a script is executing and post a new termination
-  // function if necessary.
-  window->ClearScopeWhenAllScriptsStop();
-}
-
-void
-nsGlobalWindow::ClearScopeWhenAllScriptsStop()
-{
-  NS_ASSERTION(IsInnerWindow(), "Must be an inner window");
-
-  // We cannot clear scope safely until all the scripts in our script context
-  // stopped. This might be a long wait, for example if one script is busy
-  // because it started a nested event loop for a modal dialog.
-  nsIScriptContext *jsscx = GetContextInternal();
-  if (jsscx && jsscx->GetExecutingScript()) {
-    // We ignore the return value because the only reason that we clear scope
-    // here is to try to prevent leaks. Failing to clear scope might mean that
-    // we'll leak more but if we don't have enough memory to allocate a
-    // termination function we probably don't have to worry about this anyway.
-    jsscx->SetTerminationFunction(TryClearWindowScope,
-                                  static_cast<nsIDOMWindow *>(this));
-    return;
-  }
-
-  NotifyWindowIDDestroyed("inner-window-destroyed");
-  nsIScriptContext *scx = GetContextInternal();
-  if (scx) {
-    scx->ClearScope(mJSObject, true);
-  }
-}
-
-void
-nsGlobalWindow::FreeInnerObjects(bool aClearScope)
+nsGlobalWindow::FreeInnerObjects()
 {
   NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
 
   // Make sure that this is called before we null out the document and
   // other members that the window destroyed observers could
   // re-create.
   NotifyDOMWindowDestroyed(this);
 
@@ -1325,19 +1285,17 @@ nsGlobalWindow::FreeInnerObjects(bool aC
 
   if (mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
     mApplicationCache = nsnull;
   }
 
   mIndexedDB = nsnull;
 
-  if (aClearScope) {
-    ClearScopeWhenAllScriptsStop();
-  }
+  NotifyWindowIDDestroyed("inner-window-destroyed");
 
   if (mDummyJavaPluginOwner) {
     // Tear down the dummy java plugin.
 
     // XXXjst: On a general note, should windows with java stuff in
     // them ever even make it into the fast-back cache?
 
     mDummyJavaPluginOwner->Destroy();
@@ -1661,17 +1619,16 @@ nsGlobalWindow::WouldReuseInnerWindow(ns
   }
   
   NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
                "How'd this happen?");
   
   // Great, we're the original document, check for one of the other
   // conditions.
   if (mDoc == aNewDocument) {
-    // aClearScopeHint is false.
     return true;
   }
 
   bool equal;
   if (NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),
                                                  &equal)) &&
       equal) {
     // The origin is the same.
@@ -1835,20 +1792,18 @@ WindowStateHolder::WindowStateHolder(nsG
 
 WindowStateHolder::~WindowStateHolder()
 {
   if (mInnerWindow) {
     // This window was left in the bfcache and is now going away. We need to
     // free it up.
     // Note that FreeInnerObjects may already have been called on the
     // inner window if its outer has already had SetDocShell(null)
-    // called.  In this case the contexts will all be null and the
-    // true for aClearScope won't do anything; this is OK since
-    // SetDocShell(null) already did it.
-    mInnerWindow->FreeInnerObjects(true);
+    // called.
+    mInnerWindow->FreeInnerObjects();
   }
 }
 
 NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder)
 
 
 struct ReparentWaiverClosure
 {
@@ -2001,22 +1956,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     return NS_ERROR_FAILURE;
   }
 
   JSAutoRequest ar(cx);
 
   nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
   NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
 
-  // Make sure to clear scope on the outer window *before* we
-  // initialize the new inner window. If we don't, things
-  // (Object.prototype etc) could leak from the old outer to the new
-  // inner scope.
-  mContext->ClearScope(mJSObject, false);
-
   if (reUseInnerWindow) {
     // We're reusing the current inner window.
     NS_ASSERTION(!currentInner->IsFrozen(),
                  "We should never be reusing a shared inner window");
     newInnerWindow = currentInner;
 
     if (aDocument != oldDoc) {
       nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
@@ -2076,66 +2025,31 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
       mCreatingInnerWindow = false;
       Thaw();
 
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (currentInner && currentInner->mJSObject) {
-      bool termFuncSet = false;
-
       if (oldDoc == aDocument) {
         // Move the navigator from the old inner window to the new one since
         // this is a document.write. This is safe from a same-origin point of
         // view because document.write can only be used by the same origin.
         newInnerWindow->mNavigator = currentInner->mNavigator;
         currentInner->mNavigator = nsnull;
         if (newInnerWindow->mNavigator) {
           newInnerWindow->mNavigator->SetWindow(newInnerWindow);
         }
-
-        // Suspend the current context's request before Pop() resumes the old
-        // context's request.
-        JSAutoSuspendRequest asr(cx);
-
-        // Pop our context here so that we get the correct one for the
-        // termination function.
-        cxPusher.Pop();
-
-        JSContext *oldCx = nsContentUtils::GetCurrentJSContext();
-
-        nsIScriptContext *callerScx;
-        if (oldCx && (callerScx = GetScriptContextFromJSContext(oldCx))) {
-          // We're called from document.open() (and document.open() is
-          // called from JS), clear the scope etc in a termination
-          // function on the calling context to prevent clearing the
-          // calling scope.
-          NS_ASSERTION(!currentInner->IsFrozen(),
-              "How does this opened window get into session history");
-
-          JSAutoRequest ar(oldCx);
-
-          callerScx->SetTerminationFunction(ClearWindowScope,
-                                            static_cast<nsIDOMWindow *>
-                                                       (currentInner));
-
-          termFuncSet = true;
-        }
-
-        // Re-push our context.
-        cxPusher.Push(cx);
       }
 
-      // Don't clear scope on our current inner window if it's going to be
+      // Don't free objects on our current inner window if it's going to be
       // held in the bfcache.
       if (!currentInner->IsFrozen()) {
-        // Skip the ClearScope if we set a termination function to do
-        // it ourselves, later.
-        currentInner->FreeInnerObjects(!termFuncSet);
+        currentInner->FreeInnerObjects();
       }
     }
 
     mInnerWindow = newInnerWindow;
 
     if (!mJSObject) {
       mContext->CreateOuterObject(this, newInnerWindow);
       mContext->DidInitializeContext();
@@ -2172,17 +2086,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
         }
 
         JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
 
         mContext->SetOuterObject(mJSObject);
 
         JSCompartment *compartment = js::GetObjectCompartment(mJSObject);
         xpc::CompartmentPrivate *priv =
-          static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(cx, compartment));
+          static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment));
         if (priv && priv->waiverWrapperMap) {
           NS_ASSERTION(!JS_IsExceptionPending(cx),
                        "We might overwrite a pending exception!");
           ReparentWaiverClosure closure = {
             cx,
             newInnerWindow->mJSObject
           };
           priv->waiverWrapperMap->Enumerate(ReparentWaiverWrappers, &closure);
@@ -2428,17 +2342,17 @@ nsGlobalWindow::SetDocShell(nsIDocShell*
     // Call FreeInnerObjects on all inner windows, not just the current
     // one, since some could be held by WindowStateHolder objects that
     // are GC-owned.
     for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
          inner != this;
          inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
       NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
                    "bad outer window pointer");
-      inner->FreeInnerObjects(true);
+      inner->FreeInnerObjects();
     }
 
     // Make sure that this is called before we null out the document.
     NotifyDOMWindowDestroyed(this);
 
     NotifyWindowIDDestroyed("outer-window-destroyed");
 
     nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
@@ -2450,20 +2364,16 @@ nsGlobalWindow::SetDocShell(nsIDocShell*
       mDocumentPrincipal = mDoc->NodePrincipal();
 
       // Release our document reference
       mDocument = nsnull;
       mDoc = nsnull;
       mFocusedNode = nsnull;
     }
 
-    if (mContext) {
-      mContext->ClearScope(mJSObject, true);
-    }
-
     ClearControllers();
 
     mChromeEventHandler = nsnull; // force release now
 
     if (mArguments) { 
       // We got no new document after someone called
       // SetArguments(), drop our reference to the arguments.
       mArguments = nsnull;
@@ -8980,27 +8890,16 @@ nsGlobalWindow::CloseWindow(nsISupports 
                (static_cast<nsPIDOMWindow*>(win));
 
   // Need to post an event for closing, otherwise window and 
   // presshell etc. may get destroyed while creating frames, bug 338897.
   nsCloseEvent::PostCloseEvent(globalWin);
   // else if OOM, better not to close. That might cause a crash.
 }
 
-// static
-void
-nsGlobalWindow::ClearWindowScope(nsISupports *aWindow)
-{
-  nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(aWindow));
-  nsIScriptContext *scx = sgo->GetContext();
-  if (scx) {
-    scx->ClearScope(sgo->GetGlobalJSObject(), true);
-  }
-}
-
 //*****************************************************************************
 // nsGlobalWindow: Timeout Functions
 //*****************************************************************************
 
 PRUint32 sNestingLevel;
 
 nsresult
 nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -231,17 +231,17 @@ private:
 
 //*****************************************************************************
 // nsOuterWindow: Outer Window Proxy
 //*****************************************************************************
 
 class nsOuterWindowProxy : public js::Wrapper
 {
 public:
-  nsOuterWindowProxy() : js::Wrapper((uintN)0) {}
+  nsOuterWindowProxy() : js::Wrapper((unsigned)0) {}
 
   virtual bool isOuterWindow() {
     return true;
   }
   JSString *obj_toString(JSContext *cx, JSObject *wrapper);
   void finalize(JSContext *cx, JSObject *proxy);
 
   static nsOuterWindowProxy singleton;
@@ -590,21 +590,19 @@ private:
 protected:
   friend class HashchangeCallback;
   friend class nsBarProp;
 
   // Object Management
   virtual ~nsGlobalWindow();
   void CleanUp(bool aIgnoreModalDialog);
   void ClearControllers();
-  static void TryClearWindowScope(nsISupports* aWindow);
-  void ClearScopeWhenAllScriptsStop();
   nsresult FinalClose();
 
-  void FreeInnerObjects(bool aClearScope);
+  void FreeInnerObjects();
   nsGlobalWindow *CallerInnerWindow();
 
   nsresult InnerSetNewDocument(nsIDocument* aDocument);
 
   nsresult DefineArgumentsProperty(nsIArray *aArguments);
 
   // Get the parent, returns null if this is a toplevel window
   nsIDOMWindow* GetParentInternal();
@@ -672,17 +670,16 @@ protected:
                                     bool aDoJSFixups,
                                     nsIArray *argv,
                                     nsISupports *aExtraArgument,
                                     nsIPrincipal *aCalleePrincipal,
                                     JSContext *aJSCallerContext,
                                     nsIDOMWindow **aReturn);
 
   static void CloseWindow(nsISupports* aWindow);
-  static void ClearWindowScope(nsISupports* aWindow);
 
   // Timeout Functions
   // Language agnostic timeout function (all args passed).
   // |interval| is in milliseconds.
   nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
                                 PRInt32 interval,
                                 bool aIsInterval, PRInt32 *aReturn);
   nsresult ClearTimeoutOrInterval(PRInt32 aTimerID);
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -70,18 +70,18 @@ public:
 
   virtual nsIScriptObjectPrincipal* GetObjectPrincipal() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
                               NS_ISCRIPTCONTEXTPRINCIPAL_IID)
 
 #define NS_ISCRIPTCONTEXT_IID \
-{ 0xf3840057, 0x4fe5, 0x4f92, \
- { 0xa3, 0xb8, 0x27, 0xd7, 0x44, 0x6f, 0x72, 0x4d } }
+{ 0x6d69fbee, 0x0723, 0x48f5, \
+ { 0x82, 0x48, 0xcd, 0xcf, 0x88, 0xac, 0x25, 0x74 } }
 
 /* This MUST match JSVERSION_DEFAULT.  This version stuff if we don't
    know what language we have is a little silly... */
 #define SCRIPTVERSION_DEFAULT JSVERSION_DEFAULT
 
 /**
  * It is used by the application to initialize a runtime and run scripts.
  * A script runtime would implement this interface.
@@ -423,30 +423,16 @@ public:
    * Initialize DOM classes on aGlobalObj, always call
    * WillInitializeContext() before calling InitContext(), and always
    * call DidInitializeContext() when a context is fully
    * (successfully) initialized.
    */
   virtual nsresult InitClasses(JSObject* aGlobalObj) = 0;
 
   /**
-   * Clear the scope object - may be called either as we are being torn down,
-   * or before we are attached to a different document.
-   *
-   * aClearFromProtoChain is probably somewhat JavaScript specific.  It
-   * indicates that the global scope polluter should be removed from the
-   * prototype chain and that the objects in the prototype chain should
-   * also have their scopes cleared.  We don't do this all the time
-   * because the prototype chain is shared between inner and outer
-   * windows, and needs to stay with inner windows that we're keeping
-   * around.
-   */
-  virtual void ClearScope(void* aGlobalObj, bool aClearFromProtoChain) = 0;
-
-  /**
    * Tell the context we're about to be reinitialize it.
    */
   virtual void WillInitializeContext() = 0;
 
   /**
    * Tell the context we're done reinitializing it.
    */
   virtual void DidInitializeContext() = 0;
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2717,39 +2717,39 @@ CheckUniversalXPConnectForTraceMalloc(JS
                     IsCapabilityEnabled("UniversalXPConnect", &hasCap);
     if (NS_SUCCEEDED(rv) && hasCap)
         return JS_TRUE;
     JS_ReportError(cx, "trace-malloc functions require UniversalXPConnect");
     return JS_FALSE;
 }
 
 static JSBool
-TraceMallocDisable(JSContext *cx, uintN argc, jsval *vp)
+TraceMallocDisable(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (!CheckUniversalXPConnectForTraceMalloc(cx))
         return JS_FALSE;
 
     NS_TraceMallocDisable();
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-TraceMallocEnable(JSContext *cx, uintN argc, jsval *vp)
+TraceMallocEnable(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (!CheckUniversalXPConnectForTraceMalloc(cx))
         return JS_FALSE;
 
     NS_TraceMallocEnable();
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-TraceMallocOpenLogFile(JSContext *cx, uintN argc, jsval *vp)
+TraceMallocOpenLogFile(JSContext *cx, unsigned argc, jsval *vp)
 {
     int fd;
     JSString *str;
 
     if (!CheckUniversalXPConnectForTraceMalloc(cx))
         return JS_FALSE;
 
     if (argc == 0) {
@@ -2767,17 +2767,17 @@ TraceMallocOpenLogFile(JSContext *cx, ui
             return JS_FALSE;
         }
     }
     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(fd));
     return JS_TRUE;
 }
 
 static JSBool
-TraceMallocChangeLogFD(JSContext *cx, uintN argc, jsval *vp)
+TraceMallocChangeLogFD(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (!CheckUniversalXPConnectForTraceMalloc(cx))
         return JS_FALSE;
 
     int32_t fd, oldfd;
     if (argc == 0) {
         oldfd = -1;
     } else {
@@ -2789,50 +2789,50 @@ TraceMallocChangeLogFD(JSContext *cx, ui
             return JS_FALSE;
         }
     }
     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(oldfd));
     return JS_TRUE;
 }
 
 static JSBool
-TraceMallocCloseLogFD(JSContext *cx, uintN argc, jsval *vp)
+TraceMallocCloseLogFD(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (!CheckUniversalXPConnectForTraceMalloc(cx))
         return JS_FALSE;
 
     int32_t fd;
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     if (argc == 0)
         return JS_TRUE;
     if (!JS_ValueToECMAInt32(cx, JS_ARGV(cx, vp)[0], &fd))
         return JS_FALSE;
     NS_TraceMallocCloseLogFD((int) fd);
     return JS_TRUE;
 }
 
 static JSBool
-TraceMallocLogTimestamp(JSContext *cx, uintN argc, jsval *vp)
+TraceMallocLogTimestamp(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (!CheckUniversalXPConnectForTraceMalloc(cx))
         return JS_FALSE;
 
     JSString *str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
     if (!str)
         return JS_FALSE;
     JSAutoByteString caption(cx, str);
     if (!caption)
         return JS_FALSE;
     NS_TraceMallocLogTimestamp(caption.ptr());
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-TraceMallocDumpAllocations(JSContext *cx, uintN argc, jsval *vp)
+TraceMallocDumpAllocations(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (!CheckUniversalXPConnectForTraceMalloc(cx))
         return JS_FALSE;
 
     JSString *str = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);
     if (!str)
         return JS_FALSE;
     JSAutoByteString pathname(cx, str);
@@ -2870,17 +2870,17 @@ IsJProfAction(struct sigaction *action)
             (action->sa_flags & (SA_RESTART | SA_SIGINFO)) == (SA_RESTART | SA_SIGINFO));
 }
 
 void NS_JProfStartProfiling();
 void NS_JProfStopProfiling();
 void NS_JProfClearCircular();
 
 static JSBool
-JProfStartProfilingJS(JSContext *cx, uintN argc, jsval *vp)
+JProfStartProfilingJS(JSContext *cx, unsigned argc, jsval *vp)
 {
   NS_JProfStartProfiling();
   return JS_TRUE;
 }
 
 void NS_JProfStartProfiling()
 {
     // Figure out whether we're dealing with SIGPROF, SIGALRM, or
@@ -2912,45 +2912,45 @@ void NS_JProfStartProfiling()
         raise(SIGPOLL);
         return;
     }
 
     printf("Could not start jprof-profiling since JPROF_FLAGS was not set.\n");
 }
 
 static JSBool
-JProfStopProfilingJS(JSContext *cx, uintN argc, jsval *vp)
+JProfStopProfilingJS(JSContext *cx, unsigned argc, jsval *vp)
 {
   NS_JProfStopProfiling();
   return JS_TRUE;
 }
 
 void
 NS_JProfStopProfiling()
 {
     raise(SIGUSR1);
     //printf("Stopped jprof profiling.\n");
 }
 
 static JSBool
-JProfClearCircularJS(JSContext *cx, uintN argc, jsval *vp)
+JProfClearCircularJS(JSContext *cx, unsigned argc, jsval *vp)
 {
   NS_JProfClearCircular();
   return JS_TRUE;
 }
 
 void
 NS_JProfClearCircular()
 {
     raise(SIGUSR2);
     //printf("cleared jprof buffer\n");
 }
 
 static JSBool
-JProfSaveCircularJS(JSContext *cx, uintN argc, jsval *vp)
+JProfSaveCircularJS(JSContext *cx, unsigned argc, jsval *vp)
 {
   // Not ideal...
   NS_JProfStopProfiling();
   NS_JProfStartProfiling();
   return JS_TRUE;
 }
 
 static JSFunctionSpec JProfFunctions[] = {
@@ -2964,17 +2964,17 @@ static JSFunctionSpec JProfFunctions[] =
 #endif /* defined(MOZ_JPROF) */
 
 #ifdef MOZ_DMD
 
 // See https://wiki.mozilla.org/Performance/MemShrink/DMD for instructions on
 // how to use DMD.
 
 static JSBool
-DMDCheckJS(JSContext *cx, uintN argc, jsval *vp)
+DMDCheckJS(JSContext *cx, unsigned argc, jsval *vp)
 {
   mozilla::DMDCheckAndDump();
   return JS_TRUE;
 }
 
 static JSFunctionSpec DMDFunctions[] = {
     {"DMD",                        DMDCheckJS,                 0, 0},
     {nsnull,                       nsnull,                     0, 0}
@@ -3011,92 +3011,16 @@ nsJSContext::InitClasses(JSObject* aGlob
 #endif
 
   JSOptionChangedCallback(js_options_dot_str, this);
 
   return rv;
 }
 
 void
-nsJSContext::ClearScope(void *aGlobalObj, bool aClearFromProtoChain)
-{
-  // Push our JSContext on our thread's context stack.
-  nsCOMPtr<nsIJSContextStack> stack =
-    do_GetService("@mozilla.org/js/xpc/ContextStack;1");
-  if (stack && NS_FAILED(stack->Push(mContext))) {
-    stack = nsnull;
-  }
-
-  if (aGlobalObj) {
-    JSObject *obj = (JSObject *)aGlobalObj;
-    JSAutoRequest ar(mContext);
-
-    JSAutoEnterCompartment ac;
-    ac.enterAndIgnoreErrors(mContext, obj);
-
-    // Grab a reference to the window property, which is the outer
-    // window, so that we can re-define it once we've cleared
-    // scope. This is what keeps the outer window alive in cases where
-    // nothing else does.
-    jsval window;
-    if (!JS_GetProperty(mContext, obj, "window", &window)) {
-      window = JSVAL_VOID;
-
-      JS_ClearPendingException(mContext);
-    }
-
-    JS_ClearScope(mContext, obj);
-
-    NS_ABORT_IF_FALSE(!xpc::WrapperFactory::IsXrayWrapper(obj), "unexpected wrapper");
-
-    if (window != JSVAL_VOID) {
-      if (!JS_DefineProperty(mContext, obj, "window", window,
-                             JS_PropertyStub, JS_StrictPropertyStub,
-                             JSPROP_ENUMERATE | JSPROP_READONLY |
-                             JSPROP_PERMANENT)) {
-        JS_ClearPendingException(mContext);
-      }
-    }
-
-    if (!js::GetObjectParent(obj)) {
-      JS_ClearRegExpStatics(mContext, obj);
-    }
-
-    // Always clear watchpoints, to deal with two cases:
-    // 1.  The first document for this window is loading, and a miscreant has
-    //     preset watchpoints on the window object in order to attack the new
-    //     document's privileged information.
-    // 2.  A document loaded and used watchpoints on its own window, leaving
-    //     them set until the next document loads. We must clean up window
-    //     watchpoints here.
-    // Watchpoints set on document and subordinate objects are all cleared
-    // when those sub-window objects are finalized, after JS_ClearScope and
-    // a GC run that finds them to be garbage.
-    ::JS_ClearWatchPointsForObject(mContext, obj);
-
-    // Since the prototype chain is shared between inner and outer (and
-    // stays with the inner), we don't clear things from the prototype
-    // chain when we're clearing an outer window whose current inner we
-    // still want.
-    if (aClearFromProtoChain) {
-      nsWindowSH::InvalidateGlobalScopePolluter(mContext, obj);
-
-      // Clear up obj's prototype chain, but not Object.prototype.
-      for (JSObject *o = ::JS_GetPrototype(obj), *next;
-           o && (next = ::JS_GetPrototype(o)); o = next)
-        ::JS_ClearScope(mContext, o);
-    }
-  }
-
-  if (stack) {
-    stack->Pop(nsnull);
-  }
-}
-
-void
 nsJSContext::WillInitializeContext()
 {
   mIsInitialized = false;
 }
 
 void
 nsJSContext::DidInitializeContext()
 {
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -156,17 +156,16 @@ public:
   virtual bool GetProcessingScriptTag();
   virtual void SetProcessingScriptTag(bool aResult);
 
   virtual bool GetExecutingScript();
 
   virtual void SetGCOnDestruction(bool aGCOnDestruction);
 
   virtual nsresult InitClasses(JSObject* aGlobalObj);
-  virtual void ClearScope(void* aGlobalObj, bool bClearPolluters);
 
   virtual void WillInitializeContext();
   virtual void DidInitializeContext();
 
   virtual nsresult Serialize(nsIObjectOutputStream* aStream, JSScript* aScriptObject);
   virtual nsresult Deserialize(nsIObjectInputStream* aStream,
                                nsScriptObjectHolder<JSScript>& aResult);
 
new file mode 100644
--- /dev/null
+++ b/dom/contacts/ContactManager.js
@@ -0,0 +1,404 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict"
+
+/* static functions */
+let DEBUG = 0;
+if (DEBUG)
+  debug = function (s) { dump("-*- ContactManager: " + s + "\n"); }
+else
+  debug = function (s) {}
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+const nsIClassInfo            = Ci.nsIClassInfo;
+const CONTACTPROPERTIES_CID   = Components.ID("{53ed7c20-ceda-11e0-9572-0800200c9a66}");
+const nsIDOMContactProperties = Ci.nsIDOMContactProperties;
+
+// ContactProperties is not directly instantiated. It is used as interface.
+
+ContactProperties.prototype = {
+
+  classID : CONTACTPROPERTIES_CID,
+  classInfo : XPCOMUtils.generateCI({classID: CONTACTPROPERTIES_CID,
+                                     contractID:"@mozilla.org/contactProperties;1",
+                                     classDescription: "ContactProperties",
+                                     interfaces: [nsIDOMContactProperties],
+                                     flags: nsIClassInfo.DOM_OBJECT}),
+
+  QueryInterface : XPCOMUtils.generateQI([nsIDOMContactProperties])
+}
+
+//ContactAddress
+
+const CONTACTADDRESS_CONTRACTID = "@mozilla.org/contactAddress;1";
+const CONTACTADDRESS_CID        = Components.ID("{27a568b0-cee1-11e0-9572-0800200c9a66}");
+const nsIDOMContactAddress      = Components.interfaces.nsIDOMContactAddress;
+
+function ContactAddress(aStreetAddress, aLocality, aRegion, aPostalCode, aCountryName) {
+  this.streetAddress = aStreetAddress || null;
+  this.locality = aLocality || null;
+  this.region = aRegion || null;
+  this.postalCode = aPostalCode || null;
+  this.countryName = aCountryName || null;
+};
+
+function ContactProperties(aProp) { debug("ContactProperties Constructor"); }
+
+ContactAddress.prototype = {
+
+  classID : CONTACTADDRESS_CID,
+  classInfo : XPCOMUtils.generateCI({classID: CONTACTADDRESS_CID,
+                                     contractID: CONTACTADDRESS_CONTRACTID,
+                                     classDescription: "ContactAddress",
+                                     interfaces: [nsIDOMContactAddress],
+                                     flags: nsIClassInfo.DOM_OBJECT}),
+
+  QueryInterface : XPCOMUtils.generateQI([nsIDOMContactAddress])
+}
+
+//ContactFindOptions
+
+const CONTACTFINDOPTIONS_CONTRACTID = "@mozilla.org/contactFindOptions;1";
+const CONTACTFINDOPTIONS_CID        = Components.ID("{e31daea0-0cb6-11e1-be50-0800200c9a66}");
+const nsIDOMContactFindOptions      = Components.interfaces.nsIDOMContactFindOptions;
+
+function ContactFindOptions(aFilterValue, aFilterBy, aFilterOp, aFilterLimit) {
+  this.filterValue = aFilterValue || '';
+
+  this.filterBy = new Array();
+  for (let field in aFilterBy)
+    this.filterBy.push(field);
+
+  this.filterOp = aFilterOp || '';
+  this.filterLimit = aFilterLimit || 0;
+};
+
+ContactFindOptions.prototype = {
+
+  classID : CONTACTFINDOPTIONS_CID,
+  classInfo : XPCOMUtils.generateCI({classID: CONTACTFINDOPTIONS_CID,
+                                     contractID: CONTACTFINDOPTIONS_CONTRACTID,
+                                     classDescription: "ContactFindOptions",
+                                     interfaces: [nsIDOMContactFindOptions],
+                                     flags: nsIClassInfo.DOM_OBJECT}),
+              
+  QueryInterface : XPCOMUtils.generateQI([nsIDOMContactFindOptions])
+}
+
+//Contact
+
+const CONTACT_CONTRACTID = "@mozilla.org/contact;1";
+const CONTACT_CID        = Components.ID("{da0f7040-388b-11e1-b86c-0800200c9a66}");
+const nsIDOMContact      = Components.interfaces.nsIDOMContact;
+
+function Contact() { debug("Contact constr: "); };
+
+Contact.prototype = {
+  
+  init: function init(aProp) {
+    // Accept non-array strings for DOMString[] properties and convert them.
+    function _create(aField) {
+      if (typeof aField == "string")
+        return new Array(aField);
+      return aField;
+    };
+
+    this.name =            _create(aProp.name) || null;
+    this.honorificPrefix = _create(aProp.honorificPrefix) || null;
+    this.givenName =       _create(aProp.givenName) || null;
+    this.additionalName =  _create(aProp.additionalName) || null;
+    this.familyName =      _create(aProp.familyName) || null;
+    this.honorificSuffix = _create(aProp.honorificSuffix) || null;
+    this.nickname =        _create(aProp.nickname) || null;
+    this.email =           _create(aProp.email) || null;
+    this.photo =           _create(aProp.photo) || null;
+    this.url =             _create(aProp.url) || null;
+    this.category =        _create(aProp.category) || null;
+
+    if (aProp.adr) {
+      // Make sure adr argument is an array. Instanceof doesn't work.
+      aProp.adr = aProp.adr.length == undefined ? [aProp.adr] : aProp.adr;
+
+      this.adr = new Array();
+      for (let i = 0; i < aProp.adr.length; i++)
+        this.adr.push(new ContactAddress(aProp.adr[i].streetAddress, aProp.adr[i].locality,
+                                         aProp.adr[i].region, aProp.adr[i].postalCode,
+                                         aProp.adr[i].countryName));
+    } else {
+      this.adr = null;
+    }
+
+    this.tel =             _create(aProp.tel) || null;
+    this.org =             _create(aProp.org) || null;
+    this.bday =            (aProp.bday == "undefined" || aProp.bday == null) ? null : new Date(aProp.bday);
+    this.note =            _create(aProp.note) || null;
+    this.impp =            _create(aProp.impp) || null;
+    this.anniversary =     (aProp.anniversary == "undefined" || aProp.anniversary == null) ? null : new Date(aProp.anniversary);
+    this.sex =             (aProp.sex != "undefined") ? aProp.sex : null;
+    this.genderIdentity =  (aProp.genderIdentity != "undefined") ? aProp.genderIdentity : null;
+  },
+
+  get published () {
+    return this._published;
+  },
+
+  set published(aPublished) {
+    this._published = aPublished;
+  },
+
+  get updated () {
+    return this._updated;
+  },
+ 
+  set updated(aUpdated) {
+    this._updated = aUpdated;
+  },
+
+  classID : CONTACT_CID,
+  classInfo : XPCOMUtils.generateCI({classID: CONTACT_CID,
+                                     contractID: CONTACT_CONTRACTID,
+                                     classDescription: "Contact",
+                                     interfaces: [nsIDOMContact, nsIDOMContactProperties],
+                                     flags: nsIClassInfo.DOM_OBJECT}),
+
+  QueryInterface : XPCOMUtils.generateQI([nsIDOMContact, nsIDOMContactProperties])
+}
+
+// ContactManager
+
+const CONTACTMANAGER_CONTRACTID = "@mozilla.org/contactManager;1";
+const CONTACTMANAGER_CID        = Components.ID("{50a820b0-ced0-11e0-9572-0800200c9a66}");
+const nsIDOMContactManager      = Components.interfaces.nsIDOMContactManager;
+
+function ContactManager()
+{
+  debug("Constructor");
+}
+
+ContactManager.prototype = {
+
+  save: function save(aContact) {
+    let request;
+    if (this.hasPrivileges) {
+      debug("save: " + JSON.stringify(aContact) + " :" + aContact.id);
+      let newContact = {};
+      newContact.properties = {
+        name:            [],
+        honorificPrefix: [],
+        givenName:       [],
+        additionalName:  [],
+        familyName:      [],
+        honorificSuffix: [],
+        nickname:        [],
+        email:           [],
+        photo:           [],
+        url:             [],
+        category:        [],
+        adr:             [],
+        tel:             [],
+        org:             [],
+        bday:            null,
+        note:            [],
+        impp:            [],
+        anniversary:     null,
+        sex:             null,
+        genderIdentity:  null
+      };
+      for (let field in newContact.properties)
+        newContact.properties[field] = aContact[field];
+
+      if (aContact.id == "undefined") {
+        debug("Create id!");
+        aContact.id = this._getRandomId();
+      }
+
+      this._setMetaData(newContact, aContact);
+      debug("send: " + JSON.stringify(newContact));
+      request = this._rs.createRequest(this._window);
+      this._mm.sendAsyncMessage("Contact:Save", {contact: newContact,
+                                                 requestID: this.getRequestId({ request: request })});
+      return request;
+    } else {
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  },
+
+  remove: function removeContact(aRecord) {
+    let request;
+    if (this.hasPrivileges) {
+      request = this._rs.createRequest(this._window);
+      this._mm.sendAsyncMessage("Contact:Remove", {id: aRecord.id,
+                                                   requestID: this.getRequestId({ request: request })});
+      return request;
+    } else {
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  },
+
+  _setMetaData: function(aNewContact, aRecord) {
+    aNewContact.id = aRecord.id;
+    aNewContact.published = aRecord.published;
+    aNewContact.updated = aRecord.updated;
+  },
+
+  _convertContactsArray: function(aContacts) {
+    let contacts = new Array();
+    for (let i in aContacts) {
+      let newContact = new Contact();
+      newContact.init(aContacts[i].properties);
+      this._setMetaData(newContact, aContacts[i]);
+      contacts.push(newContact);
+    }
+    return contacts;
+  },
+
+  getRequestId: function(aRequest) {
+    let id = "id" + this._getRandomId();
+    this._requests[id] = aRequest;
+    return id;
+  },
+
+  getRequest: function(aId) {
+    if (this._requests[aId])
+      return this._requests[aId].request;
+  },
+
+  removeRequest: function(aId) {
+    if (this._requests[aId])
+      delete this._requests[aId];
+  },
+  
+  _getRandomId: function() {
+    return Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString();
+  },
+
+  receiveMessage: function(aMessage) {
+    debug("Contactmanager::receiveMessage: " + aMessage.name);
+    let msg = aMessage.json;
+    let contacts = msg.contacts;
+
+    switch (aMessage.name) {
+      case "Contacts:Find:Return:OK":
+        let req = this.getRequest(msg.requestID);
+        if (req) {
+          let result = this._convertContactsArray(contacts);
+          debug("result: " + JSON.stringify(result));
+          this._rs.fireSuccess(req, result);
+        } else {
+          debug("no request stored!" + msg.requestID);
+        }
+        break;
+      case "Contact:Save:Return:OK":
+      case "Contacts:Clear:Return:OK":
+      case "Contact:Remove:Return:OK":
+        req = this.getRequest(msg.requestID);
+        if (req)
+          this._rs.fireSuccess(req, 0);
+        break;
+      case "Contacts:Find:Return:KO":
+      case "Contact:Save:Return:KO":
+      case "Contact:Remove:Return:KO":
+      case "Contacts:Clear:Return:KO":
+        req = this.getRequest(msg.requestID);
+        if (req)
+          this._rs.fireError(req, msg.errorMsg);
+        break;
+      default: 
+        debug("Wrong message: " + aMessage.name);
+    }
+    this.removeRequest(msg.requestID);
+  },
+
+  find: function(aOptions) {
+    let request;
+    if (this.hasPrivileges) {
+      request = this._rs.createRequest(this._window);
+      this._mm.sendAsyncMessage("Contacts:Find", {findOptions: aOptions, 
+                                                  requestID: this.getRequestId({ request: request })});
+      return request;
+    } else {
+      debug("find not allowed");
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  },
+
+  clear: function() {
+    let request;
+    if (this.hasPrivileges) {
+      request = this._rs.createRequest(this._window);
+      this._mm.sendAsyncMessage("Contacts:Clear", {requestID: this.getRequestId({ request: request })});
+      return request;
+    } else {
+      debug("clear not allowed");
+      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  },
+
+  init: function(aWindow) {
+    // Set navigator.mozContacts to null.
+    if (!Services.prefs.getBoolPref("dom.mozContacts.enabled"))
+      return null;
+
+    this._window = aWindow;
+    this._messages = ["Contacts:Find:Return:OK", "Contacts:Find:Return:KO",
+                     "Contacts:Clear:Return:OK", "Contacts:Clear:Return:KO",
+                     "Contact:Save:Return:OK", "Contact:Save:Return:KO",
+                     "Contact:Remove:Return:OK", "Contact:Remove:Return:KO"];
+
+    this._mm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager);
+    this._messages.forEach((function(msgName) {
+      this._mm.addMessageListener(msgName, this);
+    }).bind(this));
+
+    this._rs = Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
+    this._requests = [];
+    Services.obs.addObserver(this, "inner-window-destroyed", false);
+    let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+    this._innerWindowID = util.currentInnerWindowID;
+
+    let principal = aWindow.document.nodePrincipal;
+    let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
+
+    let perm = principal == secMan.getSystemPrincipal() ? 
+                 Ci.nsIPermissionManager.ALLOW_ACTION : 
+                 Services.perms.testExactPermission(principal.URI, "webcontacts-manage");
+ 
+    //only pages with perm set can use the contacts
+    this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
+    debug("has privileges :" + this.hasPrivileges);
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
+    if (wId == this.innerWindowID) {
+      Services.obs.removeObserver(this, "inner-window-destroyed");
+      this._messages.forEach((function(msgName) {
+        this._mm.removeMessageListener(msgName, this);
+      }).bind(this));
+      this._mm = null;
+      this._messages = null;
+      this._requests = null;
+      this._window = null;
+      this._innerWindowID = null;
+    }
+  },
+
+  classID : CONTACTMANAGER_CID,
+  QueryInterface : XPCOMUtils.generateQI([nsIDOMContactManager, Ci.nsIDOMGlobalPropertyInitializer]),
+
+  classInfo : XPCOMUtils.generateCI({classID: CONTACTMANAGER_CID,
+                                     contractID: CONTACTMANAGER_CONTRACTID,
+                                     classDescription: "ContactManager",
+                                     interfaces: [nsIDOMContactManager],
+                                     flags: nsIClassInfo.DOM_OBJECT})
+}
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([Contact, ContactManager, ContactProperties, ContactAddress, ContactFindOptions])
new file mode 100644
--- /dev/null
+++ b/dom/contacts/ContactManager.manifest
@@ -0,0 +1,16 @@
+component {53ed7c20-ceda-11e0-9572-0800200c9a66} ContactManager.js
+contract @mozilla.org/contactProperties;1 {53ed7c20-ceda-11e0-9572-0800200c9a66}
+
+component {27a568b0-cee1-11e0-9572-0800200c9a66} ContactManager.js
+contract @mozilla.org/contactAddress;1 {27a568b0-cee1-11e0-9572-0800200c9a66}
+
+component {e31daea0-0cb6-11e1-be50-0800200c9a66} ContactManager.js
+contract @mozilla.org/contactFindOptions;1 {e31daea0-0cb6-11e1-be50-0800200c9a66}
+
+component {da0f7040-388b-11e1-b86c-0800200c9a66} ContactManager.js
+contract @mozilla.org/contact;1 {da0f7040-388b-11e1-b86c-0800200c9a66}
+category JavaScript-global-constructor mozContact @mozilla.org/contact;1
+
+component {50a820b0-ced0-11e0-9572-0800200c9a66} ContactManager.js
+contract @mozilla.org/contactManager;1 {50a820b0-ced0-11e0-9572-0800200c9a66}
+category JavaScript-navigator-property mozContacts @mozilla.org/contactManager;1
new file mode 100644
--- /dev/null
+++ b/dom/contacts/Makefile.in
@@ -0,0 +1,47 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH		= ../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH            = \
+  $(srcdir)        \
+  $(NULL)
+
+include $(DEPTH)/config/autoconf.mk
+
+ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
+VPATH += $(srcdir)/fallback
+endif
+
+MODULE         = dom
+LIBRARY_NAME   = jsdomcontacts_s
+LIBXUL_LIBRARY = 1
+
+EXTRA_COMPONENTS =              \
+  ContactManager.js             \
+  ContactManager.manifest       \
+  $(NULL)
+
+ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
+EXTRA_JS_MODULES = ContactService.jsm \
+                   $(NULL)
+
+EXTRA_JS_MODULES += ContactDB.jsm \
+                    $(NULL)
+endif
+
+ifdef ENABLE_TESTS
+DIRS += tests
+endif
+
+# Add VPATH to LOCAL_INCLUDES so we are going to include the correct backend
+# subdirectory (and the ipc one).
+LOCAL_INCLUDES += $(VPATH:%=-I%)
+
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+include $(topsrcdir)/config/rules.mk
+
+DEFINES += -D_IMPL_NS_LAYOUT
new file mode 100644
--- /dev/null
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -0,0 +1,410 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const EXPORTED_SYMBOLS = ['ContactDB'];
+
+let DEBUG = 0;
+/* static functions */
+if (DEBUG)
+    debug = function (s) { dump("-*- ContactDB component: " + s + "\n"); }
+else
+    debug = function (s) {}
+
+const Cu = Components.utils; 
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+const DB_NAME = "contacts";
+const DB_VERSION = 1;
+const STORE_NAME = "contacts";
+
+function ContactDB(aGlobal) {
+  debug("Constructor");
+  this._indexedDB = aGlobal.mozIndexedDB;
+}
+
+ContactDB.prototype = {
+
+  // Cache the DB
+  db: null,
+
+  close: function close() {
+    debug("close");
+    if (this.db)
+      this.db.close();
+  },
+
+  /**
+   * Prepare the database. This may include opening the database and upgrading
+   * it to the latest schema version.
+   * 
+   * @return (via callback) a database ready for use.
+   */
+  ensureDB: function ensureDB(callback, failureCb) {
+    if (this.db) {
+      debug("ensureDB: already have a database, returning early.");
+      callback(this.db);
+      return;
+    }
+
+    let self = this;
+    debug("try to open database:" + DB_NAME + " " + DB_VERSION);
+    let request = this._indexedDB.open(DB_NAME, DB_VERSION);
+    request.onsuccess = function (event) {
+      debug("Opened database:", DB_NAME, DB_VERSION);
+      self.db = event.target.result;
+      self.db.onversionchange = function(event) {
+        debug("WARNING: DB modified from a different window.");
+      }
+      callback(self.db);
+    };
+    request.onupgradeneeded = function (event) {
+      debug("Database needs upgrade:" + DB_NAME + event.oldVersion + event.newVersion);
+      debug("Correct new database version:" + event.newVersion == DB_VERSION);
+
+      let db = event.target.result;
+      switch (event.oldVersion) {
+        case 0:
+          debug("New database");
+          self.createSchema(db);
+          break;
+
+        default:
+          debug("No idea what to do with old database version:" + event.oldVersion);
+          failureCb(event.target.errorMessage);
+          break;
+      }
+    };
+    request.onerror = function (event) {
+      debug("Failed to open database:", DB_NAME);
+      failureCb(event.target.errorMessage);
+    };
+    request.onblocked = function (event) {
+      debug("Opening database request is blocked.");
+    };
+  },
+
+  /**
+   * Create the initial database schema.
+   *
+   * The schema of records stored is as follows:
+   *
+   * {id:            "...",       // UUID
+   *  published:     Date(...),   // First published date.
+   *  updated:       Date(...),   // Last updated date.
+   *  properties:    {...}        // Object holding the ContactProperties
+   * }
+   */
+  createSchema: function createSchema(db) {
+    let objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
+
+    // Metadata indexes
+    objectStore.createIndex("published", "published", { unique: false });
+    objectStore.createIndex("updated",   "updated",   { unique: false });
+
+    // Properties indexes
+    objectStore.createIndex("nickname",   "properties.nickname",   { unique: false, multiEntry: true });
+    objectStore.createIndex("name",       "properties.name",       { unique: false, multiEntry: true });
+    objectStore.createIndex("familyName", "properties.familyName", { unique: false, multiEntry: true });
+    objectStore.createIndex("givenName",  "properties.givenName",  { unique: false, multiEntry: true });
+    objectStore.createIndex("tel",        "properties.tel",        { unique: false, multiEntry: true });
+    objectStore.createIndex("email",      "properties.email",      { unique: false, multiEntry: true });
+    objectStore.createIndex("note",       "properties.note",       { unique: false, multiEntry: true });
+
+    debug("Created object stores and indexes");
+  },
+
+  /**
+   * Start a new transaction.
+   * 
+   * @param txn_type
+   *        Type of transaction (e.g. IDBTransaction.READ_WRITE)
+   * @param callback
+   *        Function to call when the transaction is available. It will
+   *        be invoked with the transaction and the 'contacts' object store.
+   * @param successCb [optional]
+   *        Success callback to call on a successful transaction commit.
+   * @param failureCb [optional]
+   *        Error callback to call when an error is encountered.
+   */
+  newTxn: function newTxn(txn_type, callback, successCb, failureCb) {
+    this.ensureDB(function (db) {
+      debug("Starting new transaction" + txn_type);
+      let txn = db.transaction(STORE_NAME, txn_type);
+      debug("Retrieving object store", STORE_NAME);
+      let store = txn.objectStore(STORE_NAME);
+
+      txn.oncomplete = function (event) {
+        debug("Transaction complete. Returning to callback.");
+        successCb(txn.result);
+      };
+
+      txn.onabort = function (event) {
+        debug("Caught error on transaction" + event.target.errorCode);
+        switch(event.target.errorCode) {
+          case Ci.nsIIDBDatabaseException.ABORT_ERR:
+          case Ci.nsIIDBDatabaseException.CONSTRAINT_ERR:
+          case Ci.nsIIDBDatabaseException.DATA_ERR:
+          case Ci.nsIIDBDatabaseException.TRANSIENT_ERR:
+          case Ci.nsIIDBDatabaseException.NOT_ALLOWED_ERR:
+          case Ci.nsIIDBDatabaseException.NOT_FOUND_ERR:
+          case Ci.nsIIDBDatabaseException.QUOTA_ERR:
+          case Ci.nsIIDBDatabaseException.READ_ONLY_ERR:
+          case Ci.nsIIDBDatabaseException.TIMEOUT_ERR:
+          case Ci.nsIIDBDatabaseException.TRANSACTION_INACTIVE_ERR:
+          case Ci.nsIIDBDatabaseException.VERSION_ERR:
+          case Ci.nsIIDBDatabaseException.UNKNOWN_ERR:
+            failureCb("UnknownError");
+            break;
+          default:
+            debug("Unknown errorCode", event.target.errorCode);
+            failureCb("UnknownError");
+            break;
+        }
+      };
+      callback(txn, store);
+    }, failureCb);
+  },
+
+  // Todo: add searchfields. "Tom" should be a result with T, t, To, to...
+  makeImport: function makeImport(aContact) {
+    let contact = {};
+    contact.properties = {
+      name:            [],
+      honorificPrefix: [],
+      givenName:       [],
+      additionalName:  [],
+      familyName:      [],
+      honorificSuffix: [],
+      nickname:        [],
+      email:           [],
+      photo:           [],
+      url:             [],
+      category:        [],
+      adr:             [],
+      tel:             [],
+      org:             [],
+      bday:            null,
+      note:            [],
+      impp:            [],
+      anniversary:     null,
+      sex:             null,
+      genderIdentity:  null
+    };
+
+    for (let field in aContact.properties) {
+      contact.properties[field] = aContact.properties[field];
+    }
+
+    contact.updated = aContact.updated;
+    contact.published = aContact.published;
+    contact.id = aContact.id;
+
+    return contact;
+  },
+
+  // Needed to remove searchfields
+  makeExport: function makeExport(aRecord) {
+    let contact = {};
+    contact.properties = aRecord.properties;
+
+    for (let field in aRecord.properties)
+      contact.properties[field] = aRecord.properties[field];
+
+    contact.updated = aRecord.updated;
+    contact.published = aRecord.published;
+    contact.id = aRecord.id;
+    return contact;
+  },
+
+  updateRecordMetadata: function updateRecordMetadata(record) {
+    if (!record.id) {
+      Cu.reportError("Contact without ID");
+    }
+    if (!record.published) {
+      record.published = new Date();
+    }
+    record.updated = new Date();
+  },
+
+  saveContact: function saveContact(aContact, successCb, errorCb) {
+    let contact = this.makeImport(aContact);
+    this.newTxn(Ci.nsIIDBTransaction.READ_WRITE, function (txn, store) {
+      debug("Going to update" + JSON.stringify(contact));
+
+      // Look up the existing record and compare the update timestamp.
+      // If no record exists, just add the new entry.
+      let newRequest = store.get(contact.id);
+      newRequest.onsuccess = function (event) {
+        if (!event.target.result) {
+          debug("new record!")
+          this.updateRecordMetadata(contact);
+          store.put(contact);
+        } else {
+          debug("old record!")
+          if (new Date(typeof contact.updated === "undefined" ? 0 : contact.updated) < new Date(event.target.result.updated)) {
+            debug("rev check fail!");
+            txn.abort();
+            return;
+          } else {
+            debug("rev check OK");
+            contact.published = event.target.result.published;
+            contact.updated = new Date();
+            store.put(contact);
+          }
+        }
+      }.bind(this);
+    }.bind(this), successCb, errorCb);
+  },
+
+  removeContact: function removeContact(aId, aSuccessCb, aErrorCb) {
+    this.newTxn(Ci.nsIIDBTransaction.READ_WRITE, function (txn, store) {
+      debug("Going to delete" + aId);
+      store.delete(aId);
+    }, aSuccessCb, aErrorCb);
+  },
+
+  clear: function clear(aSuccessCb, aErrorCb) {
+    this.newTxn(Ci.nsIIDBTransaction.READ_WRITE, function (txn, store) {
+      debug("Going to clear all!");
+      store.clear();
+    }, aSuccessCb, aErrorCb);
+  },
+
+  /**
+   * @param successCb
+   *        Callback function to invoke with result array.
+   * @param failureCb [optional]
+   *        Callback function to invoke when there was an error.
+   * @param options [optional]
+   *        Object specifying search options. Possible attributes:
+   *        - filterBy
+   *        - filterOp
+   *        - filterValue
+   *        - count
+   *        Possibly supported in the future:
+   *        - fields
+   *        - sortBy
+   *        - sortOrder
+   *        - startIndex
+   */
+  find: function find(aSuccessCb, aFailureCb, aOptions) {
+    debug("ContactDB:find val:" + aOptions.filterValue + " by: " + aOptions.filterBy + " op: " + aOptions.filterOp + "\n");
+
+    let self = this;
+    this.newTxn(Ci.nsIIDBTransaction.READ_ONLY, function (txn, store) {
+      if (aOptions && aOptions.filterOp == "equals") {
+        self._findWithIndex(txn, store, aOptions);
+      } else if (aOptions && aOptions.filterBy) {
+        self._findWithSearch(txn, store, aOptions);
+      } else {
+        self._findAll(txn, store, aOptions);
+      }
+    }, aSuccessCb, aFailureCb);
+  },
+
+  _findWithIndex: function _findWithIndex(txn, store, options) {
+    debug("_findWithIndex: " + options.filterValue +" " + options.filterOp + " " + options.filterBy + " ");
+    let fields = options.filterBy;
+    for (let key in fields) {
+      debug("key: " + fields[key]);
+      if (!store.indexNames.contains(fields[key]) && !fields[key] == "id") {
+        debug("Key not valid!" + fields[key] + ", " + store.indexNames);
+        txn.abort();
+        return;
+      }
+    }
+
+    // lookup for all keys
+    if (options.filterBy.length == 0) {
+      debug("search in all fields!" + JSON.stringify(store.indexNames));
+      for(let myIndex = 0; myIndex < store.indexNames.length; myIndex++) {
+        fields = Array.concat(fields, store.indexNames[myIndex])
+      }
+    }
+
+    let filter_keys = fields.slice();
+    for (let key = filter_keys.shift(); key; key = filter_keys.shift()) {
+      let request;
+      if (key == "id") {
+        // store.get would return an object and not an array
+        request = store.getAll(options.filterValue);
+      } else {
+        debug("Getting index: " + key);
+        let index = store.index(key);
+        request = index.getAll(options.filterValue, opt