Merge mc->Maple
authorBenoit Girard <b56girard@gmail.com>
Tue, 13 Mar 2012 11:05:28 -0400
changeset 89367 60ebef177e6d522e6d9a0095399d4cef1da6823e
parent 89366 16e04eaadc14450814db815c269f791fbfc5657d (current diff)
parent 88944 d87ad51531b5c701fe5cefe04d58c6e11b27fb0e (diff)
child 89368 20a6f6aee48ccc4bdab7fe5395ffc387b32cbc19
push id7119
push usereakhgari@mozilla.com
push dateWed, 14 Mar 2012 17:40:57 +0000
treeherdermozilla-inbound@10d7baa4aff0 [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 mc->Maple
accessible/tests/mochitest/test_nsIAccessNode_utils.html
browser/app/profile/firefox.js
browser/base/content/newtab/toolbar.js
browser/base/content/utilityOverlay.js
browser/devtools/highlighter/inspector.jsm
browser/devtools/styleinspector/CssLogic.jsm
browser/devtools/styleinspector/CssRuleView.jsm
browser/devtools/styleinspector/StyleInspector.jsm
browser/devtools/styleinspector/test/Makefile.in
browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
browser/themes/gnomestripe/devtools/csshtmltree.css
browser/themes/gnomestripe/jar.mn
browser/themes/gnomestripe/newtab/strip.png
browser/themes/gnomestripe/newtab/toolbar.png
browser/themes/pinstripe/devtools/csshtmltree.css
browser/themes/pinstripe/jar.mn
browser/themes/pinstripe/newtab/strip.png
browser/themes/pinstripe/newtab/toolbar.png
browser/themes/winstripe/devtools/csshtmltree.css
browser/themes/winstripe/jar.mn
browser/themes/winstripe/newtab/strip.png
browser/themes/winstripe/newtab/toolbar.png
configure.in
content/base/public/nsINode.h
content/base/src/nsAttrValue.cpp
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/base/src/nsGenericElement.cpp
content/base/src/nsMappedAttributes.cpp
dom/base/Navigator.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/plugins/base/nsJSNPRuntime.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/base/nsPluginInstanceOwner.cpp
embedding/android/GeckoAppShell.java
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/layers/ImageLayers.h
gfx/layers/basic/BasicLayers.cpp
gfx/layers/d3d10/ImageLayerD3D10.cpp
gfx/layers/d3d9/ImageLayerD3D9.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jsgc.cpp
js/src/shell/js.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/XPCJSRuntime.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDocumentViewer.cpp
layout/base/nsPresShell.cpp
layout/forms/nsFileControlFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsObjectFrame.cpp
layout/style/nsCSSRuleProcessor.cpp
mobile/android/app/mobile.js
mobile/android/base/AboutHomeContent.java
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/base/resources/layout-v11/awesomebar.xml
mobile/android/chrome/content/browser.js
modules/libpref/src/init/all.js
mozglue/android/APKOpen.cpp
toolkit/components/autocomplete/nsAutoCompleteController.cpp
toolkit/components/autocomplete/nsAutoCompleteController.h
toolkit/components/telemetry/TelemetryPing.js
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/nsAppShell.cpp
--- a/accessible/public/nsIAccessible.idl
+++ b/accessible/public/nsIAccessible.idl
@@ -54,17 +54,17 @@ interface nsIAccessibleRelation;
  * accessibility APIs like MSAA and ATK. Contains the sum of what's needed
  * to support IAccessible as well as ATK's generic accessibility objects.
  * Can also be used by in-process accessibility clients to get information
  * about objects in the accessible tree. The accessible tree is a subset of 
  * nodes in the DOM tree -- such as documents, focusable elements and text.
  * Mozilla creates the implementations of nsIAccessible on demand.
  * See http://www.mozilla.org/projects/ui/accessibility for more information.
  */
-[scriptable, uuid(3126544c-826c-4694-a2ed-67bfe56a1f37)]
+[scriptable, uuid(e7c44e0d-736e-4ead-afee-b51f4b574020)]
 interface nsIAccessible : nsISupports
 {
   /**
    * Parent node in accessible tree.
    */
   readonly attribute nsIAccessible parent;
 
   /**
@@ -106,36 +106,16 @@ interface nsIAccessible : nsISupports
   /**
    * The innerHTML for the HTML element associated with this accessible if applicable.
    * This is a text string of all the markup inside the DOM
    * node, not including the start and end tag for the node.
    */
   readonly attribute DOMString innerHTML;
 
   /**
-   * Retrieve the computed style value for this DOM node, if it is a DOM element.
-   * Note: the meanings of width, height and other size measurements depend
-   * on the version of CSS being used. Therefore, for bounds information, 
-   * it is better to use nsIAccessible::accGetBounds.
-   *
-   * @param pseudoElt [in] The pseudo element to retrieve style for, or NULL
-   *                  for general computed style information for this node.
-   * @param propertyName [in] Retrieve the computed style value for this property name,
-   *                     for example "border-bottom".
-   */
-  DOMString getComputedStyleValue(in DOMString pseudoElt, in DOMString propertyName);
-
-  /**
-   * The method is similar to getComputedStyleValue() excepting that this one
-   * returns nsIDOMCSSPrimitiveValue.
-   */
-  nsIDOMCSSPrimitiveValue getComputedStyleCSSValue(in DOMString pseudoElt,
-                                                   in DOMString propertyName);
-
-  /**
    * The DOM node this nsIAccessible is associated with.
    */
   readonly attribute nsIDOMNode DOMNode;
 
   /**
    * The document accessible that this access node resides in.
    */
   readonly attribute nsIAccessibleDocument document;
--- a/accessible/src/base/AccGroupInfo.h
+++ b/accessible/src/base/AccGroupInfo.h
@@ -61,16 +61,18 @@ public:
   {
     mozilla::a11y::role role = aAccessible->Role();
     if (role != mozilla::a11y::roles::ROW &&
         role != mozilla::a11y::roles::GRID_CELL &&
         role != mozilla::a11y::roles::OUTLINEITEM &&
         role != mozilla::a11y::roles::OPTION &&
         role != mozilla::a11y::roles::LISTITEM &&
         role != mozilla::a11y::roles::MENUITEM &&
+        role != mozilla::a11y::roles::COMBOBOX_OPTION &&
+        role != mozilla::a11y::roles::PARENT_MENUITEM &&
         role != mozilla::a11y::roles::CHECK_MENU_ITEM &&
         role != mozilla::a11y::roles::RADIO_MENU_ITEM &&
         role != mozilla::a11y::roles::RADIOBUTTON &&
         role != mozilla::a11y::roles::PAGETAB)
       return nsnull;
 
     AccGroupInfo* info = new AccGroupInfo(aAccessible, BaseRole(role));
     return info;
@@ -78,16 +80,17 @@ public:
 
 private:
   AccGroupInfo(const AccGroupInfo&);
   AccGroupInfo& operator =(const AccGroupInfo&);
 
   static mozilla::a11y::role BaseRole(mozilla::a11y::role aRole)
   {
     if (aRole == mozilla::a11y::roles::CHECK_MENU_ITEM ||
+        aRole == mozilla::a11y::roles::PARENT_MENUITEM ||
         aRole == mozilla::a11y::roles::RADIO_MENU_ITEM)
       return mozilla::a11y::roles::MENUITEM;
     return aRole;
   }
 
   /**
    * Return true if the given parent role is conceptual parent of the given
    * role.
--- a/accessible/src/base/TextAttrs.cpp
+++ b/accessible/src/base/TextAttrs.cpp
@@ -47,42 +47,16 @@
 #include "gfxUserFontSet.h"
 #include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
-// Constants and structures
-
-/**
- * Item of the gCSSTextAttrsMap map.
- */
-struct nsCSSTextAttrMapItem
-{
-  const char* mCSSName;
-  const char* mCSSValue;
-  nsIAtom** mAttrName;
-  const char* mAttrValue;
-};
-
-/**
- * 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
-  { "vertical-align",    kAnyValue,       &nsGkAtoms::textPosition,          kCopyValue }
-};
-
-////////////////////////////////////////////////////////////////////////////////
 // TextAttrsMgr
 ////////////////////////////////////////////////////////////////////////////////
 
 void
 TextAttrsMgr::GetAttributes(nsIPersistentProperties* aAttributes,
                             PRInt32* aStartHTOffset,
                             PRInt32* aEndHTOffset)
 {
@@ -134,88 +108,87 @@ TextAttrsMgr::GetAttributes(nsIPersisten
   nsIContent *offsetNode = nsnull, *offsetElm = nsnull;
   nsIFrame *frame = nsnull;
   if (mOffsetAcc) {
     offsetNode = mOffsetAcc->GetContent();
     offsetElm = nsCoreUtils::GetDOMElementFor(offsetNode);
     frame = offsetElm->GetPrimaryFrame();
   }
 
-  nsTArray<TextAttr*> textAttrArray(9);
-
   // "language" text attribute
   LangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
-  textAttrArray.AppendElement(&langTextAttr);
-
-  // "text-position" text attribute
-  CSSTextAttr posTextAttr(0, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&posTextAttr);
 
   // "background-color" text attribute
   BGColorTextAttr bgColorTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&bgColorTextAttr);
 
   // "color" text attribute
   ColorTextAttr colorTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&colorTextAttr);
 
   // "font-family" text attribute
   FontFamilyTextAttr fontFamilyTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&fontFamilyTextAttr);
 
   // "font-size" text attribute
   FontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&fontSizeTextAttr);
 
   // "font-style" text attribute
   FontStyleTextAttr fontStyleTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&fontStyleTextAttr);
 
   // "font-weight" text attribute
   FontWeightTextAttr fontWeightTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&fontWeightTextAttr);
 
   // "text-underline(line-through)-style(color)" text attributes
   TextDecorTextAttr textDecorTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&textDecorTextAttr);
+
+  // "text-position" text attribute
+  TextPosTextAttr textPosTextAttr(rootFrame, frame);
+
+  TextAttr* attrArray[] =
+  {
+    &langTextAttr,
+    &bgColorTextAttr,
+    &colorTextAttr,
+    &fontFamilyTextAttr,
+    &fontSizeTextAttr,
+    &fontStyleTextAttr,
+    &fontWeightTextAttr,
+    &textDecorTextAttr,
+    &textPosTextAttr
+  };
 
   // Expose text attributes if applicable.
   if (aAttributes) {
-    PRUint32 len = textAttrArray.Length();
-    for (PRUint32 idx = 0; idx < len; idx++)
-      textAttrArray[idx]->Expose(aAttributes, mIncludeDefAttrs);
+    for (PRUint32 idx = 0; idx < ArrayLength(attrArray); idx++)
+      attrArray[idx]->Expose(aAttributes, mIncludeDefAttrs);
   }
 
   // Expose text attributes range where they are applied if applicable.
   if (mOffsetAcc)
-    GetRange(textAttrArray, aStartHTOffset, aEndHTOffset);
+    GetRange(attrArray, ArrayLength(attrArray), aStartHTOffset, aEndHTOffset);
 }
 
 void
-TextAttrsMgr::GetRange(const nsTArray<TextAttr*>& aTextAttrArray,
+TextAttrsMgr::GetRange(TextAttr* aAttrArray[], PRUint32 aAttrArrayLen,
                        PRInt32* aStartHTOffset, PRInt32* aEndHTOffset)
 {
-  PRUint32 attrLen = aTextAttrArray.Length();
-
   // Navigate backward from anchor accessible to find start offset.
   for (PRInt32 childIdx = mOffsetAccIdx - 1; childIdx >= 0; childIdx--) {
     nsAccessible *currAcc = mHyperTextAcc->GetChildAt(childIdx);
 
     // Stop on embedded accessible since embedded accessibles are combined into
     // own range.
     if (nsAccUtils::IsEmbeddedObject(currAcc))
       break;
 
     nsIContent* currElm = nsCoreUtils::GetDOMElementFor(currAcc->GetContent());
     if (!currElm)
       return;
 
     bool offsetFound = false;
-    for (PRUint32 attrIdx = 0; attrIdx < attrLen; attrIdx++) {
-      TextAttr* textAttr = aTextAttrArray[attrIdx];
+    for (PRUint32 attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
+      TextAttr* textAttr = aAttrArray[attrIdx];
       if (!textAttr->Equal(currElm)) {
         offsetFound = true;
         break;
       }
     }
 
     if (offsetFound)
       break;
@@ -230,18 +203,18 @@ TextAttrsMgr::GetRange(const nsTArray<Te
     if (nsAccUtils::IsEmbeddedObject(currAcc))
       break;
 
     nsIContent* currElm = nsCoreUtils::GetDOMElementFor(currAcc->GetContent());
     if (!currElm)
       return;
 
     bool offsetFound = false;
-    for (PRUint32 attrIdx = 0; attrIdx < attrLen; attrIdx++) {
-      TextAttr* textAttr = aTextAttrArray[attrIdx];
+    for (PRUint32 attrIdx = 0; attrIdx < aAttrArrayLen; attrIdx++) {
+      TextAttr* textAttr = aAttrArray[attrIdx];
 
       // Alter the end offset when text attribute changes its value and stop
       // the search.
       if (!textAttr->Equal(currElm)) {
         offsetFound = true;
         break;
       }
     }
@@ -289,70 +262,16 @@ TextAttrsMgr::LangTextAttr::
   GetLang(nsIContent* aElm, nsAString& aLang)
 {
   nsCoreUtils::GetLanguageFor(aElm, mRootContent, aLang);
   return !aLang.IsEmpty();
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
-// CSSTextAttr
-////////////////////////////////////////////////////////////////////////////////
-
-TextAttrsMgr::CSSTextAttr::
-  CSSTextAttr(PRUint32 aIndex, nsIContent* aRootElm, nsIContent* aElm) :
-  TTextAttr<nsString>(!aElm), mIndex(aIndex)
-{
-  mIsRootDefined = GetValueFor(aRootElm, &mRootNativeValue);
-
-  if (aElm)
-    mIsDefined = GetValueFor(aElm, &mNativeValue);
-}
-
-bool
-TextAttrsMgr::CSSTextAttr::
-  GetValueFor(nsIContent* aElm, nsString* aValue)
-{
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl =
-    nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm);
-  if (!currStyleDecl)
-    return false;
-
-  NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
-
-  nsresult rv = currStyleDecl->GetPropertyValue(cssName, *aValue);
-  if (NS_FAILED(rv))
-    return true;
-
-  const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
-  if (cssValue != kAnyValue && !aValue->EqualsASCII(cssValue))
-    return false;
-
-  return true;
-}
-
-void
-TextAttrsMgr::CSSTextAttr::
-  ExposeValue(nsIPersistentProperties* aAttributes, const nsString& aValue)
-{
-  const char* attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
-  if (attrValue != kCopyValue) {
-    nsAutoString formattedValue;
-    AppendASCIItoUTF16(attrValue, formattedValue);
-    nsAccUtils::SetAccAttr(aAttributes, *gCSSTextAttrsMap[mIndex].mAttrName,
-                           formattedValue);
-    return;
-  }
-
-  nsAccUtils::SetAccAttr(aAttributes, *gCSSTextAttrsMap[mIndex].mAttrName,
-                         aValue);
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
 // BGColorTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 TextAttrsMgr::BGColorTextAttr::
   BGColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
   TTextAttr<nscolor>(!aFrame), mRootFrame(aRootFrame)
 {
   mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
@@ -737,8 +656,109 @@ TextAttrsMgr::TextDecorTextAttr::
                            formattedStyle);
 
     nsAutoString formattedColor;
     StyleInfo::FormatColor(aValue.Color(), formattedColor);
     nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textLineThroughColor,
                            formattedColor);
   }
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// TextPosTextAttr
+////////////////////////////////////////////////////////////////////////////////
+
+TextAttrsMgr::TextPosTextAttr::
+  TextPosTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  TTextAttr<TextPosValue>(!aFrame)
+{
+  mRootNativeValue = GetTextPosValue(aRootFrame);
+  mIsRootDefined = mRootNativeValue != eTextPosNone;
+
+  if (aFrame) {
+    mNativeValue = GetTextPosValue(aFrame);
+    mIsDefined = mNativeValue != eTextPosNone;
+  }
+}
+
+bool
+TextAttrsMgr::TextPosTextAttr::
+  GetValueFor(nsIContent* aContent, TextPosValue* aValue)
+{
+  nsIFrame* frame = aContent->GetPrimaryFrame();
+  if (frame) {
+    *aValue = GetTextPosValue(frame);
+    return *aValue != eTextPosNone;
+  }
+
+  return false;
+}
+
+void
+TextAttrsMgr::TextPosTextAttr::
+  ExposeValue(nsIPersistentProperties* aAttributes, const TextPosValue& aValue)
+{
+  switch (aValue) {
+    case eTextPosBaseline:
+      nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textPosition,
+                             NS_LITERAL_STRING("baseline"));
+      break;
+
+    case eTextPosSub:
+      nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textPosition,
+                             NS_LITERAL_STRING("sub"));
+      break;
+
+    case eTextPosSuper:
+      nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::textPosition,
+                             NS_LITERAL_STRING("super"));
+      break;
+  }
+}
+
+TextAttrsMgr::TextPosValue
+TextAttrsMgr::TextPosTextAttr::
+  GetTextPosValue(nsIFrame* aFrame) const
+{
+  const nsStyleCoord& styleCoord = aFrame->GetStyleTextReset()->mVerticalAlign;
+  switch (styleCoord.GetUnit()) {
+    case eStyleUnit_Enumerated:
+      switch (styleCoord.GetIntValue()) {
+        case NS_STYLE_VERTICAL_ALIGN_BASELINE:
+          return eTextPosBaseline;
+        case NS_STYLE_VERTICAL_ALIGN_SUB:
+          return eTextPosSub;
+        case NS_STYLE_VERTICAL_ALIGN_SUPER:
+          return eTextPosSuper;
+
+        // No good guess for these:
+        //   NS_STYLE_VERTICAL_ALIGN_TOP
+        //   NS_STYLE_VERTICAL_ALIGN_TEXT_TOP
+        //   NS_STYLE_VERTICAL_ALIGN_MIDDLE
+        //   NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM
+        //   NS_STYLE_VERTICAL_ALIGN_BOTTOM
+        //   NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE
+        // Do not expose value of text-position attribute.
+
+        default:
+          break;
+      }
+      return eTextPosNone;
+
+    case eStyleUnit_Percent:
+    {
+      float percentValue = styleCoord.GetPercentValue();
+      return percentValue > 0 ?
+        eTextPosSuper :
+        (percentValue < 0 ? eTextPosSub : eTextPosBaseline);
+    }
+
+    case eStyleUnit_Coord:
+    {
+       nscoord coordValue = styleCoord.GetCoordValue();
+       return coordValue > 0 ?
+         eTextPosSuper :
+         (coordValue < 0 ? eTextPosSub : eTextPosBaseline);
+    }
+  }
+
+  return eTextPosNone;
+}
--- a/accessible/src/base/TextAttrs.h
+++ b/accessible/src/base/TextAttrs.h
@@ -102,21 +102,22 @@ public:
 
 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 aAttrArrayLen   [in] text attributes array length
    * @param aStartHTOffset  [in, out] the start offset
    * @param aEndHTOffset    [in, out] the end offset
    */
   class TextAttr;
-  void GetRange(const nsTArray<TextAttr*>& aTextAttrArray,
+  void GetRange(TextAttr* aAttrArray[], PRUint32 aAttrArrayLen,
                 PRInt32* aStartHTOffset, PRInt32* aEndHTOffset);
 
 private:
   nsHyperTextAccessible* mHyperTextAcc;
 
   bool mIncludeDefAttrs;
 
   nsAccessible* mOffsetAcc;
@@ -152,17 +153,17 @@ protected:
    * Base class to work with text attributes. See derived classes below.
    */
   template<class T>
   class TTextAttr : public TextAttr
   {
   public:
     TTextAttr(bool aGetRootValue) : mGetRootValue(aGetRootValue) {}
 
-    // ITextAttr
+    // TextAttr
     virtual void Expose(nsIPersistentProperties* aAttributes,
                         bool aIncludeDefAttrValue)
     {
       if (mGetRootValue) {
         if (mIsRootDefined)
           ExposeValue(aAttributes, mRootNativeValue);
         return;
       }
@@ -238,37 +239,16 @@ protected:
 
   private:
     bool GetLang(nsIContent* aElm, nsAString& aLang);
     nsCOMPtr<nsIContent> mRootContent;
   };
 
 
   /**
-   * Class is used for the work with CSS based text attributes.
-   */
-  class CSSTextAttr : public TTextAttr<nsString>
-  {
-  public:
-    CSSTextAttr(PRUint32 aIndex, nsIContent* aRootElm, nsIContent* aElm);
-    virtual ~CSSTextAttr() { }
-
-  protected:
-
-    // TextAttr
-    virtual bool GetValueFor(nsIContent* aElm, nsString* aValue);
-    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
-                             const nsString& aValue);
-
-  private:
-    PRInt32 mIndex;
-  };
-
-
-  /**
    * Class is used for the work with 'background-color' text attribute.
    */
   class BGColorTextAttr : public TTextAttr<nscolor>
   {
   public:
     BGColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
     virtual ~BGColorTextAttr() { }
 
@@ -430,14 +410,42 @@ protected:
   protected:
 
     // TextAttr
     virtual bool GetValueFor(nsIContent* aElm, TextDecorValue* aValue);
     virtual void ExposeValue(nsIPersistentProperties* aAttributes,
                              const TextDecorValue& aValue);
   };
 
+  /**
+   * Class is used for the work with "text-position" text attribute.
+   */
+
+  enum TextPosValue {
+    eTextPosNone = 0,
+    eTextPosBaseline,
+    eTextPosSub,
+    eTextPosSuper
+  };
+
+  class TextPosTextAttr : public TTextAttr<TextPosValue>
+  {
+  public:
+    TextPosTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+    virtual ~TextPosTextAttr() { }
+
+  protected:
+
+    // TextAttr
+    virtual bool GetValueFor(nsIContent* aElm, TextPosValue* aValue);
+    virtual void ExposeValue(nsIPersistentProperties* aAttributes,
+                             const TextPosValue& aValue);
+
+  private:
+    TextPosValue GetTextPosValue(nsIFrame* aFrame) const;
+  };
+
 }; // TextAttrMgr
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/src/base/nsAccUtils.cpp
+++ b/accessible/src/base/nsAccUtils.cpp
@@ -170,80 +170,16 @@ nsAccUtils::GetPositionAndSizeForXULSele
       if (index < static_cast<PRUint32>(indexOf))
         (*aPosInSet)--;
     }
   }
 
   (*aPosInSet)++; // group position is 1-index based.
 }
 
-void
-nsAccUtils::GetPositionAndSizeForXULContainerItem(nsIContent *aContent,
-                                                  PRInt32 *aPosInSet,
-                                                  PRInt32 *aSetSize)
-{
-  nsCOMPtr<nsIDOMXULContainerItemElement> item(do_QueryInterface(aContent));
-  if (!item)
-    return;
-
-  nsCOMPtr<nsIDOMXULContainerElement> container;
-  item->GetParentContainer(getter_AddRefs(container));
-  if (!container)
-    return;
-
-  // Get item count.
-  PRUint32 itemsCount = 0;
-  container->GetItemCount(&itemsCount);
-
-  // Get item index.
-  PRInt32 indexOf = 0;
-  container->GetIndexOfItem(item, &indexOf);
-
-  // Calculate set size and position in the set.
-  *aSetSize = 0, *aPosInSet = 0;
-  for (PRInt32 index = indexOf; index >= 0; index--) {
-    nsCOMPtr<nsIDOMXULElement> item;
-    container->GetItemAtIndex(index, getter_AddRefs(item));
-    nsCOMPtr<nsINode> itemNode(do_QueryInterface(item));
-
-    nsAccessible* itemAcc = itemNode ?
-      GetAccService()->GetAccessible(itemNode, nsnull) : nsnull;
-
-    if (itemAcc) {
-      PRUint32 itemRole = Role(itemAcc);
-      if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
-        break; // We reached the beginning of our group.
-
-      if (!(itemAcc->State() & states::INVISIBLE)) {
-        (*aSetSize)++;
-        (*aPosInSet)++;
-      }
-    }
-  }
-
-  for (PRInt32 index = indexOf + 1; index < static_cast<PRInt32>(itemsCount);
-       index++) {
-    nsCOMPtr<nsIDOMXULElement> item;
-    container->GetItemAtIndex(index, getter_AddRefs(item));
-    nsCOMPtr<nsINode> itemNode(do_QueryInterface(item));
-
-    nsAccessible* itemAcc =
-      itemNode ? GetAccService()->GetAccessible(itemNode, nsnull) : nsnull;
-
-    if (itemAcc) {
-      PRUint32 itemRole = Role(itemAcc);
-      if (itemRole == nsIAccessibleRole::ROLE_SEPARATOR)
-        break; // We reached the end of our group.
-
-      if (!(itemAcc->State() & states::INVISIBLE))
-        (*aSetSize)++;
-    }
-  }
-}
-
 PRInt32
 nsAccUtils::GetLevelForXULContainerItem(nsIContent *aContent)
 {
   nsCOMPtr<nsIDOMXULContainerItemElement> item(do_QueryInterface(aContent));
   if (!item)
     return 0;
 
   nsCOMPtr<nsIDOMXULContainerElement> container;
--- a/accessible/src/base/nsAccUtils.h
+++ b/accessible/src/base/nsAccUtils.h
@@ -111,24 +111,16 @@ public:
    * Compute position in group (posinset) and group size (setsize) for
    * nsIDOMXULSelectControlItemElement node.
    */
   static void GetPositionAndSizeForXULSelectControlItem(nsIContent *aContent,
                                                         PRInt32 *aPosInSet,
                                                         PRInt32 *aSetSize);
 
   /**
-   * Compute group position and group size (posinset and setsize) for
-   * nsIDOMXULContainerItemElement node.
-   */
-  static void GetPositionAndSizeForXULContainerItem(nsIContent *aContent,
-                                                    PRInt32 *aPosInSet,
-                                                    PRInt32 *aSetSize);
-
-  /**
    * Compute group level for nsIDOMXULContainerItemElement node.
    */
   static PRInt32 GetLevelForXULContainerItem(nsIContent *aContent);
 
   /**
    * Set container-foo live region attributes for the given node.
    *
    * @param aAttributes    where to store the attributes
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -227,52 +227,16 @@ nsAccessible::~nsAccessible()
 
 void
 nsAccessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
 {
   mRoleMapEntry = aRoleMapEntry;
 }
 
 NS_IMETHODIMP
-nsAccessible::GetComputedStyleValue(const nsAString& aPseudoElt,
-                                    const nsAString& aPropertyName,
-                                    nsAString& aValue)
-{
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl =
-    nsCoreUtils::GetComputedStyleDeclaration(aPseudoElt, mContent);
-  NS_ENSURE_TRUE(styleDecl, NS_ERROR_FAILURE);
-
-  return styleDecl->GetPropertyValue(aPropertyName, aValue);
-}
-
-NS_IMETHODIMP
-nsAccessible::GetComputedStyleCSSValue(const nsAString& aPseudoElt,
-                                       const nsAString& aPropertyName,
-                                       nsIDOMCSSPrimitiveValue **aCSSValue) {
-  NS_ENSURE_ARG_POINTER(aCSSValue);
-  *aCSSValue = nsnull;
-
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl =
-    nsCoreUtils::GetComputedStyleDeclaration(aPseudoElt, mContent);
-  NS_ENSURE_STATE(styleDecl);
-
-  nsCOMPtr<nsIDOMCSSValue> cssValue;
-  styleDecl->GetPropertyCSSValue(aPropertyName, getter_AddRefs(cssValue));
-  NS_ENSURE_TRUE(cssValue, NS_ERROR_FAILURE);
-
-  return CallQueryInterface(cssValue, aCSSValue);
-}
-
-NS_IMETHODIMP
 nsAccessible::GetDocument(nsIAccessibleDocument **aDocument)
 {
   NS_ENSURE_ARG_POINTER(aDocument);
 
   NS_IF_ADDREF(*aDocument = Document());
   return NS_OK;
 }
 
--- a/accessible/src/base/nsApplicationAccessible.cpp
+++ b/accessible/src/base/nsApplicationAccessible.cpp
@@ -463,32 +463,14 @@ nsApplicationAccessible::ScrollTo(PRUint
 NS_IMETHODIMP
 nsApplicationAccessible::ScrollToPoint(PRUint32 aCoordinateType,
                                        PRInt32 aX, PRInt32 aY)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsApplicationAccessible::GetComputedStyleValue(const nsAString &aPseudoElt,
-                                               const nsAString &aPropertyName,
-                                               nsAString &aValue)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsApplicationAccessible::GetComputedStyleCSSValue(const nsAString &aPseudoElt,
-                                                  const nsAString &aPropertyName,
-                                                  nsIDOMCSSPrimitiveValue **aCSSPrimitiveValue)
-{
-  NS_ENSURE_ARG_POINTER(aCSSPrimitiveValue);
-  *aCSSPrimitiveValue = nsnull;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsApplicationAccessible::GetLanguage(nsAString &aLanguage)
 {
   aLanguage.Truncate();
   return NS_OK;
 }
 
--- a/accessible/src/base/nsApplicationAccessible.h
+++ b/accessible/src/base/nsApplicationAccessible.h
@@ -71,22 +71,16 @@ public:
 
   // nsIAccessible
   NS_SCRIPTABLE NS_IMETHOD GetDOMNode(nsIDOMNode** aDOMNode);
   NS_SCRIPTABLE NS_IMETHOD GetDocument(nsIAccessibleDocument** aDocument);
   NS_SCRIPTABLE NS_IMETHOD GetRootDocument(nsIAccessibleDocument** aRootDocument);
   NS_SCRIPTABLE NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
   NS_SCRIPTABLE NS_IMETHOD ScrollTo(PRUint32 aScrollType);
   NS_SCRIPTABLE NS_IMETHOD ScrollToPoint(PRUint32 aCoordinateType, PRInt32 aX, PRInt32 aY);
-  NS_SCRIPTABLE NS_IMETHOD GetComputedStyleValue(const nsAString& aPseudoElt,
-                                                 const nsAString& aPropertyName,
-                                                 nsAString& aValue NS_OUTPARAM);
-  NS_SCRIPTABLE NS_IMETHOD GetComputedStyleCSSValue(const nsAString& aPseudoElt,
-                                                    const nsAString& aPropertyName,
-                                                    nsIDOMCSSPrimitiveValue** aValue NS_OUTPARAM);
   NS_SCRIPTABLE NS_IMETHOD GetLanguage(nsAString& aLanguage);
   NS_IMETHOD GetParent(nsIAccessible **aParent);
   NS_IMETHOD GetNextSibling(nsIAccessible **aNextSibling);
   NS_IMETHOD GetPreviousSibling(nsIAccessible **aPreviousSibling);
   NS_IMETHOD GetName(nsAString &aName);
   NS_IMETHOD GetValue(nsAString &aValue);
   NS_IMETHOD GetAttributes(nsIPersistentProperties **aAttributes);
   NS_IMETHOD GroupPosition(PRInt32 *aGroupLevel, PRInt32 *aSimilarItemsInGroup,
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -565,36 +565,16 @@ nsCoreUtils::GetLanguageFor(nsIContent *
   aLanguage.Truncate();
 
   nsIContent *walkUp = aContent;
   while (walkUp && walkUp != aRootContent &&
          !walkUp->GetAttr(kNameSpaceID_None, nsGkAtoms::lang, aLanguage))
     walkUp = walkUp->GetParent();
 }
 
-already_AddRefed<nsIDOMCSSStyleDeclaration>
-nsCoreUtils::GetComputedStyleDeclaration(const nsAString& aPseudoElt,
-                                         nsIContent *aContent)
-{
-  nsIContent* content = GetDOMElementFor(aContent);
-  if (!content)
-    return nsnull;
-
-  // Returns number of items in style declaration
-  nsCOMPtr<nsIDOMWindow> window =
-    do_QueryInterface(content->OwnerDoc()->GetWindow());
-  if (!window)
-    return nsnull;
-
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
-  nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(content));
-  window->GetComputedStyle(domElement, aPseudoElt, getter_AddRefs(cssDecl));
-  return cssDecl.forget();
-}
-
 already_AddRefed<nsIBoxObject>
 nsCoreUtils::GetTreeBodyBoxObject(nsITreeBoxObject *aTreeBoxObj)
 {
   nsCOMPtr<nsIDOMElement> tcElm;
   aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm));
   nsCOMPtr<nsIDOMXULElement> tcXULElm(do_QueryInterface(tcElm));
   if (!tcXULElm)
     return nsnull;
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -284,23 +284,16 @@ public:
    * @param aContent     [in] the given node
    * @param aRootContent [in] container of the given node
    * @param aLanguage    [out] language
    */
   static void GetLanguageFor(nsIContent *aContent, nsIContent *aRootContent,
                              nsAString& aLanguage);
 
   /**
-   * Return computed styles declaration for the given node.
-   */
-  static already_AddRefed<nsIDOMCSSStyleDeclaration>
-    GetComputedStyleDeclaration(const nsAString& aPseudoElt,
-                                nsIContent *aContent);
-
-  /**
    * Return box object for XUL treechildren element by tree box object.
    */
   static already_AddRefed<nsIBoxObject>
     GetTreeBodyBoxObject(nsITreeBoxObject *aTreeBoxObj);
 
   /**
    * Return tree box object from any levels DOMNode under the XUL tree.
    */
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -1436,19 +1436,36 @@ nsHTMLTableAccessible::IsProbablyForLayo
     }
 
     if (childElm->Tag() == nsGkAtoms::tbody) {
       for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
            rowElm = rowElm->GetNextSibling()) {
         if (rowElm->IsHTML() && rowElm->Tag() == nsGkAtoms::tr) {
           for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
                cellElm = cellElm->GetNextSibling()) {
-            if (cellElm->IsHTML() && cellElm->Tag() == nsGkAtoms::th) {
-              RETURN_LAYOUT_ANSWER(false,
-                                   "Has th -- legitimate table structures");
+            if (cellElm->IsHTML()) {
+              
+              if (cellElm->NodeInfo()->Equals(nsGkAtoms::th)) {
+                RETURN_LAYOUT_ANSWER(false,
+                                     "Has th -- legitimate table structures");
+              }
+
+              if (cellElm->HasAttr(kNameSpaceID_None, nsGkAtoms::headers) ||
+                  cellElm->HasAttr(kNameSpaceID_None, nsGkAtoms::scope) ||
+                  cellElm->HasAttr(kNameSpaceID_None, nsGkAtoms::abbr)) {
+                RETURN_LAYOUT_ANSWER(false,
+                                     "Has headers, scope, or abbr attribute -- legitimate table structures");
+              }
+
+              nsAccessible* cell = mDoc->GetAccessible(cellElm);
+              if (cell && cell->GetChildCount() == 1 &&
+                  cell->FirstChild()->IsAbbreviation()) {
+                RETURN_LAYOUT_ANSWER(false,
+                                     "has abbr -- legitimate table structures");
+              }
             }
           }
         }
       }
     }
   }
 
   if (HasDescendant(NS_LITERAL_STRING("table"))) {
--- a/accessible/src/msaa/CAccessibleComponent.cpp
+++ b/accessible/src/msaa/CAccessibleComponent.cpp
@@ -38,16 +38,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "CAccessibleComponent.h"
 
 #include "AccessibleComponent_i.c"
 
 #include "nsAccessible.h"
+#include "nsCoreUtils.h"
+#include "nsWinUtils.h"
 #include "States.h"
 
 #include "nsString.h"
 
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMNSRGBAColor.h"
 
 using namespace mozilla::a11y;
@@ -151,27 +153,33 @@ CAccessibleComponent::get_background(IA2
 HRESULT
 CAccessibleComponent::GetARGBValueFromCSSProperty(const nsAString& aPropName,
                                                   IA2Color *aColorValue)
 {
 __try {
   *aColorValue = 0;
 
   nsRefPtr<nsAccessible> acc(do_QueryObject(this));
-  if (!acc)
+  if (acc->IsDefunct())
     return E_FAIL;
 
-  nsCOMPtr<nsIDOMCSSPrimitiveValue> cssValue;
-  nsresult rv = acc->GetComputedStyleCSSValue(EmptyString(), aPropName,
-                                              getter_AddRefs(cssValue));
-  if (NS_FAILED(rv) || !cssValue)
-    return GetHRESULT(rv);
+  nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl =
+    nsWinUtils::GetComputedStyleDeclaration(acc->GetContent());
+  NS_ENSURE_STATE(styleDecl);
+
+  nsCOMPtr<nsIDOMCSSValue> cssGenericValue;
+  styleDecl->GetPropertyCSSValue(aPropName, getter_AddRefs(cssGenericValue));
+
+  nsCOMPtr<nsIDOMCSSPrimitiveValue> cssValue =
+    do_QueryInterface(cssGenericValue);
+  if (!cssValue)
+    return E_FAIL;
 
   nsCOMPtr<nsIDOMRGBColor> rgbColor;
-  rv = cssValue->GetRGBColorValue(getter_AddRefs(rgbColor));
+  nsresult rv = cssValue->GetRGBColorValue(getter_AddRefs(rgbColor));
   if (NS_FAILED(rv) || !rgbColor)
     return GetHRESULT(rv);
 
   nsCOMPtr<nsIDOMNSRGBAColor> rgbaColor(do_QueryInterface(rgbColor));
   if (!rgbaColor)
     return GetHRESULT(rv);
 
   // get alpha
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp
+++ b/accessible/src/msaa/nsAccessNodeWrap.cpp
@@ -334,17 +334,17 @@ STDMETHODIMP nsAccessNodeWrap::get_compu
 {
 __try{
   *aNumStyleProperties = 0;
 
   if (IsDefunct() || IsDocumentNode())
     return E_FAIL;
 
   nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl =
-    nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), mContent);
+    nsWinUtils::GetComputedStyleDeclaration(mContent);
   NS_ENSURE_TRUE(cssDecl, E_FAIL);
 
   PRUint32 length;
   cssDecl->GetLength(&length);
 
   PRUint32 index, realIndex;
   for (index = realIndex = 0; index < length && realIndex < aMaxStyleProperties; index ++) {
     nsAutoString property, value;
@@ -369,17 +369,17 @@ STDMETHODIMP nsAccessNodeWrap::get_compu
     /* [length_is][size_is][in] */ BSTR __RPC_FAR *aStyleProperties,
     /* [length_is][size_is][out] */ BSTR __RPC_FAR *aStyleValues)
 {
 __try {
   if (IsDefunct() || IsDocumentNode())
     return E_FAIL;
  
   nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl =
-    nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), mContent);
+    nsWinUtils::GetComputedStyleDeclaration(mContent);
   NS_ENSURE_TRUE(cssDecl, E_FAIL);
 
   PRUint32 index;
   for (index = 0; index < aNumStyleProperties; index ++) {
     nsAutoString value;
     if (aStyleProperties[index])
       cssDecl->GetPropertyValue(nsDependentString(static_cast<PRUnichar*>(aStyleProperties[index])), value);  // Get property value
     aStyleValues[index] = ::SysAllocString(value.get());
--- a/accessible/src/msaa/nsWinUtils.cpp
+++ b/accessible/src/msaa/nsWinUtils.cpp
@@ -50,16 +50,35 @@
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 // Window property used by ipc related code in identifying accessible
 // tab windows.
 const PRUnichar* kPropNameTabContent = L"AccessibleTabWindow";
 
+already_AddRefed<nsIDOMCSSStyleDeclaration>
+nsWinUtils::GetComputedStyleDeclaration(nsIContent* aContent)
+{
+  nsIContent* elm = nsCoreUtils::GetDOMElementFor(aContent);
+  if (!elm)
+    return nsnull;
+
+  // Returns number of items in style declaration
+  nsCOMPtr<nsIDOMWindow> window =
+    do_QueryInterface(elm->OwnerDoc()->GetWindow());
+  if (!window)
+    return nsnull;
+
+  nsCOMPtr<nsIDOMCSSStyleDeclaration> cssDecl;
+  nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(elm));
+  window->GetComputedStyle(domElement, EmptyString(), getter_AddRefs(cssDecl));
+  return cssDecl.forget();
+}
+
 HRESULT
 nsWinUtils::ConvertToIA2Array(nsIArray *aGeckoArray, IUnknown ***aIA2Array,
                               long *aIA2ArrayLen)
 {
   *aIA2Array = NULL;
   *aIA2ArrayLen = 0;
 
   if (!aGeckoArray)
--- a/accessible/src/msaa/nsWinUtils.h
+++ b/accessible/src/msaa/nsWinUtils.h
@@ -48,16 +48,25 @@
 
 const LPCWSTR kClassNameRoot = L"MozillaUIWindowClass";
 const LPCWSTR kClassNameTabContent = L"MozillaContentWindowClass";
 
 class nsWinUtils
 {
 public:
   /**
+   * Return computed styles declaration for the given node.
+   *
+   * @note Please use it carefully since it can shutdown the accessible tree
+   *       you operate on.
+   */
+  static already_AddRefed<nsIDOMCSSStyleDeclaration>
+    GetComputedStyleDeclaration(nsIContent* aContent);
+
+  /**
    * Convert nsIArray array of accessible objects to an array of IUnknown*
    * objects used in IA2 methods.
    */
   static HRESULT ConvertToIA2Array(nsIArray *aCollection,
                                    IUnknown ***aAccessibles, long *aCount);
 
   /**
    * Start window emulation if presence of specific AT is detected.
--- a/accessible/src/xul/nsXULMenuAccessible.cpp
+++ b/accessible/src/xul/nsXULMenuAccessible.cpp
@@ -306,24 +306,16 @@ nsXULMenuitemAccessible::NativeRole()
 }
 
 PRInt32
 nsXULMenuitemAccessible::GetLevelInternal()
 {
   return nsAccUtils::GetLevelForXULContainerItem(mContent);
 }
 
-void
-nsXULMenuitemAccessible::GetPositionAndSizeInternal(PRInt32 *aPosInSet,
-                                                    PRInt32 *aSetSize)
-{
-  nsAccUtils::GetPositionAndSizeForXULContainerItem(mContent, aPosInSet,
-                                                    aSetSize);
-}
-
 bool
 nsXULMenuitemAccessible::CanHaveAnonChildren()
 {
   // That indicates we don't walk anonymous children for menuitems
   return false;
 }
 
 NS_IMETHODIMP nsXULMenuitemAccessible::DoAction(PRUint8 index)
--- a/accessible/src/xul/nsXULMenuAccessible.h
+++ b/accessible/src/xul/nsXULMenuAccessible.h
@@ -58,18 +58,16 @@ public:
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
 
   // nsAccessible
   virtual void Description(nsString& aDescription);
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual mozilla::a11y::role NativeRole();
   virtual PRUint64 NativeState();
   virtual PRInt32 GetLevelInternal();
-  virtual void GetPositionAndSizeInternal(PRInt32 *aPosInSet,
-                                          PRInt32 *aSetSize);
 
   virtual bool CanHaveAnonChildren();
 
   // ActionAccessible
   virtual PRUint8 ActionCount();
   virtual KeyBinding AccessKey() const;
   virtual KeyBinding KeyboardShortcut() const;
 
--- a/accessible/tests/mochitest/Makefile.in
+++ b/accessible/tests/mochitest/Makefile.in
@@ -96,17 +96,16 @@ include $(topsrcdir)/config/rules.mk
 		test_aria_role_equation.html \
 		test_aria_roles.html \
 		test_aria_roles.xul \
 		test_aria_token_attrs.html \
 		test_bug420863.html \
 		test_descr.html \
 		test_nsIAccessibleDocument.html \
 		test_nsIAccessibleImage.html \
-		test_nsIAccessNode_utils.html \
 		test_nsOuterDocAccessible.html \
 		test_role_nsHyperTextAcc.html \
 		test_textboxes.html \
 		test_textboxes.xul \
 		testTextboxes.js \
 		text.js \
 		treeview.css \
 		treeview.js \
--- a/accessible/tests/mochitest/attributes/test_obj_group.html
+++ b/accessible/tests/mochitest/attributes/test_obj_group.html
@@ -134,16 +134,23 @@
       // HTML headings
       testGroupAttrs("h1", 0, 0, 1);
       testGroupAttrs("h2", 0, 0, 2);
       testGroupAttrs("h3", 0, 0, 3);
       testGroupAttrs("h4", 0, 0, 4);
       testGroupAttrs("h5", 0, 0, 5);
       testGroupAttrs("h6", 0, 0, 6);
 
+      //////////////////////////////////////////////////////////////////////////
+      // ARIA combobox
+      testGroupAttrs("combo1_opt1", 1, 4);
+      testGroupAttrs("combo1_opt2", 2, 4);
+      testGroupAttrs("combo1_opt3", 3, 4);
+      testGroupAttrs("combo1_opt4", 4, 4);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 <body>
@@ -300,10 +307,17 @@
 
   <h1 id="h1">heading1</h1>
   <h2 id="h2">heading2</h2>
   <h3 id="h3">heading3</h3>
   <h4 id="h4">heading4</h4>
   <h5 id="h5">heading5</h5>
   <h6 id="h6">heading6</h6>
 
+  <ul id="combo1" role="combobox">Password
+    <li id="combo1_opt1" role="option">Xyzzy</li>
+    <li id="combo1_opt2" role="option">Plughs</li>
+    <li id="combo1_opt3" role="option">Shazaam</li>
+    <li id="combo1_opt4" role="option">JoeSentMe</li>
+  </ul>
+
 </body>
 </html>
--- a/accessible/tests/mochitest/attributes/test_obj_group.xul
+++ b/accessible/tests/mochitest/attributes/test_obj_group.xul
@@ -86,16 +86,23 @@
       testGroupAttrs("tab2", 2, 2);
 
       //////////////////////////////////////////////////////////////////////////
       // xul:radio
       testGroupAttrs("radio1", 1, 2);
       testGroupAttrs("radio2", 2, 2);
 
       //////////////////////////////////////////////////////////////////////////
+      // xul:menulist
+      testGroupAttrs("menulist1.1", 1);
+      testGroupAttrs("menulist1.2", 2);
+      testGroupAttrs("menulist1.3", 3);
+      testGroupAttrs("menulist1.4", 4);
+
+      //////////////////////////////////////////////////////////////////////////
       // ARIA menu (bug 441888)
       testGroupAttrs("aria-menuitem", 1, 3);
       testGroupAttrs("aria-menuitemcheckbox", 2, 3);
       testGroupAttrs("aria-menuitemradio", 3, 3);
       testGroupAttrs("aria-menuitem2", 1, 1);
 
       //////////////////////////////////////////////////////////////////////////
       // xul:menu (bug 443881)
@@ -170,16 +177,25 @@
     </tabpanels>
   </tabbox>
 
   <radiogroup>
     <radio id="radio1" label="radio1"/>
     <radio id="radio2" label="radio2"/>
   </radiogroup>
 
+  <menulist id="menulist1" label="Vehicle">
+    <menupopup>
+      <menuitem id="menulist1.1" label="Car"/>
+      <menuitem id="menulist1.2" label="Taxi"/>
+      <menuitem id="menulist1.3" label="Bus" selected="true"/>
+      <menuitem id="menulist1.4" label="Train"/>
+    </menupopup>
+  </menulist>
+
   <vbox>
     <description role="menuitem" id="aria-menuitem"
                  value="conventional menuitem"/>
     <description role="menuitemcheckbox" id="aria-menuitemcheckbox"
                  value="conventional checkbox menuitem"/>
     <description role="menuitem" hidden="true"/>
     <description role="menuitemradio" id="aria-menuitemradio"
                  value="conventional radio menuitem"/>
--- a/accessible/tests/mochitest/attributes/test_text.html
+++ b/accessible/tests/mochitest/attributes/test_text.html
@@ -176,16 +176,40 @@
       attrs = {};
       testTextAttrs(ID, 50, attrs, defAttrs, 50, 55);
 
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign};
       testTextAttrs(ID, 55, attrs, defAttrs, 55, 64);
 
+      attrs = {};
+      testTextAttrs(ID, 64, attrs, defAttrs, 64, 69);
+
+      attrs = { "text-position": "super" };
+      testTextAttrs(ID, 69, attrs, defAttrs, 69, 84);
+
+      attrs = {};
+      testTextAttrs(ID, 84, attrs, defAttrs, 84, 89);
+
+      attrs = { "text-position": "sub" };
+      testTextAttrs(ID, 89, attrs, defAttrs, 89, 102);
+
+      attrs = {};
+      testTextAttrs(ID, 102, attrs, defAttrs, 102, 107);
+
+      attrs = { "text-position": "super" };
+      testTextAttrs(ID, 107, attrs, defAttrs, 107, 123);
+
+      attrs = {};
+      testTextAttrs(ID, 123, attrs, defAttrs, 123, 128);
+
+      attrs = { "text-position": "sub" };
+      testTextAttrs(ID, 128, attrs, defAttrs, 128, 142);
+
       //////////////////////////////////////////////////////////////////////////
       // area7
       ID = "area7";
       defAttrs = buildDefaultTextAttrs(ID, "12pt");
       defAttrs["language"] = "en";
       testDefaultTextAttrs(ID, defAttrs);
 
       attrs = {"language": "ru"};
@@ -501,16 +525,21 @@
 <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>
   <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=473569"
+     title="Restrict text-position to allowed values">
+    Mozilla Bug 473569
+  </a>
+  <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>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=523304"
      title="expose text-underline-color and text-line-through-color text attributes">
     Mozilla Bug 523304
@@ -544,17 +573,21 @@
     <span style="color: green">Green</span>
     <img src="../moz.png" alt="image"/>
     <span style="color: red">Red</span>Normal
   </p>
   <p id="area6">
     This <sup>sentence</sup> has the word 
     <span style="vertical-align:super;">sentence</span> in 
     <sub>superscript</sub> and 
-    <span style="vertical-align:sub;">subscript</span>
+    <span style="vertical-align:sub;">subscript</span> and
+    <span style="vertical-align:20%;">superscript 20%</span> and
+    <span style="vertical-align:-20%;">subscript 20%</span> and
+    <span style="vertical-align:20px;">superscript 20px</span> and
+    <span style="vertical-align:-20px;">subscript 20px</span>
   </p>
 
   <p lang="en" id="area7">
     <span lang="ru">Привет</span>
     <span style="background-color: blue">Blue BG color</span>
     <span lang="de">Ich bin/Du bist</span>
     <span lang="en">
       Normal
--- a/accessible/tests/mochitest/table/test_layoutguess.html
+++ b/accessible/tests/mochitest/table/test_layoutguess.html
@@ -30,31 +30,49 @@
       testAbsentAttrs("table2", attr);
 
       // table with summary
       testAbsentAttrs("table3", attr);
 
       // table with caption
       testAbsentAttrs("table4", attr);
 
-      // table with empty caption
+      // layout table with empty caption
       testAttrs("table4.2", attr, true);
 
-      // table with th element
-      testAbsentAttrs("table5", attr);
-
       // table with thead element
-      testAbsentAttrs("table6", attr);
+      testAbsentAttrs("table5", attr);
 
       // table with tfoot element
-      testAbsentAttrs("table7", attr);
+      testAbsentAttrs("table5.1", attr);
 
       // table with colgroup or col elements
-      testAbsentAttrs("table8", attr);
-      testAbsentAttrs("table8.2", attr);
+      testAbsentAttrs("table5.2", attr);
+      testAbsentAttrs("table5.3", attr);
+
+      // table with th element
+      testAbsentAttrs("table6", attr);
+
+      // table with headers attribute
+      testAbsentAttrs("table6.2", attr);
+
+      // table with scope attribute
+      testAbsentAttrs("table6.2.2", attr);
+
+      // table with abbr attribute
+      testAbsentAttrs("table6.2.3", attr);
+
+      // table with abbr element
+      testAbsentAttrs("table6.3", attr);
+
+      // table with abbr element having empty text node
+      testAbsentAttrs("table6.4", attr);
+
+      // table with abbr element and non-empty text node 
+      testAttrs("table6.5", attr, true);
 
       // layout table with nested table
       testAttrs("table9", attr, true);
 
       // layout table with 1 column
       testAttrs("table10", attr, true);
 
       // layout table with 1 row
@@ -120,16 +138,21 @@
      title="Data table elements used to determine layout-guess attribute shouldn't be picked from nested tables">
     Mozilla Bug 690222
   </a>
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=693948"
      title="Expose layout-guess: true object attribute on CSS table accessible">
     Mozilla Bug 693948
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=696975"
+     title="Extend the list of legitimate data table structures">
+    Mozilla Bug 696975
+  </a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <!-- Table with role of grid -->
   <table id="table1" role="grid">
@@ -195,63 +218,110 @@
   <!-- table with caption -->
   <table id="table4">
     <caption>This is a table</caption>
     <tr>
       <td>Cell1</td><td>cell2</td>
     </tr>
   </table>
 
-  <!-- table with empty caption -->
+  <!-- layout table with empty caption -->
   <table id="table4.2">
     <caption> </caption>
     <tr>
       <td>Cell1</td><td>cell2</td>
     </tr>
   </table>
 
-  <!-- table with th element -->
+  <!-- table with thead element -->
   <table id="table5">
-    <tr>
-      <th>Cell1</th><th>cell2</th>
-    </tr>
-  </table>
-
-  <!-- table with thead element -->
-  <table id="table6">
     <thead>
       <tr>
         <td>Cell1</td><td>cell2</td>
       </tr>
     </thead>
   </table>
 
   <!-- table with tfoot element -->
-  <table id="table7">
+  <table id="table5.1">
     <tfoot>
       <tr>
         <td>Cell1</td><td>cell2</td>
       </tr>
     </tfoot>
   </table>
 
   <!-- table with colgroup and col elements -->
-  <table id="table8">
+  <table id="table5.2">
     <colgroup width="20"></colgroup>
     <tr>
       <td>Cell1</td><td>cell2</td>
     </tr>
   </table>
-  <table id="table8.2">
+  <table id="table5.3">
     <col width="20">
     <tr>
       <td>Cell1</td><td>cell2</td>
     </tr>
   </table>
 
+  <!-- table with th element -->
+  <table id="table6">
+    <tr>
+      <th>Cell1</th><th>cell2</th>
+    </tr>
+  </table>
+
+  <!-- table with headers attribute -->
+  <table id="table6.2">
+    <tr>
+      <td headers="a">table6.2 cell</td>
+    </tr>
+  </table>
+
+  <!-- table with scope attribute -->
+  <table id="table6.2.2">
+    <tr>
+      <td scope="a">table6.2.2 cell</td>
+    </tr>
+  </table>
+
+  <!-- table with abbr attribute -->
+  <table id="table6.2.3">
+    <tr>
+      <td abbr="table6.2.3">table6.2.3 cell1</td>
+    </tr>
+  </table>
+
+  <!-- table with abbr element -->
+  <table id="table6.3">
+    <tr>
+      <td>table6.3 cell1</td>
+      <td><abbr>table6.3 cell2</abbr></td>
+    </tr>
+  </table>
+
+  <!-- table with abbr element having empty text node -->
+  <table id="table6.4">
+    <tr>
+      <td>
+        <abbr>abbr</abbr>
+      </td>
+    </tr>
+  </table>
+
+  <!-- table with abbr element and non-empty text node -->
+  <table id="table6.5">
+    <tr>
+      <td>
+        This is a really long text (<abbr>tiarlt</abbr>) inside layout table 
+      </td>
+    </tr>
+  </table>
+
   <!-- layout table with nested table -->
   <table id="table9">
     <tr>
       <td><table><tr><td>Cell</td></tr></table></td>
     </tr>
   </table>
 
   <!-- layout table with 1 column -->
deleted file mode 100644
--- a/accessible/tests/mochitest/test_nsIAccessNode_utils.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<html>
-
-<head>
-  <title>nsIAccessNode util methods testing</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">
-    function doTest()
-    {
-      var elmObj = {};
-      var acc = getAccessible("span", null, elmObj);
-      computedStyle = document.defaultView.getComputedStyle(elmObj.value, "");
-
-      // html:span element
-      is(acc.getComputedStyleValue("", "color"), computedStyle.color,
-         "Wrong color for element with ID 'span'");
-
-      // text child of html:span element
-      acc = getAccessible(acc.firstChild);
-      is(acc.getComputedStyleValue("", "color"), computedStyle.color,
-         "Wrong color for text child of element with ID 'span'");
-
-      SimpleTest.finish();
-    }
-
-    SimpleTest.waitForExplicitFinish();
-    addA11yLoadEvent(doTest);
-  </script>
-</head>
-
-<body>
-
-  <a target="_blank"
-     href="https://bugzilla.mozilla.org/show_bug.cgi?id=454211"
-     title="nsIAccessNode util methods testing">
-    Mozilla Bug 454211
-  </a>
-  <p id="display"></p>
-  <div id="content" style="display: none"></div>
-  <pre id="test">
-  </pre>
-
-  <span role="note" style="color: red" id="span">text</span>
-
-</body>
-</html>
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -41,17 +41,17 @@ pref("toolkit.defaultChromeURI", "chrome
 pref("browser.chromeURL", "chrome://browser/content/");
 #ifdef MOZ_OFFICIAL_BRANDING
 pref("browser.homescreenURL", "file:///system/home/homescreen.html");
 #else
 pref("browser.homescreenURL", "file:///data/local/homescreen.html,file:///system/home/homescreen.html");
 #endif
 
 // URL for the dialer application.
-pref("dom.telephony.app.phone.url", "http://localhost:7777/data/local/apps/dialer/dialer.html http://localhost:7777/data/local/apps/homescreen/homescreen.html http://localhost:7777/apps/dialer/dialer.html http://localhost:7777/apps/homescreen/homescreen.html");
+pref("dom.telephony.app.phone.url", "http://localhost:7777/data/local/apps/dialer/dialer.html,http://localhost:7777/data/local/apps/homescreen/homescreen.html,http://localhost:7777/apps/dialer/dialer.html,http://localhost:7777/apps/homescreen/homescreen.html");
 
 // Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
 pref("browser.viewport.scaleRatio", -1);
 
 /* disable text selection */
 pref("browser.ignoreNativeFrameTextSelection", true);
 
 /* cache prefs */
@@ -439,8 +439,17 @@ pref("b2g.keys.menu.enabled", true);
 pref("b2g.keys.search.enabled", false);
 
 // Screen timeout in minutes
 pref("power.screen.timeout", 60);
 
 pref("full-screen-api.enabled", true);
 
 pref("media.volume.steps", 10);
+
+// Data connection settings. These will eventually live in the
+// navigator.settings API, or even in a database where we can look
+// it up automatically (bug 729440), but for this will have to do.
+pref("ril.data.enabled", false);
+pref("ril.data.roaming.enabled", false);
+pref("ril.data.apn", "");
+pref("ril.data.user", "");
+pref("ril.data.passwd", "");
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -277,17 +277,17 @@ pref("browser.urlbar.clickSelectsAll", f
 #else
 pref("browser.urlbar.clickSelectsAll", true);
 #endif
 #ifdef UNIX_BUT_NOT_MAC
 pref("browser.urlbar.doubleClickSelectsAll", true);
 #else
 pref("browser.urlbar.doubleClickSelectsAll", false);
 #endif
-pref("browser.urlbar.autoFill", false);
+pref("browser.urlbar.autoFill", true);
 pref("browser.urlbar.autoFill.typed", true);
 // 0: Match anywhere (e.g., middle of words)
 // 1: Match on word boundaries and then try matching anywhere
 // 2: Match only on word boundaries (e.g., after / or .)
 // 3: Match at the beginning of the url or title
 pref("browser.urlbar.matchBehavior", 1);
 pref("browser.urlbar.filter.javascript", true);
 
@@ -1037,19 +1037,16 @@ pref("devtools.inspector.sidebarOpen", f
 pref("devtools.inspector.activeSidebar", "ruleview");
 
 // Enable the Debugger
 pref("devtools.debugger.enabled", false);
 
 // The default Debugger UI height
 pref("devtools.debugger.ui.height", 250);
 
-// Disable remote debugging protocol logging
-pref("devtools.debugger.log", false);
-
 // Enable the style inspector
 pref("devtools.styleinspector.enabled", true);
 
 // Enable the Tilt inspector
 pref("devtools.tilt.enabled", true);
 pref("devtools.tilt.intro_transition", true);
 pref("devtools.tilt.outro_transition", true);
 
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -435,17 +435,18 @@ window[chromehidden~="toolbar"] toolbar:
 }
 
 /* We use the iconBox as the notification anchor when a popup notification is
    created with a null anchorID, so in that case use a default anchor icon. */
 #notification-popup-box[anchorid="notification-popup-box"] > #default-notification-icon,
 #notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
 #notification-popup-box[anchorid="indexedDB-notification-icon"] > #indexedDB-notification-icon,
 #notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon,
-#notification-popup-box[anchorid="password-notification-icon"] > #password-notification-icon {
+#notification-popup-box[anchorid="password-notification-icon"] > #password-notification-icon,
+#notification-popup-box[anchorid="webapps-notification-icon"] > #webapps-notification-icon {
   display: -moz-box;
 }
 
 #invalid-form-popup > description {
   max-width: 280px;
 }
 
 #geolocation-notification {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4747,20 +4747,25 @@ var XULBrowserWindow = {
         } catch (e) {}
         URLBarSetURI(uri);
 
         // Update starring UI
         PlacesStarButton.updateState();
       }
 
       // Show or hide browser chrome based on the whitelist
-      if (this.hideChromeForLocation(location))
+      if (this.hideChromeForLocation(location)) {
         document.documentElement.setAttribute("disablechrome", "true");
-      else
-        document.documentElement.removeAttribute("disablechrome");
+      } else {
+        let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+        if (ss.getTabValue(gBrowser.selectedTab, "appOrigin"))
+          document.documentElement.setAttribute("disablechrome", "true");
+        else
+          document.documentElement.removeAttribute("disablechrome");
+      }
 
       // Disable find commands in documents that ask for them to be disabled.
       let disableFind = false;
       if (aLocationURI &&
           (aLocationURI.schemeIs("about") || aLocationURI.schemeIs("chrome"))) {
         let docElt = content.document.documentElement;
         disableFind = docElt && docElt.getAttribute("disablefastfind") == "true";
       }
@@ -9095,17 +9100,16 @@ XPCOMUtils.defineLazyGetter(window, "gSh
   let sysInfo = Components.classes["@mozilla.org/system-info;1"]
                           .getService(Components.interfaces.nsIPropertyBag2);
   return parseFloat(sysInfo.getProperty("version")) < 6;
 #else
   return false;
 #endif
 });
 
-
 var MousePosTracker = {
   _listeners: [],
   _x: 0,
   _y: 0,
   get _windowUtils() {
     delete this._windowUtils;
     return this._windowUtils = window.getInterface(Ci.nsIDOMWindowUtils);
   },
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -522,16 +522,17 @@
                  onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
                  onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
           <box id="notification-popup-box" hidden="true" align="center">
             <image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
             <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
             <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
             <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
             <image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
+            <image id="webapps-notification-icon" class="webapps-anchor-icon" role="button"/>
           </box>
           <!-- Use onclick instead of normal popup= syntax since the popup
                code fires onmousedown, and hence eats our favicon drag events.
                We only add the identity-box button to the tab order when the location bar
                has focus, otherwise pressing F6 focuses it instead of the location bar -->
           <box id="identity-box" role="button"
                onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
                onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
@@ -998,18 +999,16 @@
              hidden="true">
 #ifdef XP_MACOSX
       <toolbarbutton id="highlighter-closebutton"
                      oncommand="InspectorUI.closeInspectorUI(false);"
                      tooltiptext="&inspectCloseButton.tooltiptext;"/>
 #endif
       <toolbarbutton id="inspector-inspect-toolbutton"
                      class="devtools-toolbarbutton"
-                     label="&inspectButton.label;"
-                     accesskey="&inspectButton.accesskey;"
                      command="Inspector:Inspect"/>
       <toolbarbutton id="inspector-treepanel-toolbutton"
                      class="devtools-toolbarbutton"
                      label="&htmlPanel.label;"
                      accesskey="&htmlPanel.accesskey;"
                      tooltiptext="&htmlPanel.tooltiptext;"
                      command="Inspector:HTMLPanel"/>
       <arrowscrollbox id="inspector-breadcrumbs"
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -82,8 +82,12 @@ html|*#highlighter-nodeinfobar-tagname {
 
 #highlighter-nodeinfobar-container[disabled] {
   visibility: hidden;
 }
 
 html|*#highlighter-nodeinfobar-tagname {
   text-transform: lowercase;
 }
+
+.devtools-toolbarbutton:not([label]) > .toolbarbutton-text {
+  display: none;
+}
--- a/browser/base/content/newtab/cells.js
+++ b/browser/base/content/newtab/cells.js
@@ -10,26 +10,24 @@
  * aren't handled here.
  */
 function Cell(aGrid, aNode) {
   this._grid = aGrid;
   this._node = aNode;
   this._node._newtabCell = this;
 
   // Register drag-and-drop event handlers.
-  ["DragEnter", "DragOver", "DragExit", "Drop"].forEach(function (aType) {
-    let method = "on" + aType;
-    this[method] = this[method].bind(this);
-    this._node.addEventListener(aType.toLowerCase(), this[method], false);
+  ["dragenter", "dragover", "dragexit", "drop"].forEach(function (aType) {
+    this._node.addEventListener(aType, this, false);
   }, this);
 }
 
 Cell.prototype = {
   /**
-   *
+   * The grid.
    */
   _grid: null,
 
   /**
    * The cell's DOM node.
    */
   get node() this._node,
 
@@ -92,46 +90,32 @@ Cell.prototype = {
    * Checks whether the cell contains a site (is empty).
    * @return Whether the cell is empty.
    */
   isEmpty: function Cell_isEmpty() {
     return !this.site;
   },
 
   /**
-   * Event handler for the 'dragenter' event.
-   * @param aEvent The dragenter event.
-   */
-  onDragEnter: function Cell_onDragEnter(aEvent) {
-    if (gDrag.isValid(aEvent)) {
-      aEvent.preventDefault();
-      gDrop.enter(this, aEvent);
-    }
-  },
-
-  /**
-   * Event handler for the 'dragover' event.
-   * @param aEvent The dragover event.
+   * Handles all cell events.
    */
-  onDragOver: function Cell_onDragOver(aEvent) {
-    if (gDrag.isValid(aEvent))
-      aEvent.preventDefault();
-  },
+  handleEvent: function Cell_handleEvent(aEvent) {
+    if (aEvent.type != "dragexit" && !gDrag.isValid(aEvent))
+      return;
 
-  /**
-   * Event handler for the 'dragexit' event.
-   * @param aEvent The dragexit event.
-   */
-  onDragExit: function Cell_onDragExit(aEvent) {
-    gDrop.exit(this, aEvent);
-  },
-
-  /**
-   * Event handler for the 'drop' event.
-   * @param aEvent The drop event.
-   */
-  onDrop: function Cell_onDrop(aEvent) {
-    if (gDrag.isValid(aEvent)) {
-      aEvent.preventDefault();
-      gDrop.drop(this, aEvent);
+    switch (aEvent.type) {
+      case "dragenter":
+        aEvent.preventDefault();
+        gDrop.enter(this, aEvent);
+        break;
+      case "dragover":
+        aEvent.preventDefault();
+        break;
+      case "dragexit":
+        gDrop.exit(this, aEvent);
+        break;
+      case "drop":
+        aEvent.preventDefault();
+        gDrop.drop(this, aEvent);
+        break;
     }
   }
 };
--- a/browser/base/content/newtab/drag.js
+++ b/browser/base/content/newtab/drag.js
@@ -31,21 +31,21 @@ let gDrag = {
   /**
    * Start a new drag operation.
    * @param aSite The site that's being dragged.
    * @param aEvent The 'dragstart' event.
    */
   start: function Drag_start(aSite, aEvent) {
     this._draggedSite = aSite;
 
-    // Prevent moz-transform for left, top.
-    aSite.node.setAttribute("dragged", "true");
-
-    // Make sure the dragged site is floating above the grid.
-    aSite.node.setAttribute("ontop", "true");
+    // Mark nodes as being dragged.
+    let selector = ".newtab-site, .newtab-control, .newtab-thumbnail";
+    let nodes = aSite.node.parentNode.querySelectorAll(selector);
+    for (let i = 0; i < nodes.length; i++)
+      nodes[i].setAttribute("dragged", "true");
 
     this._setDragData(aSite, aEvent);
 
     // Store the cursor offset.
     let node = aSite.node;
     let rect = node.getBoundingClientRect();
     this._offsetX = aEvent.clientX - rect.left;
     this._offsetY = aEvent.clientY - rect.top;
@@ -83,35 +83,38 @@ let gDrag = {
   },
 
   /**
    * Ends the current drag operation.
    * @param aSite The site that's being dragged.
    * @param aEvent The 'dragend' event.
    */
   end: function Drag_end(aSite, aEvent) {
-    aSite.node.removeAttribute("dragged");
+    let nodes = aSite.node.parentNode.querySelectorAll("[dragged]");
+    for (let i = 0; i < nodes.length; i++)
+      nodes[i].removeAttribute("dragged");
 
     // Slide the dragged site back into its cell (may be the old or the new cell).
-    gTransformation.slideSiteTo(aSite, aSite.cell, {
-      unfreeze: true,
-      callback: function () aSite.node.removeAttribute("ontop")
-    });
+    gTransformation.slideSiteTo(aSite, aSite.cell, {unfreeze: true});
 
     this._draggedSite = null;
   },
 
   /**
    * Checks whether we're responsible for a given drag event.
    * @param aEvent The drag event to check.
    * @return Whether we should handle this drag and drop operation.
    */
   isValid: function Drag_isValid(aEvent) {
     let dt = aEvent.dataTransfer;
-    return dt && dt.types.contains("text/x-moz-url");
+    let mimeType = "text/x-moz-url";
+
+    // Check that the drag data is non-empty.
+    // Can happen when dragging places folders.
+    return dt && dt.types.contains(mimeType) && dt.getData(mimeType);
   },
 
   /**
    * Initializes the drag data for the current drag operation.
    * @param aSite The site that's being dragged.
    * @param aEvent The 'dragstart' event.
    */
   _setDragData: function Drag_setDragData(aSite, aEvent) {
@@ -123,18 +126,18 @@ let gDrag = {
     dt.setData("text/plain", url);
     dt.setData("text/uri-list", url);
     dt.setData("text/x-moz-url", url + "\n" + title);
     dt.setData("text/html", "<a href=\"" + url + "\">" + url + "</a>");
 
     // Create and use an empty drag element. We don't want to use the default
     // drag image with its default opacity.
     let dragElement = document.createElementNS(HTML_NAMESPACE, "div");
-    dragElement.classList.add("drag-element");
-    let body = document.getElementById("body");
-    body.appendChild(dragElement);
+    dragElement.classList.add("newtab-drag");
+    let scrollbox = document.getElementById("newtab-scrollbox");
+    scrollbox.appendChild(dragElement);
     dt.setDragImage(dragElement, 0, 0);
 
     // After the 'dragstart' event has been processed we can remove the
     // temporary drag element from the DOM.
-    setTimeout(function () body.removeChild(dragElement), 0);
+    setTimeout(function () scrollbox.removeChild(dragElement), 0);
   }
 };
--- a/browser/base/content/newtab/dropTargetShim.js
+++ b/browser/base/content/newtab/dropTargetShim.js
@@ -21,52 +21,60 @@ let gDropTargetShim = {
   _lastDropTarget: null,
 
   /**
    * Initializes the drop target shim.
    */
   init: function DropTargetShim_init() {
     let node = gGrid.node;
 
-    this._dragover = this._dragover.bind(this);
+    // Add drag event handlers.
+    node.addEventListener("dragstart", this, true);
+    node.addEventListener("dragend", this, true);
+  },
 
-    // Add drag event handlers.
-    node.addEventListener("dragstart", this._start.bind(this), true);
-    // XXX bug 505521 - Don't listen for drag, it's useless at the moment.
-    //node.addEventListener("drag", this._drag.bind(this), false);
-    node.addEventListener("dragend", this._end.bind(this), true);
+  /**
+   * Handles all shim events.
+   */
+  handleEvent: function DropTargetShim_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "dragstart":
+        this._start(aEvent);
+        break;
+      case "dragover":
+        this._dragover(aEvent);
+        break;
+      case "dragend":
+        this._end(aEvent);
+        break;
+    }
   },
 
   /**
    * Handles the 'dragstart' event.
    * @param aEvent The 'dragstart' event.
    */
   _start: function DropTargetShim_start(aEvent) {
-    if (aEvent.target.classList.contains("site")) {
+    if (aEvent.target.classList.contains("newtab-link")) {
       gGrid.lock();
 
       // XXX bug 505521 - Listen for dragover on the document.
-      document.documentElement.addEventListener("dragover", this._dragover, false);
+      document.documentElement.addEventListener("dragover", this, false);
     }
   },
 
   /**
    * Handles the 'drag' event and determines the current drop target.
    * @param aEvent The 'drag' event.
    */
   _drag: function DropTargetShim_drag(aEvent) {
     // Let's see if we find a drop target.
     let target = this._findDropTarget(aEvent);
 
-    if (target == this._lastDropTarget) {
-      // XXX bug 505521 - Don't fire dragover for now (causes recursion).
-      /*if (target)
-        // The last drop target is valid and didn't change.
-        this._dispatchEvent(aEvent, "dragover", target);*/
-    } else {
+    if (target != this._lastDropTarget) {
       if (this._lastDropTarget)
         // We left the last drop target.
         this._dispatchEvent(aEvent, "dragexit", this._lastDropTarget);
 
       if (target)
         // We're now hovering a (new) drop target.
         this._dispatchEvent(aEvent, "dragenter", target);
 
@@ -79,17 +87,17 @@ let gDropTargetShim = {
   },
 
   /**
    * Handles the 'dragover' event as long as bug 505521 isn't fixed to get
    * current mouse cursor coordinates while dragging.
    * @param aEvent The 'dragover' event.
    */
   _dragover: function DropTargetShim_dragover(aEvent) {
-    let sourceNode = aEvent.dataTransfer.mozSourceNode;
+    let sourceNode = aEvent.dataTransfer.mozSourceNode.parentNode;
     gDrag.drag(sourceNode._newtabSite, aEvent);
 
     this._drag(aEvent);
   },
 
   /**
    * Handles the 'dragend' event.
    * @param aEvent The 'dragend' event.
@@ -112,17 +120,17 @@ let gDropTargetShim = {
       // Clean up.
       this._lastDropTarget = null;
       this._cellPositions = null;
     }
 
     gGrid.unlock();
 
     // XXX bug 505521 - Remove the document's dragover listener.
-    document.documentElement.removeEventListener("dragover", this._dragover, false);
+    document.documentElement.removeEventListener("dragover", this, false);
   },
 
   /**
    * Determines the current drop target by matching the dragged site's position
    * against all cells in the grid.
    * @return The currently hovered drop target or null.
    */
   _findDropTarget: function DropTargetShim_findDropTarget() {
--- a/browser/base/content/newtab/grid.js
+++ b/browser/base/content/newtab/grid.js
@@ -19,17 +19,17 @@ let gGrid = {
    */
   _siteFragment: null,
 
   /**
    * All cells contained in the grid.
    */
   get cells() {
     let cells = [];
-    let children = this.node.querySelectorAll("li");
+    let children = this.node.querySelectorAll(".newtab-cell");
     for (let i = 0; i < children.length; i++)
       cells.push(new Cell(this, children[i]));
 
     // Replace the getter with our cached value.
     Object.defineProperty(this, "cells", {value: cells, enumerable: true});
 
     return cells;
   },
@@ -38,18 +38,18 @@ let gGrid = {
    * All sites contained in the grid's cells. Sites may be empty.
    */
   get sites() [cell.site for each (cell in this.cells)],
 
   /**
    * Initializes the grid.
    * @param aSelector The query selector of the grid.
    */
-  init: function Grid_init(aSelector) {
-    this._node = document.querySelector(aSelector);
+  init: function Grid_init() {
+    this._node = document.getElementById("newtab-grid");
     this._createSiteFragment();
     this._draw();
   },
 
   /**
    * Creates a new site in the grid.
    * @param aLink The new site's link.
    * @param aCell The cell that will contain the new site.
@@ -91,31 +91,30 @@ let gGrid = {
   unlock: function Grid_unlock() {
     this.node.removeAttribute("locked");
   },
 
   /**
    * Creates the DOM fragment that is re-used when creating sites.
    */
   _createSiteFragment: function Grid_createSiteFragment() {
-    let site = document.createElementNS(HTML_NAMESPACE, "a");
-    site.classList.add("site");
+    let site = document.createElementNS(HTML_NAMESPACE, "div");
+    site.classList.add("newtab-site");
     site.setAttribute("draggable", "true");
 
     // Create the site's inner HTML code.
     site.innerHTML =
-      '<img class="site-img" width="' + THUMB_WIDTH +'" ' +
-      ' height="' + THUMB_HEIGHT + '" alt=""/>' +
-      '<span class="site-title"/>' +
-      '<span class="site-strip">' +
-      '  <input class="button strip-button strip-button-pin" type="button"' +
-      '   tabindex="-1" title="' + newTabString("pin") + '"/>' +
-      '  <input class="button strip-button strip-button-block" type="button"' +
-      '   tabindex="-1" title="' + newTabString("block") + '"/>' +
-      '</span>';
+      '<a class="newtab-link">' +
+      '  <span class="newtab-thumbnail"/>' +
+      '  <span class="newtab-title"/>' +
+      '</a>' +
+      '<input type="button" title="' + newTabString("pin") + '"' +
+      '       class="newtab-control newtab-control-pin"/>' +
+      '<input type="button" title="' + newTabString("block") + '"' +
+      '       class="newtab-control newtab-control-block"/>';
 
     this._siteFragment = document.createDocumentFragment();
     this._siteFragment.appendChild(site);
   },
 
   /**
    * Draws the grid, creates all sites and puts them into their cells.
    */
--- a/browser/base/content/newtab/newTab.css
+++ b/browser/base/content/newtab/newTab.css
@@ -1,173 +1,186 @@
 :root {
-  -moz-appearance: none;
-}
-
-#scrollbox:not([page-disabled]) {
-  overflow: auto;
+  -moz-user-focus: normal;
 }
 
-#body {
-  position: relative;
-  margin: 0;
-  min-width: 675px;
-  -moz-user-select: none;
-}
-
-.button {
+input[type=button] {
   cursor: pointer;
 }
 
-/* TOOLBAR */
-#toolbar {
-  position: absolute;
+/* SCROLLBOX */
+#newtab-scrollbox {
+  display: -moz-box;
+  position: relative;
+  -moz-box-flex: 1;
 }
 
-#toolbar[page-disabled] {
-  position: fixed;
+#newtab-scrollbox:not([page-disabled]) {
+  overflow: auto;
 }
 
-#toolbar:-moz-locale-dir(rtl) {
-  left: 8px;
+/* TOGGLE */
+#newtab-toggle {
+  position: absolute;
+  top: 12px;
+  right: 12px;
+}
+
+#newtab-toggle:-moz-locale-dir(rtl) {
+  left: 12px;
   right: auto;
 }
 
-.toolbar-button {
-  position: absolute;
-  cursor: pointer;
-  -moz-transition: opacity 200ms ease-out;
+/* MARGINS */
+#newtab-vertical-margin {
+  display: -moz-box;
+  position: relative;
+  -moz-box-flex: 1;
+  -moz-box-orient: vertical;
+}
+
+#newtab-margin-top {
+  min-height: 50px;
+  max-height: 80px;
+  -moz-box-flex: 1;
+}
+
+#newtab-margin-bottom {
+  min-height: 40px;
+  max-height: 100px;
+  -moz-box-flex: 1;
 }
 
-#toolbar-button-show,
-#toolbar-button-reset {
+#newtab-horizontal-margin {
+  display: -moz-box;
+  -moz-box-flex: 5;
+}
+
+.newtab-side-margin {
+  min-width: 40px;
+  max-width: 300px;
+  -moz-box-flex: 1;
+}
+
+/* GRID */
+#newtab-grid {
+  display: -moz-box;
+  -moz-box-flex: 5;
+  -moz-box-orient: vertical;
+  min-width: 600px;
+  min-height: 400px;
+  -moz-transition: 100ms ease-out;
+  -moz-transition-property: opacity;
+}
+
+#newtab-grid[page-disabled] {
   opacity: 0;
+}
+
+#newtab-grid[locked],
+#newtab-grid[page-disabled] {
   pointer-events: none;
 }
 
-#toolbar-button-reset[modified],
-#toolbar-button-show[page-disabled] {
-  opacity: 1;
-  pointer-events: auto;
-}
-
-#toolbar-button-hide[page-disabled],
-#toolbar-button-reset[page-disabled] {
-  opacity: 0;
-  pointer-events: none;
-}
-
-/* GRID */
-#grid {
-  width: 637px;
-  height: 411px;
-  overflow: hidden;
-  list-style-type: none;
-  -moz-transition: opacity 200ms ease-out;
-}
-
-#grid[page-disabled] {
-  opacity: 0;
-}
-
-#grid[page-disabled],
-#grid[locked] {
-  pointer-events: none;
+/* ROWS */
+.newtab-row {
+  display: -moz-box;
+  -moz-box-orient: horizontal;
+  -moz-box-direction: normal;
+  -moz-box-flex: 1;
 }
 
 /* CELLS */
-.cell {
-  float: left;
-  width: 201px;
-  height: 127px;
-  margin-bottom: 15px;
-  -moz-margin-end: 16px;
-}
-
-.cell:-moz-locale-dir(rtl) {
-  float: right;
-}
-
-.cell:nth-child(3n+3) {
-  -moz-margin-end: 0;
+.newtab-cell {
+  display: -moz-box;
+  -moz-box-flex: 1;
 }
 
 /* SITES */
-.site {
-  display: block;
+.newtab-site {
   position: relative;
-  width: 201px;
-  height: 127px;
+  -moz-box-flex: 1;
+  -moz-transition: 100ms ease-out;
+  -moz-transition-property: top, left, opacity;
 }
 
-.site[frozen] {
+.newtab-site[frozen] {
   position: absolute;
   pointer-events: none;
 }
 
-.site[ontop] {
+.newtab-site[dragged] {
+  -moz-transition-property: none;
   z-index: 10;
 }
 
-/* SITE IMAGE */
-.site-img {
-  display: block;
-  opacity: 0.75;
-  -moz-transition: opacity 200ms ease-out;
+/* LINK + THUMBNAILS */
+.newtab-link,
+.newtab-thumbnail {
+  position: absolute;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
 }
 
-.site:hover > .site-img,
-.site[ontop] > .site-img,
-.site:-moz-focusring > .site-img {
+.newtab-thumbnail {
+  opacity: .8;
+  -moz-transition: opacity 100ms ease-out;
+}
+
+.newtab-thumbnail[dragged],
+.newtab-link:-moz-focusring > .newtab-thumbnail,
+.newtab-site:hover > .newtab-link > .newtab-thumbnail {
   opacity: 1;
 }
 
-.site-img[loading] {
-  display: none;
-}
-
-/* SITE TITLE */
-.site-title {
+/* TITLES */
+.newtab-title {
   position: absolute;
   left: 0;
+  right: 0;
   bottom: 0;
+  white-space: nowrap;
   overflow: hidden;
+  text-overflow: ellipsis;
 }
 
-/* SITE STRIP */
-.site-strip {
+/* CONTROLS */
+.newtab-control {
   position: absolute;
-  left: 0;
-  top: 0;
-  width: 195px;
-  height: 17px;
-  overflow: hidden;
+  top: 4px;
   opacity: 0;
-  -moz-transition: opacity 200ms ease-out;
+  -moz-transition: opacity 100ms ease-out;
 }
 
-.site:hover:not([frozen]) > .site-strip {
+.newtab-control:-moz-focusring,
+.newtab-site:hover > .newtab-control {
   opacity: 1;
 }
 
-.strip-button-pin,
-.strip-button-block:-moz-locale-dir(rtl) {
-  float: left;
+.newtab-control[dragged] {
+  opacity: 0 !important;
 }
 
-.strip-button-block,
-.strip-button-pin:-moz-locale-dir(rtl) {
-  float: right;
+.newtab-control-pin:-moz-locale-dir(ltr),
+.newtab-control-block:-moz-locale-dir(rtl) {
+  left: 4px;
+}
+
+.newtab-control-block:-moz-locale-dir(ltr),
+.newtab-control-pin:-moz-locale-dir(rtl) {
+  right: 4px;
 }
 
 /* DRAG & DROP */
 
 /*
  * This is just a temporary drag element used for dataTransfer.setDragImage()
  * so that we can use custom drag images and elements. It needs an opacity of
  * 0.01 so that the core code detects that it's in fact a visible element.
  */
-.drag-element {
+.newtab-drag {
   width: 1px;
   height: 1px;
   background-color: #fff;
   opacity: 0.01;
 }
--- a/browser/base/content/newtab/newTab.js
+++ b/browser/base/content/newtab/newTab.js
@@ -25,26 +25,23 @@ let {
 XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
   return Services.strings.
     createBundle("chrome://browser/locale/newTab.properties");
 });
 
 function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
 
 const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
-const THUMB_WIDTH = 201;
-const THUMB_HEIGHT = 127;
 
 #include batch.js
 #include transformations.js
 #include page.js
-#include toolbar.js
 #include grid.js
 #include cells.js
 #include sites.js
 #include drag.js
 #include drop.js
 #include dropTargetShim.js
 #include dropPreview.js
 #include updater.js
 
 // Everything is loaded. Initialize the New Tab Page.
-gPage.init("#toolbar", "#grid");
+gPage.init();
--- a/browser/base/content/newtab/newTab.xul
+++ b/browser/base/content/newtab/newTab.xul
@@ -1,40 +1,56 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 # 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/.
 
-<?xml-stylesheet href="chrome://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/newtab/newTab.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/newtab/newTab.css" type="text/css"?>
 
 <!DOCTYPE window [
   <!ENTITY % newTabDTD SYSTEM "chrome://browser/locale/newTab.dtd">
   %newTabDTD;
 ]>
 
-<xul:window xmlns="http://www.w3.org/1999/xhtml"
+<xul:window id="newtab-window" xmlns="http://www.w3.org/1999/xhtml"
             xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-            disablefastfind="true" title="&newtab.pageTitle;">
-  <xul:vbox id="scrollbox" flex="1" title=" ">
-    <body id="body">
-      <div id="toolbar">
-        <input class="button toolbar-button" id="toolbar-button-show"
-               type="button" title="&newtab.show;"/>
-        <input class="button toolbar-button" id="toolbar-button-hide"
-               type="button" title="&newtab.hide;"/>
-        <input class="button toolbar-button" id="toolbar-button-reset"
-               type="button" title="&newtab.reset;"/>
+            xul:disablefastfind="true" xul:title="&newtab.pageTitle;">
+
+  <div id="newtab-scrollbox">
+
+    <div id="newtab-vertical-margin">
+      <div id="newtab-margin-top"/>
+
+      <div id="newtab-horizontal-margin">
+        <div class="newtab-side-margin"/>
+
+        <div id="newtab-grid">
+          <div class="newtab-row">
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+          </div>
+          <div class="newtab-row">
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+          </div>
+          <div class="newtab-row">
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+            <div class="newtab-cell"/>
+          </div>
+        </div>
+
+        <div class="newtab-side-margin"/>
       </div>
 
-      <ul id="grid">
-        <li class="cell"/><li class="cell"/><li class="cell"/>
-        <li class="cell"/><li class="cell"/><li class="cell"/>
-        <li class="cell"/><li class="cell"/><li class="cell"/>
-      </ul>
+      <div id="newtab-margin-bottom"/>
+    </div>
+    <input id="newtab-toggle" type="button"/>
+  </div>
 
-      <xul:script type="text/javascript;version=1.8"
-                  src="chrome://browser/content/newtab/newTab.js"/>
-    </body>
-  </xul:vbox>
+  <xul:script type="text/javascript;version=1.8"
+              src="chrome://browser/content/newtab/newTab.js"/>
 </xul:window>
--- a/browser/base/content/newtab/page.js
+++ b/browser/base/content/newtab/page.js
@@ -6,35 +6,34 @@
 
 /**
  * This singleton represents the whole 'New Tab Page' and takes care of
  * initializing all its components.
  */
 let gPage = {
   /**
    * Initializes the page.
-   * @param aToolbarSelector The query selector for the page toolbar.
-   * @param aGridSelector The query selector for the grid.
    */
-  init: function Page_init(aToolbarSelector, aGridSelector) {
-    gToolbar.init(aToolbarSelector);
-    this._gridSelector = aGridSelector;
-
+  init: function Page_init() {
     // Add ourselves to the list of pages to receive notifications.
     gAllPages.register(this);
 
     // Listen for 'unload' to unregister this page.
-    function unload() { gAllPages.unregister(this); }
-    addEventListener("unload", unload.bind(this), false);
+    addEventListener("unload", this, false);
+
+    // Listen for toggle button clicks.
+    let button = document.getElementById("newtab-toggle");
+    button.addEventListener("click", this, false);
 
     // Check if the new tab feature is enabled.
-    if (gAllPages.enabled)
+    let enabled = gAllPages.enabled;
+    if (enabled)
       this._init();
-    else
-      this._updateAttributes(false);
+
+    this._updateAttributes(enabled);
   },
 
   /**
    * Listens for notifications specific to this page.
    */
   observe: function Page_observe() {
     let enabled = gAllPages.enabled;
     this._updateAttributes(enabled);
@@ -43,132 +42,82 @@ let gPage = {
     if (enabled)
       this._init();
   },
 
   /**
    * Updates the whole page and the grid when the storage has changed.
    */
   update: function Page_update() {
-    this.updateModifiedFlag();
     gGrid.refresh();
   },
 
   /**
-   * Checks if the page is modified and sets the CSS class accordingly
-   */
-  updateModifiedFlag: function Page_updateModifiedFlag() {
-    let node = document.getElementById("toolbar-button-reset");
-    let modified = this._isModified();
-
-    if (modified)
-      node.setAttribute("modified", "true");
-    else
-      node.removeAttribute("modified");
-
-    this._updateTabIndices(gAllPages.enabled, modified);
-  },
-
-  /**
    * Internally initializes the page. This runs only when/if the feature
    * is/gets enabled.
    */
   _init: function Page_init() {
     if (this._initialized)
       return;
 
     this._initialized = true;
 
     gLinks.populateCache(function () {
-      // Check if the grid is modified.
-      this.updateModifiedFlag();
-
       // Initialize and render the grid.
-      gGrid.init(this._gridSelector);
+      gGrid.init();
 
       // Initialize the drop target shim.
       gDropTargetShim.init();
 
 #ifdef XP_MACOSX
       // Workaround to prevent a delay on MacOSX due to a slow drop animation.
-      document.addEventListener("dragover", this.onDragOver, false);
-      document.addEventListener("drop", this.onDrop, false);
+      document.addEventListener("dragover", this, false);
+      document.addEventListener("drop", this, false);
 #endif
     }.bind(this));
   },
 
   /**
    * Updates the 'page-disabled' attributes of the respective DOM nodes.
-   * @param aValue Whether to set or remove attributes.
+   * @param aValue Whether the New Tab Page is enabled or not.
    */
   _updateAttributes: function Page_updateAttributes(aValue) {
-    let nodes = document.querySelectorAll("#grid, #scrollbox, #toolbar, .toolbar-button");
+    let selector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid";
+    let nodes = document.querySelectorAll(selector);
 
     // Set the nodes' states.
     for (let i = 0; i < nodes.length; i++) {
       let node = nodes[i];
       if (aValue)
         node.removeAttribute("page-disabled");
       else
         node.setAttribute("page-disabled", "true");
     }
 
-    this._updateTabIndices(aValue, this._isModified());
-  },
-
-  /**
-   * Checks whether the page is modified.
-   * @return Whether the page is modified or not.
-   */
-  _isModified: function Page_isModified() {
-    // The page is considered modified only if sites have been removed.
-    return !gBlockedLinks.isEmpty();
+    // Update the toggle button's title.
+    let toggle = document.getElementById("newtab-toggle");
+    toggle.setAttribute("title", newTabString(aValue ? "hide" : "show"));
   },
 
   /**
-   * Updates the tab indices of focusable elements.
-   * @param aEnabled Whether the page is currently enabled.
-   * @param aModified Whether the page is currently modified.
+   * Handles all page events.
    */
-  _updateTabIndices: function Page_updateTabIndices(aEnabled, aModified) {
-    function setFocusable(aNode, aFocusable) {
-      if (aFocusable)
-        aNode.removeAttribute("tabindex");
-      else
-        aNode.setAttribute("tabindex", "-1");
-    }
-
-    // Sites and the 'hide' button are always focusable when the grid is shown.
-    let nodes = document.querySelectorAll(".site, #toolbar-button-hide");
-    for (let i = 0; i < nodes.length; i++)
-      setFocusable(nodes[i], aEnabled);
-
-    // The 'show' button is focusable when the grid is hidden.
-    let btnShow = document.getElementById("toolbar-button-show");
-    setFocusable(btnShow, !aEnabled);
-
-    // The 'reset' button is focusable when the grid is shown and modified.
-    let btnReset = document.getElementById("toolbar-button-reset");
-    setFocusable(btnReset, aEnabled && aModified);
-  },
-
-  /**
-   * Handles the 'dragover' event. Workaround to prevent a delay on MacOSX
-   * due to a slow drop animation.
-   * @param aEvent The 'dragover' event.
-   */
-  onDragOver: function Page_onDragOver(aEvent) {
-    if (gDrag.isValid(aEvent) && gDrag.draggedSite)
-      aEvent.preventDefault();
-  },
-
-  /**
-   * Handles the 'drop' event. Workaround to prevent a delay on MacOSX due to
-   * a slow drop animation.
-   * @param aEvent The 'drop' event.
-   */
-  onDrop: function Page_onDrop(aEvent) {
-    if (gDrag.isValid(aEvent) && gDrag.draggedSite) {
-      aEvent.preventDefault();
-      aEvent.stopPropagation();
+  handleEvent: function Page_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "unload":
+        gAllPages.unregister(this);
+        break;
+      case "click":
+        gAllPages.enabled = !gAllPages.enabled;
+        break;
+      case "dragover":
+        if (gDrag.isValid(aEvent) && gDrag.draggedSite)
+          aEvent.preventDefault();
+        break;
+      case "drop":
+        if (gDrag.isValid(aEvent) && gDrag.draggedSite) {
+          aEvent.preventDefault();
+          aEvent.stopPropagation();
+        }
+        break;
     }
   }
 };
--- a/browser/base/content/newtab/sites.js
+++ b/browser/base/content/newtab/sites.js
@@ -77,22 +77,26 @@ Site.prototype = {
    */
   isPinned: function Site_isPinned() {
     return gPinnedLinks.isPinned(this._link);
   },
 
   /**
    * Blocks the site (removes it from the grid) and calls the given callback
    * when done.
-   * @param aCallback The callback to be called when finished.
+   * @param aCallback The function to be called when finished.
    */
   block: function Site_block(aCallback) {
-    gBlockedLinks.block(this._link);
-    gUpdater.updateGrid(aCallback);
-    gPage.updateModifiedFlag();
+    if (gBlockedLinks.isBlocked(this._link)) {
+      if (aCallback)
+        aCallback();
+    } else {
+      gBlockedLinks.block(this._link);
+      gUpdater.updateGrid(aCallback);
+    }
   },
 
   /**
    * Gets the DOM node specified by the given query selector.
    * @param aSelector The query selector.
    * @return The DOM node we found.
    */
   _querySelector: function Site_querySelector(aSelector) {
@@ -100,110 +104,76 @@ Site.prototype = {
   },
 
   /**
    * Updates attributes for all nodes which status depends on this site being
    * pinned or unpinned.
    * @param aPinned Whether this site is now pinned or unpinned.
    */
   _updateAttributes: function (aPinned) {
-    let buttonPin = this._querySelector(".strip-button-pin");
+    let control = this._querySelector(".newtab-control-pin");
 
     if (aPinned) {
-      this.node.setAttribute("pinned", true);
-      buttonPin.setAttribute("title", newTabString("unpin"));
+      control.setAttribute("pinned", true);
+      control.setAttribute("title", newTabString("unpin"));
     } else {
-      this.node.removeAttribute("pinned");
-      buttonPin.setAttribute("title", newTabString("pin"));
+      control.removeAttribute("pinned");
+      control.setAttribute("title", newTabString("pin"));
     }
   },
 
   /**
    * Renders the site's data (fills the HTML fragment).
    */
   _render: function Site_render() {
     let title = this.title || this.url;
-    this.node.setAttribute("title", title);
-    this.node.setAttribute("href", this.url);
-    this._querySelector(".site-title").textContent = title;
+    let link = this._querySelector(".newtab-link");
+    link.setAttribute("title", title);
+    link.setAttribute("href", this.url);
+    this._querySelector(".newtab-title").textContent = title;
 
     if (this.isPinned())
       this._updateAttributes(true);
 
-    this._renderThumbnail();
-  },
-
-  /**
-   * Renders the site's thumbnail.
-   */
-  _renderThumbnail: function Site_renderThumbnail() {
-    let img = this._querySelector(".site-img")
-    img.setAttribute("alt", this.title || this.url);
-    img.setAttribute("loading", "true");
-
-    // Wait until the image has loaded.
-    img.addEventListener("load", function onLoad() {
-      img.removeEventListener("load", onLoad, false);
-      img.removeAttribute("loading");
-    }, false);
-
-    // Set the thumbnail url.
-    img.setAttribute("src", PageThumbs.getThumbnailURL(this.url));
+    let thumbnailURL = PageThumbs.getThumbnailURL(this.url);
+    let thumbnail = this._querySelector(".newtab-thumbnail");
+    thumbnail.style.backgroundImage = "url(" + thumbnailURL + ")";
   },
 
   /**
    * Adds event handlers for the site and its buttons.
    */
   _addEventHandlers: function Site_addEventHandlers() {
     // Register drag-and-drop event handlers.
-    ["DragStart", /*"Drag",*/ "DragEnd"].forEach(function (aType) {
-      let method = "_on" + aType;
-      this[method] = this[method].bind(this);
-      this._node.addEventListener(aType.toLowerCase(), this[method], false);
-    }, this);
-
-    let self = this;
-
-    function pin(aEvent) {
-      if (aEvent)
-        aEvent.preventDefault();
+    this._node.addEventListener("dragstart", this, false);
+    this._node.addEventListener("dragend", this, false);
 
-      if (self.isPinned())
-        self.unpin();
-      else
-        self.pin();
-    }
-
-    function block(aEvent) {
-      if (aEvent)
-        aEvent.preventDefault();
-
-      self.block();
-    }
-
-    this._querySelector(".strip-button-pin").addEventListener("click", pin, false);
-    this._querySelector(".strip-button-block").addEventListener("click", block, false);
+    let controls = this.node.querySelectorAll(".newtab-control");
+    for (let i = 0; i < controls.length; i++)
+      controls[i].addEventListener("click", this, false);
   },
 
   /**
-   * Event handler for the 'dragstart' event.
-   * @param aEvent The drag event.
+   * Handles all site events.
    */
-  _onDragStart: function Site_onDragStart(aEvent) {
-    gDrag.start(this, aEvent);
-  },
-
-  /**
-   * Event handler for the 'drag' event.
-   * @param aEvent The drag event.
-  */
-  _onDrag: function Site_onDrag(aEvent) {
-    gDrag.drag(this, aEvent);
-  },
-
-  /**
-   * Event handler for the 'dragend' event.
-   * @param aEvent The drag event.
-   */
-  _onDragEnd: function Site_onDragEnd(aEvent) {
-    gDrag.end(this, aEvent);
+  handleEvent: function Site_handleEvent(aEvent) {
+    switch (aEvent.type) {
+      case "click":
+        aEvent.preventDefault();
+        if (aEvent.target.classList.contains("newtab-control-block"))
+          this.block();
+        else if (this.isPinned())
+          this.unpin();
+        else
+          this.pin();
+        break;
+      case "dragstart":
+        gDrag.start(this, aEvent);
+        break;
+      case "drag":
+        gDrag.drag(this, aEvent);
+        break;
+      case "dragend":
+        gDrag.end(this, aEvent);
+        break;
+    }
   }
 };
deleted file mode 100644
--- a/browser/base/content/newtab/toolbar.js
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifdef 0
-/* 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/. */
-#endif
-
-/**
- * This singleton represents the page's toolbar that allows to enable/disable
- * the 'New Tab Page' feature and to reset the whole page.
- */
-let gToolbar = {
-  /**
-   * Initializes the toolbar.
-   * @param aSelector The query selector of the toolbar.
-   */
-  init: function Toolbar_init(aSelector) {
-    this._node = document.querySelector(aSelector);
-    let buttons = this._node.querySelectorAll("input");
-
-    // Listen for 'click' events on the toolbar buttons.
-    ["show", "hide", "reset"].forEach(function (aType, aIndex) {
-      let self = this;
-      let button = buttons[aIndex];
-      let handler = function () self[aType]();
-
-      button.addEventListener("click", handler, false);
-
-#ifdef XP_MACOSX
-      // Per default buttons lose focus after being clicked on Mac OS X.
-      // So when the URL bar has focus and a toolbar button is clicked the
-      // URL bar regains focus and the history pops up. We need to prevent
-      // that by explicitly removing its focus.
-      button.addEventListener("mousedown", function () {
-        window.focus();
-      }, false);
-#endif
-    }, this);
-  },
-
-  /**
-   * Enables the 'New Tab Page' feature.
-   */
-  show: function Toolbar_show() {
-    this._passButtonFocus("show", "hide");
-    gAllPages.enabled = true;
-  },
-
-  /**
-   * Disables the 'New Tab Page' feature.
-   */
-  hide: function Toolbar_hide() {
-    this._passButtonFocus("hide", "show");
-    gAllPages.enabled = false;
-  },
-
-  /**
-   * Resets the whole page and forces it to re-render its content.
-   * @param aCallback The callback to call when the page has been reset.
-   */
-  reset: function Toolbar_reset(aCallback) {
-    this._passButtonFocus("reset", "hide");
-    let node = gGrid.node;
-
-    // animate the page reset
-    gTransformation.fadeNodeOut(node, function () {
-      NewTabUtils.reset();
-
-      gLinks.populateCache(function () {
-        gAllPages.update();
-
-        // Without the setTimeout() we have a strange flicker.
-        setTimeout(function () gTransformation.fadeNodeIn(node, aCallback));
-      }, true);
-    });
-  },
-
-  /**
-   * Passes the focus from the current button to the next.
-   * @param aCurrent The button that currently has focus.
-   * @param aNext The button that is focused next.
-   */
-  _passButtonFocus: function Toolbar_passButtonFocus(aCurrent, aNext) {
-    if (document.querySelector("#toolbar-button-" + aCurrent + ":-moz-focusring"))
-      document.getElementById("toolbar-button-" + aNext).focus();
-  }
-};
-
--- a/browser/base/content/newtab/transformations.js
+++ b/browser/base/content/newtab/transformations.js
@@ -6,16 +6,34 @@
 
 /**
  * This singleton allows to transform the grid by repositioning a site's node
  * in the DOM and by showing or hiding the node. It additionally provides
  * convenience methods to work with a site's DOM node.
  */
 let gTransformation = {
   /**
+   * Returns the width of the left and top border of a cell. We need to take it
+   * into account when measuring and comparing site and cell positions.
+   */
+  get _cellBorderWidths() {
+    let cstyle = window.getComputedStyle(gGrid.cells[0].node, null);
+    let widths = {
+      left: parseInt(cstyle.getPropertyValue("border-left-width")),
+      top: parseInt(cstyle.getPropertyValue("border-top-width"))
+    };
+
+    // Cache this value, overwrite the getter.
+    Object.defineProperty(this, "_cellBorderWidths",
+                          {value: widths, enumerable: true});
+
+    return widths;
+  },
+
+  /**
    * Gets a DOM node's position.
    * @param aNode The DOM node.
    * @return A Rect instance with the position.
    */
   getNodePosition: function Transformation_getNodePosition(aNode) {
     let {left, top, width, height} = aNode.getBoundingClientRect();
     return new Rect(left + scrollX, top + scrollY, width, height);
   },
@@ -75,27 +93,38 @@ let gTransformation = {
     style.left = left + "px";
   },
 
   /**
    * Freezes a site in its current position by positioning it absolute.
    * @param aSite The site to freeze.
    */
   freezeSitePosition: function Transformation_freezeSitePosition(aSite) {
+    if (this._isFrozen(aSite))
+      return;
+
+    let style = aSite.node.style;
+    let comp = getComputedStyle(aSite.node, null);
+    style.width = comp.getPropertyValue("width")
+    style.height = comp.getPropertyValue("height");
+
     aSite.node.setAttribute("frozen", "true");
     this.setSitePosition(aSite, this.getNodePosition(aSite.node));
   },
 
   /**
    * Unfreezes a site by removing its absolute positioning.
    * @param aSite The site to unfreeze.
    */
   unfreezeSitePosition: function Transformation_unfreezeSitePosition(aSite) {
+    if (!this._isFrozen(aSite))
+      return;
+
     let style = aSite.node.style;
-    style.left = style.top = "";
+    style.left = style.top = style.width = style.height = "";
     aSite.node.removeAttribute("frozen");
   },
 
   /**
    * Slides the given site to the target node's position.
    * @param aSite The site to move.
    * @param aTarget The slide target.
    * @param aOptions Set of options (see below).
@@ -112,18 +141,23 @@ let gTransformation = {
     function finish() {
       if (aOptions && aOptions.unfreeze)
         self.unfreezeSitePosition(aSite);
 
       if (callback)
         callback();
     }
 
+    // We need to take the width of a cell's border into account.
+    targetPosition.left += this._cellBorderWidths.left;
+    targetPosition.top += this._cellBorderWidths.top;
+
     // Nothing to do here if the positions already match.
-    if (currentPosition.equals(targetPosition)) {
+    if (currentPosition.left == targetPosition.left &&
+        currentPosition.top == targetPosition.top) {
       finish();
     } else {
       this.setSitePosition(aSite, targetPosition);
       this._whenTransitionEnded(aSite.node, finish);
     }
   },
 
   /**
@@ -217,10 +251,19 @@ let gTransformation = {
    * Moves a site to the cell with the given index.
    * @param aSite The site to move.
    * @param aIndex The target cell's index.
    * @param aOptions Options that are directly passed to slideSiteTo().
    */
   _moveSite: function Transformation_moveSite(aSite, aIndex, aOptions) {
     this.freezeSitePosition(aSite);
     this.slideSiteTo(aSite, gGrid.cells[aIndex], aOptions);
+  },
+
+  /**
+   * Checks whether a site is currently frozen.
+   * @param aSite The site to check.
+   * @return Whether the given site is frozen.
+   */
+  _isFrozen: function Transformation_isFrozen(aSite) {
+    return aSite.node.hasAttribute("frozen");
   }
 };
--- a/browser/base/content/test/newtab/Makefile.in
+++ b/browser/base/content/test/newtab/Makefile.in
@@ -18,13 +18,15 @@ include $(topsrcdir)/config/rules.mk
 	browser_newtab_drop_preview.js \
 	browser_newtab_private_browsing.js \
 	browser_newtab_reset.js \
 	browser_newtab_tabsync.js \
 	browser_newtab_unpin.js \
 	browser_newtab_bug722273.js \
 	browser_newtab_bug723102.js \
 	browser_newtab_bug723121.js \
+	browser_newtab_bug725996.js \
+	browser_newtab_bug734043.js \
 	head.js \
 	$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/base/content/test/newtab/browser_newtab_bug723102.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug723102.js
@@ -7,11 +7,12 @@ function runTests() {
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   let firstTab = gBrowser.selectedTab;
 
   yield addNewTabPageTab();
   gBrowser.removeTab(firstTab);
 
-  cw.gToolbar.hide();
+  ok(NewTabUtils.allPages.enabled, true, "page is enabled");
+  NewTabUtils.allPages.enabled = false;
   ok(cw.gGrid.node.hasAttribute("page-disabled"), "page is disabled");
 }
--- a/browser/base/content/test/newtab/browser_newtab_bug723121.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug723121.js
@@ -5,25 +5,29 @@ function runTests() {
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   checkGridLocked(false, "grid is unlocked");
 
   let cell = cells[0].node;
   let site = cells[0].site.node;
+  let link = site.querySelector(".newtab-link");
 
-  sendDragEvent(site, "dragstart");
+  sendDragEvent(link, "dragstart");
   checkGridLocked(true, "grid is now locked");
 
-  sendDragEvent(site, "dragend");
+  sendDragEvent(link, "dragend");
   checkGridLocked(false, "grid isn't locked anymore");
 
   sendDragEvent(cell, "dragstart");
   checkGridLocked(false, "grid isn't locked - dragstart was ignored");
+
+  sendDragEvent(site, "dragstart");
+  checkGridLocked(false, "grid isn't locked - dragstart was ignored");
 }
 
 function checkGridLocked(aLocked, aMessage) {
   is(cw.gGrid.node.hasAttribute("locked"), aLocked, aMessage);
 }
 
 function sendDragEvent(aNode, aType) {
   let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_bug725996.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function runTests() {
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+  checkGrid("0,1,2,3,4,5,6,7,8");
+
+  let cell = cells[0].node;
+
+  sendDropEvent(cell, "about:blank#99\nblank");
+  is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
+     "first cell is pinned and contains the dropped site");
+
+  yield whenPagesUpdated();
+  checkGrid("99p,0,1,2,3,4,5,6,7");
+
+  sendDropEvent(cell, "");
+  is(NewTabUtils.pinnedLinks.links[0].url, "about:blank#99",
+     "first cell is still pinned with the site we dropped before");
+}
+
+function sendDropEvent(aNode, aData) {
+  let ifaceReq = cw.QueryInterface(Ci.nsIInterfaceRequestor);
+  let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
+
+  let dataTransfer = {
+    mozUserCancelled: false,
+    setData: function () null,
+    setDragImage: function () null,
+    getData: function () aData,
+
+    types: {
+      contains: function (aType) aType == "text/x-moz-url"
+    },
+
+    mozGetDataAt: function (aType, aIndex) {
+      if (aIndex || aType != "text/x-moz-url")
+        return null;
+
+      return aData;
+    },
+  };
+
+  let event = cw.document.createEvent("DragEvents");
+  event.initDragEvent("drop", true, true, cw, 0, 0, 0, 0, 0,
+                      false, false, false, false, 0, null, dataTransfer);
+
+  windowUtils.dispatchDOMEventViaPresShell(aNode, event, true);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/newtab/browser_newtab_bug734043.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function runTests() {
+  // TODO Bug 735166 - Intermittent timeout in browser_newtab_bug734043.js
+  return;
+
+  setLinks("0,1,2,3,4,5,6,7,8");
+  setPinnedLinks("");
+
+  yield addNewTabPageTab();
+
+  let receivedError = false;
+  let block = cw.document.querySelector(".newtab-control-block");
+
+  function onError() {
+    receivedError = true;
+  }
+
+  cw.addEventListener("error", onError);
+
+  for (let i = 0; i < 3; i++) {
+    EventUtils.synthesizeMouseAtCenter(block, {}, cw);
+    yield executeSoon(TestRunner.next);
+  }
+
+  yield whenPagesUpdated();
+  ok(!receivedError, "we got here without any errors");
+  cw.removeEventListener("error", onError);
+}
--- a/browser/base/content/test/newtab/browser_newtab_disable.js
+++ b/browser/base/content/test/newtab/browser_newtab_disable.js
@@ -10,25 +10,25 @@ function runTests() {
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   let gridNode = cw.gGrid.node;
 
   ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
 
-  cw.gToolbar.hide();
+  NewTabUtils.allPages.enabled = false;
   ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
 
   let oldGridNode = cw.gGrid.node;
 
   // create a second new tage page and make sure it's disabled. enable it
   // again and check if the former page gets enabled as well.
   yield addNewTabPageTab();
   ok(gridNode.hasAttribute("page-disabled"), "page is disabled");
 
   // check that no sites have been rendered
   is(0, cw.document.querySelectorAll(".site").length, "no sites have been rendered");
 
-  cw.gToolbar.show();
+  NewTabUtils.allPages.enabled = true;
   ok(!gridNode.hasAttribute("page-disabled"), "page is not disabled");
   ok(!oldGridNode.hasAttribute("page-disabled"), "old page is not disabled");
 }
--- a/browser/base/content/test/newtab/browser_newtab_reset.js
+++ b/browser/base/content/test/newtab/browser_newtab_reset.js
@@ -1,15 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /*
  * These tests make sure that resetting the 'New Tage Page' works as expected.
  */
 function runTests() {
+  // Disabled until bug 716543 is fixed.
+  return;
+
   // create a new tab page and check its modified state after blocking a site
   setLinks("0,1,2,3,4,5,6,7,8");
   setPinnedLinks("");
 
   yield addNewTabPageTab();
   let resetButton = cw.document.getElementById("toolbar-button-reset");
 
   checkGrid("0,1,2,3,4,5,6,7,8");
--- a/browser/base/content/test/newtab/browser_newtab_tabsync.js
+++ b/browser/base/content/test/newtab/browser_newtab_tabsync.js
@@ -3,16 +3,19 @@
 
 /*
  * These tests make sure that all changes that are made to a specific
  * 'New Tab Page' are synchronized with all other open 'New Tab Pages'
  * automatically. All about:newtab pages should always be in the same
  * state.
  */
 function runTests() {
+  // Disabled until bug 716543 is fixed.
+  return;
+
   setLinks("0,1,2,3,4,5,6,7,8,9");
   setPinnedLinks(",1");
 
   yield addNewTabPageTab();
   checkGrid("0,1p,2,3,4,5,6,7,8");
 
   let resetButton = cw.document.getElementById("toolbar-button-reset");
   ok(!resetButton.hasAttribute("modified"), "page is not modified");
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -183,17 +183,17 @@ function checkGrid(aSitesPattern, aSites
     // Check the site's url.
     if (site.url != "about:blank#" + num) {
       valid = false;
       is(site.url, "about:blank#" + num, "cell#" + index + " has the wrong url");
     }
 
     let shouldBePinned = /p$/.test(id);
     let cellContainsPinned = site.isPinned();
-    let cssClassPinned = site.node && site.node.hasAttribute("pinned");
+    let cssClassPinned = site.node && site.node.querySelector(".newtab-control-pin").hasAttribute("pinned");
 
     // Check if the site should be and is pinned.
     if (shouldBePinned) {
       if (!cellContainsPinned) {
         valid = false;
         ok(false, "expected cell#" + index + " to be pinned");
       } else if (!cssClassPinned) {
         valid = false;
@@ -260,8 +260,25 @@ function simulateDrop(aDropTarget, aDrag
   if (aDragSource)
     cw.gDrag.start(aDragSource.site, event);
 
   cw.gDrop.drop(aDropTarget, event, function () executeSoon(TestRunner.next));
 
   if (aDragSource)
     cw.gDrag.end(aDragSource.site);
 }
+
+/**
+ * Resumes testing when all pages have been updated.
+ */
+function whenPagesUpdated() {
+  let page = {
+    update: function () {
+      NewTabUtils.allPages.unregister(this);
+      executeSoon(TestRunner.next);
+    }
+  };
+
+  NewTabUtils.allPages.register(page);
+  registerCleanupFunction(function () {
+    NewTabUtils.allPages.unregister(page);
+  });
+}
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -39,17 +39,33 @@
 #
 # ***** END LICENSE BLOCK *****
 
 // Services = object with smart getters for common XPCOM services
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "BROWSER_NEW_TAB_URL", function () {
-  return Services.prefs.getCharPref("browser.newtab.url") || "about:blank";
+  const PREF = "browser.newtab.url";
+
+  function getNewTabPageURL() {
+    return Services.prefs.getCharPref(PREF) || "about:blank";
+  }
+
+  function update() {
+    BROWSER_NEW_TAB_URL = getNewTabPageURL();
+  }
+
+  Services.prefs.addObserver(PREF, update, false);
+  addEventListener("unload", function onUnload() {
+    removeEventListener("unload", onUnload);
+    Services.prefs.removeObserver(PREF, update);
+  });
+
+  return getNewTabPageURL();
 });
 
 var TAB_DROP_TYPE = "application/x-moz-tabbrowser-tab";
 
 var gBidiUI = false;
 
 /**
  * Determines whether the given url is considered a special URL for new tabs.
--- a/browser/build.mk
+++ b/browser/build.mk
@@ -93,16 +93,22 @@ distclean::
 	@$(MAKE) -C browser/installer distclean
 
 source-package::
 	@$(MAKE) -C browser/installer source-package
 
 upload::
 	@$(MAKE) -C browser/installer upload
 
+source-upload::
+	@$(MAKE) -C browser/installer source-upload
+
+hg-bundle::
+	@$(MAKE) -C browser/installer hg-bundle
+
 l10n-check::
 	@$(MAKE) -C browser/locales l10n-check
 
 ifdef ENABLE_TESTS
 # Implemented in testing/testsuite-targets.mk
 
 mochitest-browser-chrome:
 	$(RUN_MOCHITEST) --browser-chrome
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -62,16 +62,19 @@ XPCOMUtils.defineLazyGetter(this, "NetUt
 XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() {
   Cu.import("resource://gre/modules/PlacesUtils.jsm");
   return PlacesUtils;
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "KeywordURLResetPrompter",
                                   "resource:///modules/KeywordURLResetPrompter.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "webappsUI", 
+                                  "resource://gre/modules/webappsUI.jsm");
+
 const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
 const PREF_PLUGINS_UPDATEURL  = "plugins.update.url";
 
 // We try to backup bookmarks at idle times, to avoid doing that at shutdown.
 // Number of idle seconds before trying to backup bookmarks.  15 minutes.
 const BOOKMARKS_BACKUP_IDLE_TIME = 15 * 60;
 // Minimum interval in milliseconds between backups.
 const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000;
@@ -341,16 +344,17 @@ BrowserGlue.prototype = {
       this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
     if (this._isPlacesInitObserver)
       os.removeObserver(this, "places-init-complete");
     if (this._isPlacesLockedObserver)
       os.removeObserver(this, "places-database-locked");
     if (this._isPlacesShutdownObserver)
       os.removeObserver(this, "places-shutdown");
     os.removeObserver(this, "defaultURIFixup-using-keyword-pref");
+    webappsUI.uninit();
   },
 
   _onAppDefaults: function BG__onAppDefaults() {
     // apply distribution customizations (prefs)
     // other customizations are applied in _onProfileStartup()
     this._distributionCustomizer.applyPrefDefaults();
   },
 
@@ -365,16 +369,19 @@ BrowserGlue.prototype = {
 
     // apply distribution customizations
     // prefs are applied in _onAppDefaults()
     this._distributionCustomizer.applyCustomizations();
 
     // handle any UI migration
     this._migrateUI();
 
+    // Initialize webapps UI
+    webappsUI.init();
+
     Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
   },
 
   // the first browser window has finished initializing
   _onFirstWindowLoaded: function BG__onFirstWindowLoaded() {
 #ifdef XP_WIN
     // For windows seven, initialize the jump list module.
     const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
@@ -400,17 +407,16 @@ BrowserGlue.prototype = {
       this._showRightsNotification();
 #ifdef MOZ_TELEMETRY_REPORTING
     } else {
       // Only show telemetry notification when about:rights notification is not shown.
       this._showTelemetryNotification();
 #endif
     }
 
-
     // Show update notification, if needed.
     if (Services.prefs.prefHasUserValue("app.update.postupdate"))
       this._showUpdateNotification();
 
     // Load the "more info" page for a locked places.sqlite
     // This property is set earlier by places-database-locked topic.
     if (this._isPlacesDatabaseLocked) {
       this._showPlacesLockedNotificationBox();
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -371,41 +371,36 @@ PlacesViewBase.prototype = {
    * @param aPopup
    *        The livemark container popup
    * @param aStatus
    *        The livemark status
    */
   _setLivemarkStatusMenuItem:
   function PVB_setLivemarkStatusMenuItem(aPopup, aStatus) {
     let statusMenuitem = aPopup._statusMenuitem;
-    let stringId = "";
-    if (aStatus == Ci.mozILivemark.STATUS_LOADING)
-      stringId = "bookmarksLivemarkLoading";
-    else if (aStatus == Ci.mozILivemark.STATUS_FAILED)
-      stringId = "bookmarksLivemarkFailed";
-
-    if (stringId && !statusMenuitem) {
+    if (!statusMenuitem) {
       // Create the status menuitem and cache it in the popup object.
       statusMenuitem = document.createElement("menuitem");
-      statusMenuitem.setAttribute("livemarkStatus", stringId);
       statusMenuitem.className = "livemarkstatus-menuitem";
-      statusMenuitem.setAttribute("label", PlacesUIUtils.getString(stringId));
       statusMenuitem.setAttribute("disabled", true);
-      aPopup.insertBefore(statusMenuitem, aPopup._startMarker.nextSibling);
       aPopup._statusMenuitem = statusMenuitem;
     }
-    else if (stringId &&
-             statusMenuitem.getAttribute("livemarkStatus") != stringId) {
+
+    if (aStatus == Ci.mozILivemark.STATUS_LOADING ||
+        aStatus == Ci.mozILivemark.STATUS_FAILED) {
       // Status has changed, update the cached status menuitem.
+      let stringId = aStatus == Ci.mozILivemark.STATUS_LOADING ?
+                       "bookmarksLivemarkLoading" : "bookmarksLivemarkFailed";
       statusMenuitem.setAttribute("label", PlacesUIUtils.getString(stringId));
+      if (aPopup._startMarker.nextSibling != statusMenuitem)
+        aPopup.insertBefore(statusMenuitem, aPopup._startMarker.nextSibling);
     }
-    else if (!stringId && statusMenuitem) {
+    else {
       // The livemark has finished loading.
       aPopup.removeChild(aPopup._statusMenuitem);
-      aPopup._statusMenuitem = null;
     }
   },
 
   toggleCutNode: function PVB_toggleCutNode(aNode, aValue) {
     let elt = aNode._DOMElement;
     if (elt) {
       // We may get the popup for menus, but we need the menu itself.
       if (elt.localName == "menupopup")
@@ -887,16 +882,24 @@ function PlacesToolbar(aPlace) {
 
   this._viewElt._placesView = this;
 
   this._addEventListeners(this._viewElt, this._cbEvents, false);
   this._addEventListeners(this._rootElt, ["popupshowing", "popuphidden"], true);
   this._addEventListeners(this._rootElt, ["overflow", "underflow"], true);
   this._addEventListeners(window, ["resize", "unload"], false);
 
+  // If personal-bookmarks has been dragged to the tabs toolbar,
+  // we have to track addition and removals of tabs, to properly
+  // recalculate the available space for bookmarks.
+  // TODO (bug 734730): Use a performant mutation listener when available.
+  if (this._viewElt.parentNode.parentNode == document.getElementById("TabsToolbar")) {
+    this._addEventListeners(gBrowser.tabContainer, ["TabOpen", "TabClose"], false);
+  }
+
   PlacesViewBase.call(this, aPlace);
 
   Services.telemetry.getHistogramById("FX_BOOKMARKS_TOOLBAR_INIT_MS")
                     .add(Date.now() - startTime);
 }
 
 PlacesToolbar.prototype = {
   __proto__: PlacesViewBase.prototype,
@@ -913,16 +916,17 @@ PlacesToolbar.prototype = {
   },
 
   uninit: function PT_uninit() {
     this._removeEventListeners(this._viewElt, this._cbEvents, false);
     this._removeEventListeners(this._rootElt, ["popupshowing", "popuphidden"],
                                true);
     this._removeEventListeners(this._rootElt, ["overflow", "underflow"], true);
     this._removeEventListeners(window, ["resize", "unload"], false);
+    this._removeEventListeners(gBrowser.tabContainer, ["TabOpen", "TabClose"], false);
 
     PlacesViewBase.prototype.uninit.apply(this, arguments);
   },
 
   _openedMenuButton: null,
   _allowPopupShowing: true,
 
   _rebuild: function PT__rebuild() {
@@ -1012,19 +1016,20 @@ PlacesToolbar.prototype = {
     if (aBefore)
       this._rootElt.insertBefore(button, aBefore);
     else
       this._rootElt.appendChild(button);
   },
 
   _updateChevronPopupNodesVisibility:
   function PT__updateChevronPopupNodesVisibility() {
-    for (let i = 0; i < this._chevronPopup.childNodes.length; i++) {
-      this._chevronPopup.childNodes[i].hidden =
-        this._rootElt.childNodes[i].style.visibility != "hidden";
+    for (let i = 0, node = this._chevronPopup._startMarker.nextSibling;
+         node != this._chevronPopup._endMarker;
+         i++, node = node.nextSibling) {
+      node.hidden = this._rootElt.childNodes[i].style.visibility != "hidden";
     }
   },
 
   _onChevronPopupShowing:
   function PT__onChevronPopupShowing(aEvent) {
     // Handle popupshowing only for the chevron popup, not for nested ones.
     if (aEvent.target != this._chevronPopup)
       return;
@@ -1066,17 +1071,21 @@ PlacesToolbar.prototype = {
       case "underflow":
         if (aEvent.target != aEvent.currentTarget)
           return;
 
         // Ignore purely vertical underflows.
         if (aEvent.detail == 0)
           return;
 
+        this.updateChevron();
         this._chevron.collapsed = true;
+        break;
+      case "TabOpen":
+      case "TabClose":
         this.updateChevron();
         break;
       case "dragstart":
         this._onDragStart(aEvent);
         break;
       case "dragover":
         this._onDragOver(aEvent);
         break;
--- a/browser/components/thumbnails/PageThumbs.jsm
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -13,25 +13,25 @@ const Ci = Components.interfaces;
 const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
 
 /**
  * The default width for page thumbnails.
  *
  * Hint: This is the default value because the 'New Tab Page' is the only
  *       client for now.
  */
-const THUMBNAIL_WIDTH = 201;
+const THUMBNAIL_WIDTH = 400;
 
 /**
  * The default height for page thumbnails.
  *
  * Hint: This is the default value because the 'New Tab Page' is the only
  *       client for now.
  */
-const THUMBNAIL_HEIGHT = 127;
+const THUMBNAIL_HEIGHT = 225;
 
 /**
  * The default background color for page thumbnails.
  */
 const THUMBNAIL_BG_COLOR = "#fff";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
--- a/browser/config/mozconfigs/linux32/debug
+++ b/browser/config/mozconfigs/linux32/debug
@@ -13,8 +13,11 @@ export MOZILLA_OFFICIAL=1
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 #Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/linux32/nightly
+++ b/browser/config/mozconfigs/linux32/nightly
@@ -22,8 +22,11 @@ mk_add_options PROFILE_GEN_SCRIPT='$(PYT
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 #Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/linux32/release
+++ b/browser/config/mozconfigs/linux32/release
@@ -16,8 +16,11 @@ export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/linux64/debug
+++ b/browser/config/mozconfigs/linux64/debug
@@ -10,8 +10,11 @@ ac_add_options --enable-stdcxx-compat
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/linux64/nightly
+++ b/browser/config/mozconfigs/linux64/nightly
@@ -22,8 +22,11 @@ mk_add_options PROFILE_GEN_SCRIPT='$(PYT
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 #Use ccache
 ac_add_options --with-ccache=/usr/bin/ccache
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/linux64/release
+++ b/browser/config/mozconfigs/linux64/release
@@ -16,8 +16,11 @@ export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/macosx-universal/nightly
+++ b/browser/config/mozconfigs/macosx-universal/nightly
@@ -17,8 +17,11 @@ export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/macosx-universal/release
+++ b/browser/config/mozconfigs/macosx-universal/release
@@ -12,8 +12,11 @@ export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/macosx32/debug
+++ b/browser/config/mozconfigs/macosx32/debug
@@ -5,8 +5,11 @@ ac_add_options --enable-signmar
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/macosx64/debug
+++ b/browser/config/mozconfigs/macosx64/debug
@@ -10,8 +10,11 @@ mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -3,8 +3,11 @@ ac_add_options --enable-trace-malloc
 ac_add_options --enable-signmar
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 mk_add_options MOZ_MAKE_FLAGS=-j1
 
 . $topsrcdir/browser/config/mozconfigs/win32/vs2010-mozconfig
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/win32/nightly
+++ b/browser/config/mozconfigs/win32/nightly
@@ -12,8 +12,11 @@ ac_add_options --enable-js-diagnostics
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 mk_add_options MOZ_MAKE_FLAGS=-j1
 
 . $topsrcdir/browser/config/mozconfigs/win32/vs2010-mozconfig
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/win32/release
+++ b/browser/config/mozconfigs/win32/release
@@ -8,8 +8,11 @@ ac_add_options --enable-jemalloc
 ac_add_options --enable-official-branding
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 . $topsrcdir/browser/config/mozconfigs/win32/vs2010-mozconfig
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/win64/debug
+++ b/browser/config/mozconfigs/win64/debug
@@ -4,8 +4,13 @@ ac_add_options --host=x86_64-pc-mingw32
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-signmar
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 mk_add_options MOZ_MAKE_FLAGS=-j1
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
+
+. $topsrcdir/browser/config/mozconfigs/win64/vs2010-mozconfig
--- a/browser/config/mozconfigs/win64/nightly
+++ b/browser/config/mozconfigs/win64/nightly
@@ -13,8 +13,13 @@ ac_add_options --enable-signmar
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 mk_add_options MOZ_MAKE_FLAGS=-j1
+
+# Package js shell.
+export MOZ_PACKAGE_JSSHELL=1
+
+. $topsrcdir/browser/config/mozconfigs/win64/vs2010-mozconfig
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/win64/vs2010-mozconfig
@@ -0,0 +1,16 @@
+export INCLUDE=/c/tools/msvs10/vc/include:/c/tools/msvs10/vc/atlmfc/include:/c/tools/sdks/v7.0/include:/c/tools/sdks/v7.0/include/atl:/c/tools/sdks/dx10/include
+export LIBPATH=/c/tools/msvs10/vc/lib/amd64:/c/tools/msvs10/vc/atlmfc/lib/amd64
+export LIB=/c/tools/msvs10/vc/lib/amd64:/c/tools/msvs10/vc/atlmfc/lib/amd64:/c/tools/sdks/v7.0/lib/x64:/c/tools/sdks/dx10/lib/x64
+export PATH="/c/tools/msvs10/Common7/IDE:/c/tools/msvs10/VC/BIN/amd64:/c/tools/msvs10/VC/BIN/x86_amd64:/c/tools/msvs10/VC/BIN:/c/tools/msvs10/Common7/Tools:/c/tools/msvs10/VC/VCPackages:${PATH}"
+export WIN32_REDIST_DIR=/c/tools/msvs10/VC/redist/x64/Microsoft.VC100.CRT
+
+# Use 32bit linker for PGO crash bug.
+# https://connect.microsoft.com/VisualStudio/feedback/details/686117/
+export LD=/c/tools/msvs10/VC/BIN/x86_amd64/link.exe
+
+
+mk_add_options "export LIB=$LIB"
+mk_add_options "export LIBPATH=$LIBPATH"
+mk_add_options "export PATH=$PATH"
+mk_add_options "export INCLUDE=$INCLUDE"
+mk_add_options "export WIN32_REDIST_DIR=$WIN32_REDIST_DIR"
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -66,33 +66,35 @@ include $(topsrcdir)/config/rules.mk
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_location-changes.js \
 	browser_dbg_script-switching.js \
 	browser_dbg_pause-resume.js \
 	browser_dbg_update-editor-mode.js \
-	browser_dbg_select-line.js \
+	$(warning browser_dbg_select-line.js temporarily disabled due to oranges, see bug 726609) \
 	browser_dbg_clean-exit.js \
 	browser_dbg_bug723069_editor-breakpoints.js \
 	browser_dbg_bug731394_editor-contextmenu.js \
+	browser_dbg_displayName.js \
 	head.js \
 	$(NULL)
 
 _BROWSER_TEST_PAGES = \
 	browser_dbg_tab1.html \
 	browser_dbg_tab2.html \
 	browser_dbg_debuggerstatement.html \
 	browser_dbg_stack.html \
 	browser_dbg_script-switching.html \
 	test-script-switching-01.js \
 	test-script-switching-02.js \
 	browser_dbg_frame-parameters.html \
 	browser_dbg_update-editor-mode.html \
 	test-editor-mode \
+	browser_dbg_displayName.html \
 	$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
 
 libs:: $(_BROWSER_TEST_PAGES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_displayName.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head><title>Browser Debugger Test Tab</title>
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<script type="text/javascript">
+
+var a = function() {
+  return function() {
+    debugger;
+  }
+}
+
+var anon = a();
+anon.displayName = "anonFunc";
+
+function evalCall() {
+  eval("anon();");
+}
+
+</script>
+</head>
+
+<body></body>
+
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_displayName.js
@@ -0,0 +1,53 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var gPane = null;
+var gTab = null;
+var gDebuggee = null;
+var gDebugger = null;
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_displayName.html";
+
+function test() {
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.debuggerWindow;
+
+    testAnonCall();
+  });
+}
+
+function testAnonCall() {
+  gPane.activeThread.addOneTimeListener("framesadded", function() {
+    Services.tm.currentThread.dispatch({ run: function() {
+
+      let frames = gDebugger.DebuggerView.Stackframes._frames;
+
+      is(gDebugger.StackFrames.activeThread.state, "paused",
+        "Should only be getting stack frames while paused.");
+
+      is(frames.querySelectorAll(".dbg-stackframe").length, 3,
+        "Should have three frames.");
+
+      is(frames.querySelector("#stackframe-0 .dbg-stackframe-name").textContent,
+        "anonFunc", "Frame name should be anonFunc");
+
+      resumeAndFinish();
+    }}, 0);
+  });
+
+  gDebuggee.evalCall();
+}
+
+function resumeAndFinish() {
+  gDebugger.StackFrames.activeThread.resume(function() {
+    removeTab(gTab);
+    gPane = null;
+    gDebuggee = null;
+    finish();
+  });
+}
--- a/browser/devtools/highlighter/TreePanel.jsm
+++ b/browser/devtools/highlighter/TreePanel.jsm
@@ -304,92 +304,107 @@ TreePanel.prototype = {
           this.IUI.highlighter.highlight(node);
         }
       }
     }
   },
 
   /**
    * Handle double-click events in the html tree panel.
-   * (double-clicking an attribute value allows it to be edited)
+   * Double-clicking an attribute name or value allows it to be edited.
    * @param aEvent
    *        The mouse event.
    */
   onTreeDblClick: function TP_onTreeDblClick(aEvent)
   {
     // if already editing an attribute value, double-clicking elsewhere
     // in the tree is the same as a click, which dismisses the editor
     if (this.editingContext)
       this.closeEditor();
 
     let target = aEvent.target;
 
+    if (!this.hasClass(target, "editable")) {
+      return;
+    }
+
+    let repObj = this.getRepObject(target);
+
     if (this.hasClass(target, "nodeValue")) {
-      let repObj = this.getRepObject(target);
       let attrName = target.getAttribute("data-attributeName");
       let attrVal = target.innerHTML;
 
-      this.editAttributeValue(target, repObj, attrName, attrVal);
+      this.editAttribute(target, repObj, attrName, attrVal);
+    }
+
+    if (this.hasClass(target, "nodeName")) {
+      let attrName = target.innerHTML;
+      let attrValNode = target.nextSibling.nextSibling; // skip 2 (=)
+
+      if (attrValNode)
+        this.editAttribute(target, repObj, attrName, attrValNode.innerHTML);
     }
   },
 
   /**
-   * Starts the editor for an attribute value.
+   * Starts the editor for an attribute name or value.
    * @param aAttrObj
-   *        The DOM object representing the attribute value in the HTML Tree
+   *        The DOM object representing the attribute name or value in the HTML
+   *        Tree.
    * @param aRepObj
    *        The original DOM (target) object being inspected/edited
    * @param aAttrName
    *        The name of the attribute being edited
    * @param aAttrVal
    *        The current value of the attribute being edited
    */
-  editAttributeValue:
-  function TP_editAttributeValue(aAttrObj, aRepObj, aAttrName, aAttrVal)
+  editAttribute:
+  function TP_editAttribute(aAttrObj, aRepObj, aAttrName, aAttrVal)
   {
     let editor = this.treeBrowserDocument.getElementById("attribute-editor");
     let editorInput =
       this.treeBrowserDocument.getElementById("attribute-editor-input");
     let attrDims = aAttrObj.getBoundingClientRect();
     // figure out actual viewable viewport dimensions (sans scrollbars)
     let viewportWidth = this.treeBrowserDocument.documentElement.clientWidth;
     let viewportHeight = this.treeBrowserDocument.documentElement.clientHeight;
 
     // saves the editing context for use when the editor is saved/closed
     this.editingContext = {
       attrObj: aAttrObj,
       repObj: aRepObj,
-      attrName: aAttrName
+      attrName: aAttrName,
+      attrValue: aAttrVal
     };
 
     // highlight attribute-value node in tree while editing
     this.addClass(aAttrObj, "editingAttributeValue");
 
     // show the editor
     this.addClass(editor, "editing");
 
     // offset the editor below the attribute-value node being edited
-    let editorVeritcalOffset = 2;
+    let editorVerticalOffset = 2;
 
     // keep the editor comfortably within the bounds of the viewport
     let editorViewportBoundary = 5;
 
     // outer editor is sized based on the <input> box inside it
     editorInput.style.width = Math.min(attrDims.width, viewportWidth -
                                 editorViewportBoundary) + "px";
     editorInput.style.height = Math.min(attrDims.height, viewportHeight -
                                 editorViewportBoundary) + "px";
     let editorDims = editor.getBoundingClientRect();
 
     // calculate position for the editor according to the attribute node
     let editorLeft = attrDims.left + this.treeIFrame.contentWindow.scrollX -
                     // center the editor against the attribute value
                     ((editorDims.width - attrDims.width) / 2);
     let editorTop = attrDims.top + this.treeIFrame.contentWindow.scrollY +
-                    attrDims.height + editorVeritcalOffset;
+                    attrDims.height + editorVerticalOffset;
 
     // but, make sure the editor stays within the visible viewport
     editorLeft = Math.max(0, Math.min(
                                       (this.treeIFrame.contentWindow.scrollX +
                                           viewportWidth - editorDims.width),
                                       editorLeft)
                           );
     editorTop = Math.max(0, Math.min(
@@ -398,18 +413,23 @@ TreePanel.prototype = {
                                       editorTop)
                           );
 
     // position the editor
     editor.style.left = editorLeft + "px";
     editor.style.top = editorTop + "px";
 
     // set and select the text
-    editorInput.value = aAttrVal;
-    editorInput.select();
+    if (this.hasClass(aAttrObj, "nodeValue")) {
+      editorInput.value = aAttrVal;
+      editorInput.select();
+    } else {
+      editorInput.value = aAttrName;
+      editorInput.select();
+    }
 
     // listen for editor specific events
     this.bindEditorEvent(editor, "click", function(aEvent) {
       aEvent.stopPropagation();
     });
     this.bindEditorEvent(editor, "dblclick", function(aEvent) {
       aEvent.stopPropagation();
     });
@@ -505,25 +525,42 @@ TreePanel.prototype = {
 
   /**
    * Commit the edits made in the editor, then close it.
    */
   saveEditor: function TP_saveEditor()
   {
     let editorInput =
       this.treeBrowserDocument.getElementById("attribute-editor-input");
+    let dirty = false;
 
-    // set the new attribute value on the original target DOM element
-    this.editingContext.repObj.setAttribute(this.editingContext.attrName,
-                                              editorInput.value);
+    if (this.hasClass(this.editingContext.attrObj, "nodeValue")) {
+      // set the new attribute value on the original target DOM element
+      this.editingContext.repObj.setAttribute(this.editingContext.attrName,
+                                                editorInput.value);
+
+      // update the HTML tree attribute value
+      this.editingContext.attrObj.innerHTML = editorInput.value;
+      dirty = true;
+    }
 
-    // update the HTML tree attribute value
-    this.editingContext.attrObj.innerHTML = editorInput.value;
+    if (this.hasClass(this.editingContext.attrObj, "nodeName")) {
+      // remove the original attribute from the original target DOM element
+      this.editingContext.repObj.removeAttribute(this.editingContext.attrName);
 
-    this.IUI.isDirty = true;
+      // set the new attribute value on the original target DOM element
+      this.editingContext.repObj.setAttribute(editorInput.value,
+                                              this.editingContext.attrValue);
+
+      // update the HTML tree attribute value
+      this.editingContext.attrObj.innerHTML = editorInput.value;
+      dirty = true;
+    }
+
+    this.IUI.isDirty = dirty;
     this.IUI.nodeChanged(this.registrationObject);
 
     // event notification
     Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
                                   null);
 
     this.closeEditor();
   },
--- a/browser/devtools/highlighter/inspector.jsm
+++ b/browser/devtools/highlighter/inspector.jsm
@@ -22,16 +22,17 @@
  *
  * Contributor(s):
  *   Rob Campbell <rcampbell@mozilla.com> (original author)
  *   Mihai Șucan <mihai.sucan@gmail.com>
  *   Julian Viereck <jviereck@mozilla.com>
  *   Paul Rouget <paul@mozilla.com>
  *   Kyle Simpson <ksimpson@mozilla.com>
  *   Johan Charlez <johan.charlez@gmail.com>
+ *   Mike Ratcliffe <mratcliffe@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -99,16 +100,25 @@ function InspectorUI(aWindow)
 {
   this.chromeWin = aWindow;
   this.chromeDoc = aWindow.document;
   this.tabbrowser = aWindow.gBrowser;
   this.tools = {};
   this.toolEvents = {};
   this.store = new InspectorStore();
   this.INSPECTOR_NOTIFICATIONS = INSPECTOR_NOTIFICATIONS;
+
+  // Set the tooltip of the inspect button.
+  let keysbundle = Services.strings.createBundle(
+    "chrome://global/locale/keys.properties");
+  let returnString = keysbundle.GetStringFromName("VK_RETURN");
+  let tooltip = this.strings.formatStringFromName("inspectButton.tooltiptext",
+    [returnString], 1);
+  let button = this.chromeDoc.getElementById("inspector-inspect-toolbutton");
+  button.setAttribute("tooltiptext", tooltip);
 }
 
 InspectorUI.prototype = {
   browser: null,
   tools: null,
   toolEvents: null,
   inspecting: false,
   ruleViewEnabled: true,
@@ -840,30 +850,26 @@ InspectorUI.prototype = {
   },
 
   /**
    * Copy the innerHTML of the selected Node to the clipboard. Called via the
    * Inspector:CopyInner command.
    */
   copyInnerHTML: function IUI_copyInnerHTML()
   {
-    let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
-                    getService(Ci.nsIClipboardHelper);
-    clipboard.copyString(this.selection.innerHTML);
+    clipboardHelper.copyString(this.selection.innerHTML);
   },
 
   /**
    * Copy the outerHTML of the selected Node to the clipboard. Called via the
    * Inspector:CopyOuter command.
    */
   copyOuterHTML: function IUI_copyOuterHTML()
   {
-    let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
-                    getService(Ci.nsIClipboardHelper);
-    clipboard.copyString(this.selection.outerHTML);
+    clipboardHelper.copyString(this.selection.outerHTML);
   },
 
   /**
    * Delete the selected node. Called via the Inspector:DeleteNode command.
    */
   deleteNode: function IUI_deleteNode()
   {
     let selection = this.selection;
@@ -921,22 +927,44 @@ InspectorUI.prototype = {
       let ruleViewStore = this.store.getValue(winID, "ruleView");
       if (!ruleViewStore) {
         ruleViewStore = {};
         this.store.setValue(winID, "ruleView", ruleViewStore);
       }
 
       this.ruleView = new CssRuleView(doc, ruleViewStore);
 
+      // Add event handlers bound to this.
       this.boundRuleViewChanged = this.ruleViewChanged.bind(this);
       this.ruleView.element.addEventListener("CssRuleViewChanged",
                                              this.boundRuleViewChanged);
       this.cssRuleViewBoundCSSLinkClicked = this.ruleViewCSSLinkClicked.bind(this);
       this.ruleView.element.addEventListener("CssRuleViewCSSLinkClicked",
                                              this.cssRuleViewBoundCSSLinkClicked);
+      this.cssRuleViewBoundMouseDown = this.ruleViewMouseDown.bind(this);
+      this.ruleView.element.addEventListener("mousedown",
+                                             this.cssRuleViewBoundMouseDown);
+      this.cssRuleViewBoundMouseUp = this.ruleViewMouseUp.bind(this);
+      this.ruleView.element.addEventListener("mouseup",
+                                             this.cssRuleViewBoundMouseUp);
+      this.cssRuleViewBoundMouseMove = this.ruleViewMouseMove.bind(this);
+      this.cssRuleViewBoundMenuUpdate = this.ruleViewMenuUpdate.bind(this);
+
+      this.cssRuleViewBoundCopy = this.ruleViewCopy.bind(this);
+      iframe.addEventListener("copy", this.cssRuleViewBoundCopy);
+
+      this.cssRuleViewBoundCopyRule = this.ruleViewCopyRule.bind(this);
+      this.cssRuleViewBoundCopyDeclaration =
+        this.ruleViewCopyDeclaration.bind(this);
+      this.cssRuleViewBoundCopyProperty = this.ruleViewCopyProperty.bind(this);
+      this.cssRuleViewBoundCopyPropertyValue =
+        this.ruleViewCopyPropertyValue.bind(this);
+
+      // Add the rule view's context menu.
+      this.ruleViewAddContextMenu();
 
       doc.documentElement.appendChild(this.ruleView.element);
       this.ruleView.highlight(this.selection);
       Services.obs.notifyObservers(null,
         INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, null);
     }.bind(this);
 
     iframe.addEventListener("load", boundLoadListener, true);
@@ -998,28 +1026,365 @@ InspectorUI.prototype = {
       this.chromeWin.StyleEditor.openChrome(styleSheet, rule.ruleLine);
     } else {
       let href = rule.elementStyle.element.ownerDocument.location.href;
       this.chromeWin.openUILinkIn("view-source:" + href, "window");
     }
   },
 
   /**
+   * This is the mousedown handler for the rule view. We use it to track whether
+   * text is currently getting selected.
+   * .
+   * @param aEvent The event object
+   */
+  ruleViewMouseDown: function IUI_ruleViewMouseDown(aEvent)
+  {
+    this.ruleView.element.addEventListener("mousemove",
+      this.cssRuleViewBoundMouseMove);
+  },
+
+  /**
+   * This is the mouseup handler for the rule view. We use it to track whether
+   * text is currently getting selected.
+   * .
+   * @param aEvent The event object
+   */
+  ruleViewMouseUp: function IUI_ruleViewMouseUp(aEvent)
+  {
+    this.ruleView.element.removeEventListener("mousemove",
+      this.cssRuleViewBoundMouseMove);
+    this.ruleView._selectionMode = false;
+  },
+
+  /**
+   * This is the mousemove handler for the rule view. We use it to track whether
+   * text is currently getting selected.
+   * .
+   * @param aEvent The event object
+   */
+  ruleViewMouseMove: function IUI_ruleViewMouseMove(aEvent)
+  {
+    this.ruleView._selectionMode = true;
+  },
+
+  /**
+   * Add a context menu to the rule view.
+   */
+  ruleViewAddContextMenu: function IUI_ruleViewAddContextMenu()
+  {
+    let iframe = this.getToolIframe(this.ruleViewObject);
+    let popupSet = this.chromeDoc.getElementById("mainPopupSet");
+    let menu = this.chromeDoc.createElement("menupopup");
+    menu.addEventListener("popupshowing", this.cssRuleViewBoundMenuUpdate);
+    menu.id = "rule-view-context-menu";
+
+    // Copy selection
+    let label = styleInspectorStrings
+      .GetStringFromName("rule.contextmenu.copyselection");
+    let accessKey = styleInspectorStrings
+      .GetStringFromName("rule.contextmenu.copyselection.accesskey");
+    let item = this.chromeDoc.createElement("menuitem");
+    item.id = "rule-view-copy";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.cssRuleViewBoundCopy);
+    menu.appendChild(item);
+
+    // Copy rule
+    label = styleInspectorStrings.
+      GetStringFromName("rule.contextmenu.copyrule");
+    accessKey = styleInspectorStrings.
+      GetStringFromName("rule.contextmenu.copyrule.accesskey");
+    item = this.chromeDoc.createElement("menuitem");
+    item.id = "rule-view-copy-rule";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.cssRuleViewBoundCopyRule);
+    menu.appendChild(item);
+
+    // Copy declaration
+    label = styleInspectorStrings.
+      GetStringFromName("rule.contextmenu.copydeclaration");
+    accessKey = styleInspectorStrings.
+      GetStringFromName("rule.contextmenu.copydeclaration.accesskey");
+    item = this.chromeDoc.createElement("menuitem");
+    item.id = "rule-view-copy-declaration";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.cssRuleViewBoundCopyDeclaration);
+    menu.appendChild(item);
+
+    // Copy property name
+    label = styleInspectorStrings.
+      GetStringFromName("rule.contextmenu.copyproperty");
+    accessKey = styleInspectorStrings.
+      GetStringFromName("rule.contextmenu.copyproperty.accesskey");
+    item = this.chromeDoc.createElement("menuitem");
+    item.id = "rule-view-copy-property";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.cssRuleViewBoundCopyProperty);
+    menu.appendChild(item);
+
+    // Copy property value
+    label = styleInspectorStrings.
+      GetStringFromName("rule.contextmenu.copypropertyvalue");
+    accessKey = styleInspectorStrings.
+      GetStringFromName("rule.contextmenu.copypropertyvalue.accesskey");
+    item = this.chromeDoc.createElement("menuitem");
+    item.id = "rule-view-copy-property-value";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.cssRuleViewBoundCopyPropertyValue);
+    menu.appendChild(item);
+
+    popupSet.appendChild(menu);
+
+    iframe.setAttribute("context", menu.id);
+  },
+
+  /**
+   * Update the rule view's context menu by disabling irrelevant menuitems and
+   * enabling relevant ones.
+   *
+   * @param aEvent The event object
+   */
+  ruleViewMenuUpdate: function IUI_ruleViewMenuUpdate(aEvent)
+  {
+    let iframe = this.getToolIframe(this.ruleViewObject);
+    let win = iframe.contentWindow;
+
+    // Copy selection.
+    let disable = win.getSelection().isCollapsed;
+    let menuitem = this.chromeDoc.getElementById("rule-view-copy");
+    menuitem.disabled = disable;
+
+    // Copy property, copy property name & copy property value.
+    let node = this.chromeDoc.popupNode;
+    if (!node.classList.contains("ruleview-property") &&
+        !node.classList.contains("ruleview-computed")) {
+      while (node = node.parentElement) {
+        if (node.classList.contains("ruleview-property") ||
+          node.classList.contains("ruleview-computed")) {
+          break;
+        }
+      }
+    }
+    let disablePropertyItems = !node || (node &&
+      !node.classList.contains("ruleview-property") &&
+      !node.classList.contains("ruleview-computed"));
+
+    menuitem = this.chromeDoc.querySelector("#rule-view-copy-declaration");
+    menuitem.disabled = disablePropertyItems;
+    menuitem = this.chromeDoc.querySelector("#rule-view-copy-property");
+    menuitem.disabled = disablePropertyItems;
+    menuitem = this.chromeDoc.querySelector("#rule-view-copy-property-value");
+    menuitem.disabled = disablePropertyItems;
+  },
+
+  /**
+   * Copy selected text from the rule view.
+   *
+   * @param aEvent The event object
+   */
+  ruleViewCopy: function IUI_ruleViewCopy(aEvent)
+  {
+    let iframe = this.getToolIframe(this.ruleViewObject);
+    let win = iframe.contentWindow;
+    let text = win.getSelection().toString();
+
+    // Remove any double newlines.
+    text = text.replace(/(\r?\n)\r?\n/g, "$1");
+
+    // Remove "inline"
+    let inline = styleInspectorStrings.GetStringFromName("rule.sourceInline");
+    let rx = new RegExp("^" + inline + "\\r?\\n?", "g");
+    text = text.replace(rx, "");
+
+    // Remove file:line
+    text = text.replace(/[\w\.]+:\d+(\r?\n)/g, "$1");
+
+    // Remove inherited from: line
+    let inheritedFrom = styleInspectorStrings
+      .GetStringFromName("rule.inheritedSource");
+    inheritedFrom = inheritedFrom.replace(/\s%S\s\(%S\)/g, "");
+    rx = new RegExp("(\r?\n)" + inheritedFrom + ".*", "g");
+    text = text.replace(rx, "$1");
+
+    clipboardHelper.copyString(text);
+
+    if (aEvent) {
+      aEvent.preventDefault();
+    }
+  },
+
+  /**
+   * Copy a rule from the rule view.
+   *
+   * @param aEvent The event object
+   */
+  ruleViewCopyRule: function IUI_ruleViewCopyRule(aEvent)
+  {
+    let node = this.chromeDoc.popupNode;
+    if (node.className != "ruleview-code") {
+      if (node.className == "ruleview-rule-source") {
+        node = node.nextElementSibling;
+      } else {
+        while (node = node.parentElement) {
+          if (node.className == "ruleview-code") {
+            break;
+          }
+        }
+      }
+    }
+
+    if (node.className == "ruleview-code") {
+      // We need to strip expanded properties from the node because we use
+      // node.textContent below, which also gets text from hidden nodes. The
+      // simplest way to do this is to clone the node and remove them from the
+      // clone.
+      node = node.cloneNode();
+      let computed = node.querySelector(".ruleview-computedlist");
+      if (computed) {
+        computed.parentNode.removeChild(computed);
+      }
+    }
+
+    let text = node.textContent;
+
+    // Format the rule
+    if (osString == "WINNT") {
+      text = text.replace(/{/g, "{\r\n    ");
+      text = text.replace(/;/g, ";\r\n    ");
+      text = text.replace(/\s*}/g, "\r\n}");
+    } else {
+      text = text.replace(/{/g, "{\n    ");
+      text = text.replace(/;/g, ";\n    ");
+      text = text.replace(/\s*}/g, "\n}");
+    }
+
+    clipboardHelper.copyString(text);
+  },
+
+  /**
+   * Copy a declaration from the rule view.
+   *
+   * @param aEvent The event object
+   */
+  ruleViewCopyDeclaration: function IUI_ruleViewCopyDeclaration(aEvent)
+  {
+    let node = this.chromeDoc.popupNode;
+    if (!node.classList.contains("ruleview-property") &&
+        !node.classList.contains("ruleview-computed")) {
+      while (node = node.parentElement) {
+        if (node.classList.contains("ruleview-property") ||
+            node.classList.contains("ruleview-computed")) {
+          break;
+        }
+      }
+    }
+
+    // We need to strip expanded properties from the node because we use
+    // node.textContent below, which also gets text from hidden nodes. The
+    // simplest way to do this is to clone the node and remove them from the
+    // clone.
+    node = node.cloneNode();
+    let computed = node.querySelector(".ruleview-computedlist");
+    if (computed) {
+      computed.parentNode.removeChild(computed);
+    }
+    clipboardHelper.copyString(node.textContent);
+  },
+
+  /**
+   * Copy a property name from the rule view.
+   *
+   * @param aEvent The event object
+   */
+  ruleViewCopyProperty: function IUI_ruleViewCopyProperty(aEvent)
+  {
+    let node = this.chromeDoc.popupNode;
+
+    if (!node.classList.contains("ruleview-propertyname")) {
+      node = node.querySelector(".ruleview-propertyname");
+    }
+
+    if (node) {
+      clipboardHelper.copyString(node.textContent);
+    }
+  },
+
+  /**
+   * Copy a property value from the rule view.
+   *
+   * @param aEvent The event object
+   */
+  ruleViewCopyPropertyValue: function IUI_ruleViewCopyPropertyValue(aEvent)
+  {
+    let node = this.chromeDoc.popupNode;
+
+    if (!node.classList.contains("ruleview-propertyvalue")) {
+      node = node.querySelector(".ruleview-propertyvalue");
+    }
+
+    if (node) {
+      clipboardHelper.copyString(node.textContent);
+    }
+  },
+
+  /**
    * Destroy the rule view.
    */
   destroyRuleView: function IUI_destroyRuleView()
   {
     let iframe = this.getToolIframe(this.ruleViewObject);
+    iframe.removeEventListener("copy", this.cssRuleViewBoundCopy);
     iframe.parentNode.removeChild(iframe);
 
     if (this.ruleView) {
+      let menu = this.chromeDoc.querySelector("#rule-view-context-menu");
+      if (menu) {
+        // Copy
+        let menuitem = this.chromeDoc.querySelector("#rule-view-copy");
+        menuitem.removeEventListener("command", this.cssRuleViewBoundCopy);
+
+        // Copy rule
+        menuitem = this.chromeDoc.querySelector("#rule-view-copy-rule");
+        menuitem.removeEventListener("command", this.cssRuleViewBoundCopyRule);
+
+        // Copy property
+        menuitem = this.chromeDoc.querySelector("#rule-view-copy-declaration");
+        menuitem.removeEventListener("command",
+                                     this.cssRuleViewBoundCopyDeclaration);
+
+        // Copy property name
+        menuitem = this.chromeDoc.querySelector("#rule-view-copy-property");
+        menuitem.removeEventListener("command",
+                                     this.cssRuleViewBoundCopyProperty);
+
+        // Copy property value
+        menuitem = this.chromeDoc.querySelector("#rule-view-copy-property-value");
+        menuitem.removeEventListener("command",
+                                     this.cssRuleViewBoundCopyPropertyValue);
+
+        menu.removeEventListener("popupshowing", this.cssRuleViewBoundMenuUpdate);
+        menu.parentNode.removeChild(menu);
+      }
+
       this.ruleView.element.removeEventListener("CssRuleViewChanged",
                                                 this.boundRuleViewChanged);
       this.ruleView.element.removeEventListener("CssRuleViewCSSLinkClicked",
                                                 this.cssRuleViewBoundCSSLinkClicked);
+      this.ruleView.element.removeEventListener("mousedown",
+                                                this.cssRuleViewBoundMouseDown);
+      this.ruleView.element.removeEventListener("mouseup",
+                                                this.cssRuleViewBoundMouseUp);
+      this.ruleView.element.removeEventListener("mousemove",
+                                                this.cssRuleViewBoundMouseMove);
       delete boundRuleViewChanged;
       this.ruleView.clear();
       delete this.ruleView;
     }
   },
 
   /////////////////////////////////////////////////////////////////////////
   //// Utility Methods
@@ -1231,16 +1596,17 @@ InspectorUI.prototype = {
     btn.setAttribute("group", "sidebar-tools");
     this.sidebarToolbar.appendChild(btn);
 
     // create tool iframe
     let iframe = this.chromeDoc.createElement("iframe");
     iframe.id = "devtools-sidebar-iframe-" + aRegObj.id;
     iframe.setAttribute("flex", "1");
     iframe.setAttribute("tooltip", "aHTMLTooltip");
+    iframe.addEventListener("mousedown", iframe.focus);
     this.sidebarDeck.appendChild(iframe);
 
     // wire up button to show the iframe
     this.bindToolEvent(btn, "click", function showIframe() {
       this.toolShow(aRegObj);
     }.bind(this));
   },
 
@@ -1342,16 +1708,20 @@ InspectorUI.prototype = {
    */
   unregisterSidebarTool: function IUI_unregisterSidebarTool(aRegObj)
   {
     // unbind tool button click event
     let buttonId = this.getToolbarButtonId(aRegObj.id);
     let btn = this.chromeDoc.getElementById(buttonId);
     this.unbindToolEvent(btn, "click");
 
+    // Remove focus listener
+    let iframe = this.getToolIframe(aRegObj);
+    iframe.removeEventListener("mousedown", iframe.focus);
+
     // remove sidebar buttons and tools
     this.sidebarToolbar.removeChild(btn);
 
     // call unregister callback and remove from collection, this also removes
     // the iframe.
     if (aRegObj.unregister)
       aRegObj.unregister.call(aRegObj.context);
 
@@ -2227,8 +2597,22 @@ XPCOMUtils.defineLazyGetter(this, "Style
   var obj = {};
   Cu.import("resource:///modules/devtools/StyleInspector.jsm", obj);
   return obj.StyleInspector;
 });
 
 XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
+
+XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function() {
+  return Cc["@mozilla.org/widget/clipboardhelper;1"].
+    getService(Ci.nsIClipboardHelper);
+});
+
+XPCOMUtils.defineLazyGetter(this, "styleInspectorStrings", function() {
+  return Services.strings.createBundle(
+    "chrome://browser/locale/devtools/styleinspector.properties");
+});
+
+XPCOMUtils.defineLazyGetter(this, "osString", function() {
+  return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
+});
--- a/browser/devtools/highlighter/test/Makefile.in
+++ b/browser/devtools/highlighter/test/Makefile.in
@@ -53,16 +53,17 @@ include $(topsrcdir)/config/rules.mk
 		browser_inspector_tab_switch.js \
 		browser_inspector_treePanel_output.js \
 		browser_inspector_treePanel_input.html \
 		browser_inspector_treePanel_result.html \
 		browser_inspector_registertools.js \
 		browser_inspector_bug_665880.js \
 		browser_inspector_bug_674871.js \
 		browser_inspector_editor.js \
+		browser_inspector_editor_name.js \
 		browser_inspector_bug_566084_location_changed.js \
 		browser_inspector_infobar.js \
 		browser_inspector_bug_690361.js \
 		browser_inspector_bug_672902_keyboard_shortcuts.js \
 		browser_inspector_keybindings.js \
 		browser_inspector_breadcrumbs.html \
 		browser_inspector_breadcrumbs.js \
 		browser_inspector_bug_699308_iframe_navigation.js \
--- a/browser/devtools/highlighter/test/browser_inspector_editor.js
+++ b/browser/devtools/highlighter/test/browser_inspector_editor.js
@@ -1,20 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* ***** BEGIN LICENSE BLOCK *****
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
- *
- * Contributor(s):
- *   Rob Campbell <rcampbell@mozilla.com>
- *   Mihai Sucan <mihai.sucan@gmail.com>
- *   Kyle Simpson <ksimpson@mozilla.com>
- *
- * ***** END LICENSE BLOCK ***** */
+ * ***** END LICENSE BLOCK *****
+ */
 
 let doc;
 let div;
 let editorTestSteps;
 
 function doNextStep() {
   editorTestSteps.next();
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/highlighter/test/browser_inspector_editor_name.js
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* ***** BEGIN LICENSE BLOCK *****
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ * ***** END LICENSE BLOCK *****
+ */
+
+let doc;
+let div;
+let editorTestSteps;
+
+function doNextStep() {
+  editorTestSteps.next();
+}
+
+function setupEditorTests()
+{
+  div = doc.createElement("div");
+  div.setAttribute("id", "foobar");
+  div.setAttribute("class", "barbaz");
+  doc.body.appendChild(div);
+
+  Services.obs.addObserver(setupHTMLPanel, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
+  InspectorUI.toggleInspectorUI();
+}
+
+function setupHTMLPanel()
+{
+  Services.obs.removeObserver(setupHTMLPanel, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
+  Services.obs.addObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
+  InspectorUI.toggleHTMLPanel();
+}
+
+function runEditorTests()
+{
+  Services.obs.removeObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
+  InspectorUI.stopInspecting();
+  InspectorUI.inspectNode(doc.body, true);
+
+  // setup generator for async test steps
+  editorTestSteps = doEditorTestSteps();
+
+  // add step listeners
+  Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
+  Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
+  Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
+
+  // start the tests
+  doNextStep();
+}
+
+function highlighterTrap()
+{
+  // bug 696107
+  InspectorUI.highlighter.removeListener("nodeselected", highlighterTrap);
+  ok(false, "Highlighter moved. Shouldn't be here!");
+  finishUp();
+}
+
+function doEditorTestSteps()
+{
+  let treePanel = InspectorUI.treePanel;
+  let editor = treePanel.treeBrowserDocument.getElementById("attribute-editor");
+  let editorInput = treePanel.treeBrowserDocument.getElementById("attribute-editor-input");
+
+  // Step 1: grab and test the attribute-name nodes in the HTML panel, then open editor
+  let nodes = treePanel.treeBrowserDocument.querySelectorAll(".nodeName.editable");
+  let attrNameNode_id = nodes[0]
+  let attrNameNode_class = nodes[1];
+
+  is(attrNameNode_id.innerHTML, "id", "Step 1: we have the correct `id` attribute-name node in the HTML panel");
+  is(attrNameNode_class.innerHTML, "class", "we have the correct `class` attribute-name node in the HTML panel");
+
+  // double-click the `id` attribute-name node to open the editor
+  executeSoon(function() {
+    // firing 2 clicks right in a row to simulate a double-click
+    EventUtils.synthesizeMouse(attrNameNode_id, 2, 2, {clickCount: 2}, attrNameNode_id.ownerDocument.defaultView);
+  });
+
+  yield; // End of Step 1
+
+
+  // Step 2: validate editing session, enter new attribute value into editor, and save input
+  ok(InspectorUI.treePanel.editingContext, "Step 2: editor session started");
+  let selection = InspectorUI.selection;
+
+  ok(selection, "Selection is: " + selection);
+
+  let editorVisible = editor.classList.contains("editing");
+  ok(editorVisible, "editor popup visible");
+
+  // check if the editor popup is "near" the correct position
+  let editorDims = editor.getBoundingClientRect();
+  let attrNameNodeDims = attrNameNode_id.getBoundingClientRect();
+  let editorPositionOK = (editorDims.left >= (attrNameNodeDims.left - editorDims.width - 5)) &&
+                          (editorDims.right <= (attrNameNodeDims.right + editorDims.width + 5)) &&
+                          (editorDims.top >= (attrNameNodeDims.top - editorDims.height - 5)) &&
+                          (editorDims.bottom <= (attrNameNodeDims.bottom + editorDims.height + 5));
+
+  ok(editorPositionOK, "editor position acceptable");
+
+  // check to make sure the attribute-value node being edited is properly highlighted
+  let attrNameNodeHighlighted = attrNameNode_id.classList.contains("editingAttributeValue");
+  ok(attrNameNodeHighlighted, "`id` attribute-name node is editor-highlighted");
+
+  is(treePanel.editingContext.repObj, div, "editor session has correct reference to div");
+  is(treePanel.editingContext.attrObj, attrNameNode_id, "editor session has correct reference to `id` attribute-name node in HTML panel");
+  is(treePanel.editingContext.attrName, "id", "editor session knows correct attribute-name");
+
+  editorInput.value = "burp";
+  editorInput.focus();
+
+  InspectorUI.highlighter.addListener("nodeselected", highlighterTrap);
+
+  // hit <enter> to save the textbox value
+  executeSoon(function() {
+    // Extra key to test that keyboard handlers have been removed. bug 696107.
+    EventUtils.synthesizeKey("VK_LEFT", {}, attrNameNode_id.ownerDocument.defaultView);
+    EventUtils.synthesizeKey("VK_RETURN", {}, attrNameNode_id.ownerDocument.defaultView);
+  });
+
+  // two `yield` statements, to trap both the "SAVED" and "CLOSED" events that will be triggered
+  yield;
+  yield; // End of Step 2
+
+  // remove this from previous step
+  InspectorUI.highlighter.removeListener("nodeselected", highlighterTrap);
+
+  // Step 3: validate that the previous editing session saved correctly, then open editor on `class` attribute value
+  ok(!treePanel.editingContext, "Step 3: editor session ended");
+  editorVisible = editor.classList.contains("editing");
+  ok(!editorVisible, "editor popup hidden");
+  attrNameNodeHighlighted = attrNameNode_id.classList.contains("editingAttributeValue");
+  ok(!attrNameNodeHighlighted, "`id` attribute-value node is no longer editor-highlighted");
+  is(div.getAttribute("burp"), "foobar", "`id` attribute-name successfully updated");
+  is(attrNameNode_id.innerHTML, "burp", "attribute-name node in HTML panel successfully updated");
+
+  // double-click the `class` attribute-value node to open the editor
+  executeSoon(function() {
+    // firing 2 clicks right in a row to simulate a double-click
+    EventUtils.synthesizeMouse(attrNameNode_class, 2, 2, {clickCount: 2}, attrNameNode_class.ownerDocument.defaultView);
+  });
+
+  yield; // End of Step 3
+
+
+  // Step 4: enter value into editor, then hit <escape> to discard it
+  ok(treePanel.editingContext, "Step 4: editor session started");
+  editorVisible = editor.classList.contains("editing");
+  ok(editorVisible, "editor popup visible");
+
+  is(treePanel.editingContext.attrObj, attrNameNode_class, "editor session has correct reference to `class` attribute-name node in HTML panel");
+  is(treePanel.editingContext.attrName, "class", "editor session knows correct attribute-name");
+
+  editorInput.value = "Hello World";
+  editorInput.focus();
+
+  // hit <escape> to discard the inputted value
+  executeSoon(function() {
+    EventUtils.synthesizeKey("VK_ESCAPE", {}, attrNameNode_class.ownerDocument.defaultView);
+  });
+
+  yield; // End of Step 4
+
+
+  // Step 5: validate that the previous editing session discarded correctly, then open editor on `id` attribute value again
+  ok(!treePanel.editingContext, "Step 5: editor session ended");
+  editorVisible = editor.classList.contains("editing");
+  ok(!editorVisible, "editor popup hidden");
+  is(div.getAttribute("class"), "barbaz", "`class` attribute-name *not* updated");
+  is(attrNameNode_class.innerHTML, "class", "attribute-name node in HTML panel *not* updated");
+
+  // double-click the `id` attribute-name node to open the editor
+  executeSoon(function() {
+    // firing 2 clicks right in a row to simulate a double-click
+    EventUtils.synthesizeMouse(attrNameNode_id, 2, 2, {clickCount: 2}, attrNameNode_id.ownerDocument.defaultView);
+  });
+
+  yield; // End of Step 5
+
+
+  // Step 6: validate that editor opened again, then test double-click inside of editor (should do nothing)
+  ok(treePanel.editingContext, "Step 6: editor session started");
+  editorVisible = editor.classList.contains("editing");
+  ok(editorVisible, "editor popup visible");
+
+  // double-click on the editor input box
+  executeSoon(function() {
+    // firing 2 clicks right in a row to simulate a double-click
+    EventUtils.synthesizeMouse(editorInput, 2, 2, {clickCount: 2}, editorInput.ownerDocument.defaultView);
+
+    // since the previous double-click is supposed to do nothing,
+    // wait a brief moment, then move on to the next step
+    executeSoon(function() {
+      doNextStep();
+    });
+  });
+
+  yield; // End of Step 6
+
+
+  // Step 7: validate that editing session is still correct, then enter a value and try a click
+  //         outside of editor (should cancel the editing session)
+  ok(treePanel.editingContext, "Step 7: editor session still going");
+  editorVisible = editor.classList.contains("editing");
+  ok(editorVisible, "editor popup still visible");
+
+  editorInput.value = "all your base are belong to us";
+
+  // single-click the `class` attribute-value node
+  executeSoon(function() {
+    EventUtils.synthesizeMouse(attrNameNode_class, 2, 2, {}, attrNameNode_class.ownerDocument.defaultView);
+  });
+
+  yield; // End of Step 7
+
+
+  // Step 8: validate that the editor was closed and that the editing was not saved
+  ok(!treePanel.editingContext, "Step 8: editor session ended");
+  editorVisible = editor.classList.contains("editing");
+  ok(!editorVisible, "editor popup hidden");
+  is(div.getAttribute("burp"), "foobar", "`id` attribute-name *not* updated");
+  is(attrNameNode_id.innerHTML, "burp", "attribute-value node in HTML panel *not* updated");
+
+  // End of Step 8
+  executeSoon(finishUp);
+}
+
+function finishUp() {
+  // end of all steps, so clean up
+  Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
+  Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
+  Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
+  doc = div = null;
+  InspectorUI.closeInspectorUI();
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function() {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+    doc = content.document;
+    waitForFocus(setupEditorTests, content);
+  }, true);
+
+  content.location = "data:text/html,basic tests for html panel attribute-value editor";
+}
+
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -19,16 +19,17 @@
    - The Mozilla Foundation.
    - Portions created by the Initial Developer are Copyright (C) 2011
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Rob Campbell <robcee@mozilla.com> (original author)
    -   Mihai Sucan <mihai.sucan@gmail.com>
    -   Erik Vold <erikvvold@gmail.com>
+   -   Mark Capella <markcapella@twcny.rr.com>
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    - in which case the provisions of the GPL or the LGPL are applicable instead
    - of those above. If you wish to allow use of your version of this file only
    - under the terms of either the GPL or the LGPL, and not to allow others to
    - use your version of this file under the terms of the MPL, indicate your
--- a/browser/devtools/sourceeditor/orion/Makefile.dryice.js
+++ b/browser/devtools/sourceeditor/orion/Makefile.dryice.js
@@ -48,16 +48,17 @@ copy({
     ORION_EDITOR + "/orion/textview/global.js",
     ORION_EDITOR + "/orion/textview/eventTarget.js",
     ORION_EDITOR + "/orion/editor/regex.js",
     ORION_EDITOR + "/orion/textview/keyBinding.js",
     ORION_EDITOR + "/orion/textview/annotations.js",
     ORION_EDITOR + "/orion/textview/rulers.js",
     ORION_EDITOR + "/orion/textview/undoStack.js",
     ORION_EDITOR + "/orion/textview/textModel.js",
+    ORION_EDITOR + "/orion/textview/projectionTextModel.js",
     ORION_EDITOR + "/orion/textview/tooltip.js",
     ORION_EDITOR + "/orion/textview/textView.js",
     ORION_EDITOR + "/orion/textview/textDND.js",
     ORION_EDITOR + "/orion/editor/htmlGrammar.js",
     ORION_EDITOR + "/orion/editor/textMateStyler.js",
     ORION_EDITOR + "/examples/textview/textStyler.js",
   ],
   dest: js_src,
--- a/browser/devtools/sourceeditor/orion/README
+++ b/browser/devtools/sourceeditor/orion/README
@@ -17,16 +17,20 @@ Orion version: git clone from 2012-01-26
 
   + patches for Eclipse Bug 370606 - Problems with UndoStack and deletions at
                                      the beginning of the document
     http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=cec71bddaf32251c34d3728df5da13c130d14f33
     http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=3ce24b94f1d8103b16b9cf16f2f50a6302d43b18
     http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=27177e9a3dc70c20b4877e3eab3adfff1d56e342
     see https://bugs.eclipse.org/bugs/show_bug.cgi?id=370606
 
+  + patch for Mozilla Bug 730532 - remove CSS2Properties aliases for MozOpacity
+                                   and MozOutline*
+    see https://bugzilla.mozilla.org/show_bug.cgi?id=730532#c3
+
 # License
 
 The following files are licensed according to the contents in the LICENSE
 file:
   orion.js
   orion.css
 
 # Theming
--- a/browser/devtools/sourceeditor/orion/orion.js
+++ b/browser/devtools/sourceeditor/orion/orion.js
@@ -2565,16 +2565,600 @@ define("orion/textview/textModel", ['ori
 });/*******************************************************************************
  * @license
  * Copyright (c) 2010, 2011 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials are made 
  * available under the terms of the Eclipse Public License v1.0 
  * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
  * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
  * 
+ * Contributors: 
+ *		Felipe Heidrich (IBM Corporation) - initial API and implementation
+ *		Silenio Quarti (IBM Corporation) - initial API and implementation
+ ******************************************************************************/
+
+/*global define */
+
+define("orion/textview/projectionTextModel", ['orion/textview/textModel', 'orion/textview/eventTarget'], function(mTextModel, mEventTarget) {
+
+	/**
+	 * @class This object represents a projection range. A projection specifies a
+	 * range of text and the replacement text. The range of text is relative to the
+	 * base text model associated to a projection model.
+	 * <p>
+	 * <b>See:</b><br/>
+	 * {@link orion.textview.ProjectionTextModel}<br/>
+	 * {@link orion.textview.ProjectionTextModel#addProjection}<br/>
+	 * </p>		 
+	 * @name orion.textview.Projection
+	 * 
+	 * @property {Number} start The start offset of the projection range. 
+	 * @property {Number} end The end offset of the projection range. This offset is exclusive.
+	 * @property {String|orion.textview.TextModel} [text=""] The projection text to be inserted
+	 */
+	/**
+	 * Constructs a new <code>ProjectionTextModel</code> based on the specified <code>TextModel</code>.
+	 *
+	 * @param {orion.textview.TextModel} baseModel The base text model.
+	 *
+	 * @name orion.textview.ProjectionTextModel
+	 * @class The <code>ProjectionTextModel</code> represents a projection of its base text
+	 * model. Projection ranges can be added to the projection text model to hide and/or insert
+	 * ranges to the base text model.
+	 * <p>
+	 * The contents of the projection text model is modified when changes occur in the base model,
+	 * projection model or by calls to {@link #addProjection} and {@link #removeProjection}.
+	 * </p>
+	 * <p>
+	 * <b>See:</b><br/>
+	 * {@link orion.textview.TextView}<br/>
+	 * {@link orion.textview.TextModel}
+	 * {@link orion.textview.TextView#setModel}
+	 * </p>
+	 * @borrows orion.textview.EventTarget#addEventListener as #addEventListener
+	 * @borrows orion.textview.EventTarget#removeEventListener as #removeEventListener
+	 * @borrows orion.textview.EventTarget#dispatchEvent as #dispatchEvent
+	 */
+	function ProjectionTextModel(baseModel) {
+		this._model = baseModel;	/* Base Model */
+		this._projections = [];
+	}
+
+	ProjectionTextModel.prototype = /** @lends orion.textview.ProjectionTextModel.prototype */ {
+		/**
+		 * Adds a projection range to the model.
+		 * <p>
+		 * The model must notify the listeners before and after the the text is
+		 * changed by calling {@link #onChanging} and {@link #onChanged} respectively. 
+		 * </p>
+		 * @param {orion.textview.Projection} projection The projection range to be added.
+		 * 
+		 * @see #removeProjection
+		 */
+		addProjection: function(projection) {
+			if (!projection) {return;}
+			//start and end can't overlap any exist projection
+			var model = this._model, projections = this._projections;
+			projection._lineIndex = model.getLineAtOffset(projection.start);
+			projection._lineCount = model.getLineAtOffset(projection.end) - projection._lineIndex;
+			var text = projection.text;
+			if (!text) { text = ""; }
+			if (typeof text === "string") {
+				projection._model = new mTextModel.TextModel(text, model.getLineDelimiter());
+			} else {
+				projection._model = text;
+			}
+			var eventStart = this.mapOffset(projection.start, true);
+			var removedCharCount = projection.end - projection.start;
+			var removedLineCount = projection._lineCount;
+			var addedCharCount = projection._model.getCharCount();
+			var addedLineCount = projection._model.getLineCount() - 1;
+			var modelChangingEvent = {
+				type: "Changing",
+				text: projection._model.getText(),
+				start: eventStart,
+				removedCharCount: removedCharCount,
+				addedCharCount: addedCharCount,
+				removedLineCount: removedLineCount,
+				addedLineCount: addedLineCount
+			};
+			this.onChanging(modelChangingEvent);
+			var index = this._binarySearch(projections, projection.start);
+			projections.splice(index, 0, projection);
+			var modelChangedEvent = {
+				type: "Changed",
+				start: eventStart,
+				removedCharCount: removedCharCount,
+				addedCharCount: addedCharCount,
+				removedLineCount: removedLineCount,
+				addedLineCount: addedLineCount
+			};
+			this.onChanged(modelChangedEvent);
+		},
+		/**
+		 * Returns all projection ranges of this model.
+		 * 
+		 * @return {orion.textview.Projection[]} The projection ranges.
+		 * 
+		 * @see #addProjection
+		 */
+		getProjections: function() {
+			return this._projections.slice(0);
+		},
+		/**
+		 * Gets the base text model.
+		 *
+		 * @return {orion.textview.TextModel} The base text model.
+		 */
+		getBaseModel: function() {
+			return this._model;
+		},
+		/**
+		 * Maps offsets between the projection model and its base model.
+		 *
+		 * @param {Number} offset The offset to be mapped.
+		 * @param {Boolean} [baseOffset=false] <code>true</code> if <code>offset</code> is in base model and
+		 *	should be mapped to the projection model.
+		 * @return {Number} The mapped offset
+		 */
+		mapOffset: function(offset, baseOffset) {
+			var projections = this._projections, delta = 0, i, projection;
+			if (baseOffset) {
+				for (i = 0; i < projections.length; i++) {
+					projection = projections[i];
+					if (projection.start > offset) { break; }
+					if (projection.end > offset) { return -1; }
+					delta += projection._model.getCharCount() - (projection.end - projection.start);
+				}
+				return offset + delta;
+			}
+			for (i = 0; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > offset - delta) { break; }
+				var charCount = projection._model.getCharCount();
+				if (projection.start + charCount > offset - delta) {
+					return -1;
+				}
+				delta += charCount - (projection.end - projection.start);
+			}
+			return offset - delta;
+		},
+		/**
+		 * Removes a projection range from the model.
+		 * <p>
+		 * The model must notify the listeners before and after the the text is
+		 * changed by calling {@link #onChanging} and {@link #onChanged} respectively. 
+		 * </p>
+		 * 
+		 * @param {orion.textview.Projection} projection The projection range to be removed.
+		 * 
+		 * @see #addProjection
+		 */
+		removeProjection: function(projection) {
+			//TODO remove listeners from model
+			var i, delta = 0;
+			for (i = 0; i < this._projections.length; i++) {
+				var p = this._projections[i];
+				if (p === projection) {
+					projection = p;
+					break;
+				}
+				delta += p._model.getCharCount() - (p.end - p.start);
+			}
+			if (i < this._projections.length) {
+				var model = this._model;
+				var eventStart = projection.start + delta;
+				var addedCharCount = projection.end - projection.start;
+				var addedLineCount = projection._lineCount;
+				var removedCharCount = projection._model.getCharCount();
+				var removedLineCount = projection._model.getLineCount() - 1;
+				var modelChangingEvent = {
+					type: "Changing",
+					text: model.getText(projection.start, projection.end),
+					start: eventStart,
+					removedCharCount: removedCharCount,
+					addedCharCount: addedCharCount,
+					removedLineCount: removedLineCount,
+					addedLineCount: addedLineCount
+				};
+				this.onChanging(modelChangingEvent);
+				this._projections.splice(i, 1);
+				var modelChangedEvent = {
+					type: "Changed",
+					start: eventStart,
+					removedCharCount: removedCharCount,
+					addedCharCount: addedCharCount,
+					removedLineCount: removedLineCount,
+					addedLineCount: addedLineCount
+				};
+				this.onChanged(modelChangedEvent);
+			}
+		},
+		/** @ignore */
+		_binarySearch: function (array, offset) {
+			var high = array.length, low = -1, index;
+			while (high - low > 1) {
+				index = Math.floor((high + low) / 2);
+				if (offset <= array[index].start) {
+					high = index;
+				} else {
+					low = index;
+				}
+			}
+			return high;
+		},
+		/**
+		 * @see orion.textview.TextModel#getCharCount
+		 */
+		getCharCount: function() {
+			var count = this._model.getCharCount(), projections = this._projections;
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				count += projection._model.getCharCount() - (projection.end - projection.start);
+			}
+			return count;
+		},
+		/**
+		 * @see orion.textview.TextModel#getLine
+		 */
+		getLine: function(lineIndex, includeDelimiter) {
+			if (lineIndex < 0) { return null; }
+			var model = this._model, projections = this._projections;
+			var delta = 0, result = [], offset = 0, i, lineCount, projection;
+			for (i = 0; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection._lineIndex >= lineIndex - delta) { break; }
+				lineCount = projection._model.getLineCount() - 1;
+				if (projection._lineIndex + lineCount >= lineIndex - delta) {
+					var projectionLineIndex = lineIndex - (projection._lineIndex + delta);
+					if (projectionLineIndex < lineCount) {
+						return projection._model.getLine(projectionLineIndex, includeDelimiter);
+					} else {
+						result.push(projection._model.getLine(lineCount));
+					}
+				}
+				offset = projection.end;
+				delta += lineCount - projection._lineCount;
+			}
+			offset = Math.max(offset, model.getLineStart(lineIndex - delta));
+			for (; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection._lineIndex > lineIndex - delta) { break; }
+				result.push(model.getText(offset, projection.start));
+				lineCount = projection._model.getLineCount() - 1;
+				if (projection._lineIndex + lineCount > lineIndex - delta) {
+					result.push(projection._model.getLine(0, includeDelimiter));
+					return result.join("");
+				}
+				result.push(projection._model.getText());
+				offset = projection.end;
+				delta += lineCount - projection._lineCount;
+			}
+			var end = model.getLineEnd(lineIndex - delta, includeDelimiter);
+			if (offset < end) {
+				result.push(model.getText(offset, end));
+			}
+			return result.join("");
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineAtOffset
+		 */
+		getLineAtOffset: function(offset) {
+			var model = this._model, projections = this._projections;
+			var delta = 0, lineDelta = 0;
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				if (projection.start > offset - delta) { break; }
+				var charCount = projection._model.getCharCount();
+				if (projection.start + charCount > offset - delta) {
+					var projectionOffset = offset - (projection.start + delta);
+					lineDelta += projection._model.getLineAtOffset(projectionOffset);
+					delta += projectionOffset;
+					break;
+				}
+				lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+				delta += charCount - (projection.end - projection.start);
+			}
+			return model.getLineAtOffset(offset - delta) + lineDelta;
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineCount
+		 */
+		getLineCount: function() {
+			var model = this._model, projections = this._projections;
+			var count = model.getLineCount();
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				count += projection._model.getLineCount() - 1 - projection._lineCount;
+			}
+			return count;
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineDelimiter
+		 */
+		getLineDelimiter: function() {
+			return this._model.getLineDelimiter();
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineEnd
+		 */
+		getLineEnd: function(lineIndex, includeDelimiter) {
+			if (lineIndex < 0) { return -1; }
+			var model = this._model, projections = this._projections;
+			var delta = 0, offsetDelta = 0;
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				if (projection._lineIndex > lineIndex - delta) { break; }
+				var lineCount = projection._model.getLineCount() - 1;
+				if (projection._lineIndex + lineCount > lineIndex - delta) {
+					var projectionLineIndex = lineIndex - (projection._lineIndex + delta);
+					return projection._model.getLineEnd (projectionLineIndex, includeDelimiter) + projection.start + offsetDelta;
+				}
+				offsetDelta += projection._model.getCharCount() - (projection.end - projection.start);
+				delta += lineCount - projection._lineCount;
+			}
+			return model.getLineEnd(lineIndex - delta, includeDelimiter) + offsetDelta;
+		},
+		/**
+		 * @see orion.textview.TextModel#getLineStart
+		 */
+		getLineStart: function(lineIndex) {
+			if (lineIndex < 0) { return -1; }
+			var model = this._model, projections = this._projections;
+			var delta = 0, offsetDelta = 0;
+			for (var i = 0; i < projections.length; i++) {
+				var projection = projections[i];
+				if (projection._lineIndex >= lineIndex - delta) { break; }
+				var lineCount = projection._model.getLineCount() - 1;
+				if (projection._lineIndex + lineCount >= lineIndex - delta) {
+					var projectionLineIndex = lineIndex - (projection._lineIndex + delta);
+					return projection._model.getLineStart (projectionLineIndex) + projection.start + offsetDelta;
+				}
+				offsetDelta += projection._model.getCharCount() - (projection.end - projection.start);
+				delta += lineCount - projection._lineCount;
+			}
+			return model.getLineStart(lineIndex - delta) + offsetDelta;
+		},
+		/**
+		 * @see orion.textview.TextModel#getText
+		 */
+		getText: function(start, end) {
+			if (start === undefined) { start = 0; }
+			var model = this._model, projections = this._projections;
+			var delta = 0, result = [], i, projection, charCount;
+			for (i = 0; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > start - delta) { break; }
+				charCount = projection._model.getCharCount();
+				if (projection.start + charCount > start - delta) {
+					if (end !== undefined && projection.start + charCount > end - delta) {
+						return projection._model.getText(start - (projection.start + delta), end - (projection.start + delta));
+					} else {
+						result.push(projection._model.getText(start - (projection.start + delta)));
+						start = projection.end + delta + charCount - (projection.end - projection.start);
+					}
+				}
+				delta += charCount - (projection.end - projection.start);
+			}
+			var offset = start - delta;
+			if (end !== undefined) {
+				for (; i < projections.length; i++) {
+					projection = projections[i];
+					if (projection.start > end - delta) { break; }
+					result.push(model.getText(offset, projection.start));
+					charCount = projection._model.getCharCount();
+					if (projection.start + charCount > end - delta) {
+						result.push(projection._model.getText(0, end - (projection.start + delta)));
+						return result.join("");
+					}
+					result.push(projection._model.getText());
+					offset = projection.end;
+					delta += charCount - (projection.end - projection.start);
+				}
+				result.push(model.getText(offset, end - delta));
+			} else {
+				for (; i < projections.length; i++) {
+					projection = projections[i];
+					result.push(model.getText(offset, projection.start));
+					result.push(projection._model.getText());
+					offset = projection.end;
+				}
+				result.push(model.getText(offset));
+			}
+			return result.join("");
+		},
+		/** @ignore */
+		_onChanging: function(text, start, removedCharCount, addedCharCount, removedLineCount, addedLineCount) {
+			var model = this._model, projections = this._projections, i, projection, delta = 0, lineDelta;
+			var end = start + removedCharCount;
+			for (; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > start) { break; }
+				delta += projection._model.getCharCount() - (projection.end - projection.start);
+			}
+			/*TODO add stuff saved by setText*/
+			var mapStart = start + delta, rangeStart = i;
+			for (; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > end) { break; }
+				delta += projection._model.getCharCount() - (projection.end - projection.start);
+				lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+			}
+			/*TODO add stuff saved by setText*/
+			var mapEnd = end + delta, rangeEnd = i;
+			this.onChanging(mapStart, mapEnd - mapStart, addedCharCount/*TODO add stuff saved by setText*/, removedLineCount + lineDelta/*TODO add stuff saved by setText*/, addedLineCount/*TODO add stuff saved by setText*/);
+			projections.splice(projections, rangeEnd - rangeStart);
+			var count = text.length - (mapEnd - mapStart);
+			for (; i < projections.length; i++) {
+				projection = projections[i];
+				projection.start += count;
+				projection.end += count;
+				projection._lineIndex = model.getLineAtOffset(projection.start);
+			}
+		},
+		/**
+		 * @see orion.textview.TextModel#onChanging
+		 */
+		onChanging: function(modelChangingEvent) {
+			return this.dispatchEvent(modelChangingEvent);
+		},
+		/**
+		 * @see orion.textview.TextModel#onChanged
+		 */
+		onChanged: function(modelChangedEvent) {
+			return this.dispatchEvent(modelChangedEvent);
+		},
+		/**
+		 * @see orion.textview.TextModel#setLineDelimiter
+		 */
+		setLineDelimiter: function(lineDelimiter) {
+			this._model.setLineDelimiter(lineDelimiter);
+		},
+		/**
+		 * @see orion.textview.TextModel#setText
+		 */
+		setText: function(text, start, end) {
+			if (text === undefined) { text = ""; }
+			if (start === undefined) { start = 0; }
+			var eventStart = start, eventEnd = end;
+			var model = this._model, projections = this._projections;
+			var delta = 0, lineDelta = 0, i, projection, charCount, startProjection, endProjection, startLineDelta = 0;
+			for (i = 0; i < projections.length; i++) {
+				projection = projections[i];
+				if (projection.start > start - delta) { break; }
+				charCount = projection._model.getCharCount();
+				if (projection.start + charCount > start - delta) {
+					if (end !== undefined && projection.start + charCount > end - delta) {
+						projection._model.setText(text, start - (projection.start + delta), end - (projection.start + delta));
+						//TODO events - special case
+						return;
+					} else {
+						startLineDelta = projection._model.getLineCount() - 1 - projection._model.getLineAtOffset(start - (projection.start + delta));
+						startProjection = {
+							projection: projection,
+							start: start - (projection.start + delta)
+						};
+						start = projection.end + delta + charCount - (projection.end - projection.start);
+					}
+				}
+				lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+				delta += charCount - (projection.end - projection.start);
+			}
+			var mapStart = start - delta, rangeStart = i, startLine = model.getLineAtOffset(mapStart) + lineDelta - startLineDelta;
+			if (end !== undefined) {
+				for (; i < projections.length; i++) {
+					projection = projections[i];
+					if (projection.start > end - delta) { break; }
+					charCount = projection._model.getCharCount();
+					if (projection.start + charCount > end - delta) {
+						lineDelta += projection._model.getLineAtOffset(end - (projection.start + delta));
+						charCount = end - (projection.start + delta);
+						end = projection.end + delta;
+						endProjection = {
+							projection: projection,
+							end: charCount
+						};
+						break;
+					}
+					lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+					delta += charCount - (projection.end - projection.start);
+				}
+			} else {
+				for (; i < projections.length; i++) {
+					projection = projections[i];
+					lineDelta += projection._model.getLineCount() - 1 - projection._lineCount;
+					delta += projection._model.getCharCount() - (projection.end - projection.start);
+				}
+				end = eventEnd = model.getCharCount() + delta;
+			}
+			var mapEnd = end - delta, rangeEnd = i, endLine = model.getLineAtOffset(mapEnd) + lineDelta;
+			
+			//events
+			var removedCharCount = eventEnd - eventStart;
+			var removedLineCount = endLine - startLine;
+			var addedCharCount = text.length;
+			var addedLineCount = 0;
+			var cr = 0, lf = 0, index = 0;
+			while (true) {
+				if (cr !== -1 && cr <= index) { cr = text.indexOf("\r", index); }
+				if (lf !== -1 && lf <= index) { lf = text.indexOf("\n", index); }
+				if (lf === -1 && cr === -1) { break; }
+				if (cr !== -1 && lf !== -1) {
+					if (cr + 1 === lf) {
+						index = lf + 1;
+					} else {
+						index = (cr < lf ? cr : lf) + 1;
+					}
+				} else if (cr !== -1) {
+					index = cr + 1;
+				} else {
+					index = lf + 1;
+				}
+				addedLineCount++;
+			}
+			
+			var modelChangingEvent = {
+				type: "Changing",
+				text: text,
+				start: eventStart,
+				removedCharCount: removedCharCount,
+				addedCharCount: addedCharCount,
+				removedLineCount: removedLineCount,
+				addedLineCount: addedLineCount
+			};
+			this.onChanging(modelChangingEvent);
+			
+//			var changeLineCount = model.getLineAtOffset(mapEnd) - model.getLineAtOffset(mapStart) + addedLineCount;
+			model.setText(text, mapStart, mapEnd);
+			if (startProjection) {
+				projection = startProjection.projection;
+				projection._model.setText("", startProjection.start);
+			}		
+			if (endProjection) {
+				projection = endProjection.projection;
+				projection._model.setText("", 0, endProjection.end);
+				projection.start = projection.end;
+				projection._lineCount = 0;
+			}
+			projections.splice(rangeStart, rangeEnd - rangeStart);
+			var changeCount = text.length - (mapEnd - mapStart);
+			for (i = rangeEnd; i < projections.length; i++) {
+				projection = projections[i];
+				projection.start += changeCount;
+				projection.end += changeCount;
+//				if (projection._lineIndex + changeLineCount !== model.getLineAtOffset(projection.start)) {
+//					log("here");
+//				}
+				projection._lineIndex = model.getLineAtOffset(projection.start);
+//				projection._lineIndex += changeLineCount;
+			}
+			
+			var modelChangedEvent = {
+				type: "Changed",
+				start: eventStart,
+				removedCharCount: removedCharCount,
+				addedCharCount: addedCharCount,
+				removedLineCount: removedLineCount,
+				addedLineCount: addedLineCount
+			};
+			this.onChanged(modelChangedEvent);
+		}
+	};
+	mEventTarget.EventTarget.addMixin(ProjectionTextModel.prototype);
+
+	return {ProjectionTextModel: ProjectionTextModel};
+});
+/*******************************************************************************
+ * @license
+ * Copyright (c) 2010, 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials are made 
+ * available under the terms of the Eclipse Public License v1.0 
+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+ * 
  * Contributors: IBM Corporation - initial API and implementation
  ******************************************************************************/
 
 /*global define setTimeout clearTimeout setInterval clearInterval Node */
 
 define("orion/textview/tooltip", ['orion/textview/textView', 'orion/textview/textModel', 'orion/textview/projectionTextModel'], function(mTextView, mTextModel, mProjectionTextModel) {
 
 	/** @private */
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm
+++ b/browser/devtools/sourceeditor/source-editor-orion.jsm
@@ -903,17 +903,18 @@ SourceEditor.prototype = {
     }
   },
 
   /**
    * Retrieve the list of Orion Annotations filtered by type for the given text range.
    *
    * @private
    * @param string aType
-   *        The annotation type to filter annotations for.
+   *        The annotation type to filter annotations for. Use one of the keys
+   *        in ORION_ANNOTATION_TYPES.
    * @param number aStart
    *        Offset from where to start finding the annotations.
    * @param number aEnd
    *        End offset for retrieving the annotations.
    * @return array
    *         The array of annotations, filtered by type, within the given text
    *         range.
    */
--- a/browser/devtools/sourceeditor/source-editor.jsm
+++ b/browser/devtools/sourceeditor/source-editor.jsm
@@ -263,34 +263,34 @@ SourceEditor.EVENTS = {
   FOCUS: "Focus",
 
   /**
    * The blur event is fired when the editor goes out of focus.
    */
   BLUR: "Blur",
 
   /**
-   * The MouseMove event is sent when the user moves the mouse over a line
-   * annotation. The event object properties:
+   * The MouseMove event is sent when the user moves the mouse over a line.
+   * The event object properties:
    *   - event - the DOM mousemove event object.
    *   - x and y - the mouse coordinates relative to the document being edited.
    */
   MOUSE_MOVE: "MouseMove",
 
   /**
-   * The MouseOver event is sent when the mouse pointer enters a line
-   * annotation. The event object properties:
+   * The MouseOver event is sent when the mouse pointer enters a line.
+   * The event object properties:
    *   - event - the DOM mouseover event object.
    *   - x and y - the mouse coordinates relative to the document being edited.
    */
   MOUSE_OVER: "MouseOver",
 
   /**
-   * This MouseOut event is sent when the mouse pointer exits a line
-   * annotation. The event object properties:
+   * This MouseOut event is sent when the mouse pointer exits a line.
+   * The event object properties:
    *   - event - the DOM mouseout event object.
    *   - x and y - the mouse coordinates relative to the document being edited.
    */
   MOUSE_OUT: "MouseOut",
 
   /**
    * The BreakpointChange event is fired when a new breakpoint is added or when
    * a breakpoint is removed - either through API use or through the editor UI.
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -36,16 +36,17 @@
  * 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 ***** */
 
 const Ci = Components.interfaces;
+const Cc = Components.classes;
 const Cu = Components.utils;
 const FILTER_CHANGED_TIMEOUT = 300;
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
@@ -156,31 +157,41 @@ function CssHtmlTree(aStyleInspector)
   this.styleWin = aStyleInspector.iframe;
   this.styleInspector = aStyleInspector;
   this.cssLogic = aStyleInspector.cssLogic;
   this.doc = aStyleInspector.document;
   this.win = aStyleInspector.window;
   this.getRTLAttr = this.win.getComputedStyle(this.win.gBrowser).direction;
   this.propertyViews = [];
 
+  // Create bound methods.
+  this.siBoundMenuUpdate = this.computedViewMenuUpdate.bind(this);
+  this.siBoundCopy = this.computedViewCopy.bind(this);
+  this.siBoundCopyDeclaration = this.computedViewCopyDeclaration.bind(this);
+  this.siBoundCopyProperty = this.computedViewCopyProperty.bind(this);
+  this.siBoundCopyPropertyValue = this.computedViewCopyPropertyValue.bind(this);
+
   // The document in which we display the results (csshtmltree.xul).
   this.styleDocument = this.styleWin.contentWindow.document;
 
+  this.styleDocument.addEventListener("copy", this.siBoundCopy);
+
   // Nodes used in templating
   this.root = this.styleDocument.getElementById("root");
   this.templateRoot = this.styleDocument.getElementById("templateRoot");
   this.propertyContainer = this.styleDocument.getElementById("propertyContainer");
   this.panel = aStyleInspector.panel;
 
   // No results text.
   this.noResults = this.styleDocument.getElementById("noResults");
 
   // The element that we're inspecting, and the document that it comes from.
   this.viewedElement = null;
   this.createStyleViews();
+  this.createContextMenu();
 }
 
 /**
  * Memoized lookup of a l10n string from a string bundle.
  * @param {string} aName The key to lookup.
  * @returns A localized version of the given key.
  */
 CssHtmlTree.l10n = function CssHtmlTree_l10n(aName)
@@ -226,16 +237,21 @@ CssHtmlTree.processTemplate = function C
 
 XPCOMUtils.defineLazyGetter(CssHtmlTree, "_strings", function() Services.strings
         .createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
 
 XPCOMUtils.defineLazyGetter(CssHtmlTree, "HELP_LINK_TITLE", function() {
   return CssHtmlTree.HELP_LINK_TITLE = CssHtmlTree.l10n("helpLinkTitle");
 });
 
+XPCOMUtils.defineLazyGetter(this, "clipboardHelper", function() {
+  return Cc["@mozilla.org/widget/clipboardhelper;1"].
+    getService(Ci.nsIClipboardHelper);
+});
+
 CssHtmlTree.prototype = {
   // Cache the list of properties that have matched and unmatched properties.
   _matchedProperties: null,
   _unmatchedProperties: null,
 
   htmlComplete: false,
 
   // Used for cancelling timeouts in the style filter.
@@ -465,32 +481,229 @@ CssHtmlTree.prototype = {
       let result = this.cssLogic.hasUnmatchedSelectors([aProperty]);
       this._unmatchedProperties[aProperty] = result[aProperty];
     }
 
     return this._unmatchedProperties[aProperty];
   },
 
   /**
+   * Create a context menu.
+   */
+  createContextMenu: function SI_createContextMenu()
+  {
+    let popupSet = this.doc.getElementById("mainPopupSet");
+
+    let menu = this.doc.createElement("menupopup");
+    menu.addEventListener("popupshowing", this.siBoundMenuUpdate);
+    menu.id = "computed-view-context-menu";
+    popupSet.appendChild(menu);
+
+    // Copy selection
+    let label = CssHtmlTree.l10n("style.contextmenu.copyselection");
+    let accessKey = CssHtmlTree.l10n("style.contextmenu.copyselection.accesskey");
+    let item = this.doc.createElement("menuitem");
+    item.id = "computed-view-copy";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.siBoundCopy);
+    menu.appendChild(item);
+
+    // Copy declaration
+    label = CssHtmlTree.l10n("style.contextmenu.copydeclaration");
+    accessKey = CssHtmlTree.l10n("style.contextmenu.copydeclaration.accesskey");
+    item = this.doc.createElement("menuitem");
+    item.id = "computed-view-copy-declaration";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.siBoundCopyDeclaration);
+    menu.appendChild(item);
+
+    // Copy property name
+    label = CssHtmlTree.l10n("style.contextmenu.copyproperty");
+    accessKey = CssHtmlTree.l10n("style.contextmenu.copyproperty.accesskey");
+    item = this.doc.createElement("menuitem");
+    item.id = "computed-view-copy-property";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.siBoundCopyProperty);
+    menu.appendChild(item);
+
+    // Copy property value
+    label = CssHtmlTree.l10n("style.contextmenu.copypropertyvalue");
+    accessKey = CssHtmlTree.l10n("style.contextmenu.copypropertyvalue.accesskey");
+    item = this.doc.createElement("menuitem");
+    item.id = "computed-view-copy-property-value";
+    item.setAttribute("label", label);
+    item.setAttribute("accesskey", accessKey);
+    item.addEventListener("command", this.siBoundCopyPropertyValue);
+    menu.appendChild(item);
+
+    this.styleWin.setAttribute("context", menu.id);
+  },
+
+  /**
+   * Update the context menu by disabling irrelevant menuitems and enabling
+   * relevant ones.
+   */
+  computedViewMenuUpdate: function si_computedViewMenuUpdate()
+  {
+    let win = this.styleDocument.defaultView;
+    let disable = win.getSelection().isCollapsed;
+    let menuitem = this.doc.querySelector("#computed-view-copy");
+    menuitem.disabled = disable;
+
+    let node = this.doc.popupNode;
+    if (!node.classList.contains("property-view")) {
+      while (node = node.parentElement) {
+        if (node.classList.contains("property-view")) {
+          break;
+        }
+      }
+    }
+    let disablePropertyItems = !node;
+    menuitem = this.doc.querySelector("#computed-view-copy-declaration");
+    menuitem.disabled = disablePropertyItems;
+    menuitem = this.doc.querySelector("#computed-view-copy-property");
+    menuitem.disabled = disablePropertyItems;
+    menuitem = this.doc.querySelector("#computed-view-copy-property-value");
+    menuitem.disabled = disablePropertyItems;
+  },
+
+  /**
+   * Copy selected text.
+   *
+   * @param aEvent The event object
+   */
+  computedViewCopy: function si_computedViewCopy(aEvent)
+  {
+    let win = this.styleDocument.defaultView;
+    let text = win.getSelection().toString();
+
+    // Tidy up block headings by moving CSS property names and their values onto
+    // the same line and inserting a colon between them.
+    text = text.replace(/(.+)\r?\n\s+/g, "$1: ");
+
+    // Remove any MDN link titles
+    text = text.replace(CssHtmlTree.HELP_LINK_TITLE, "");
+    clipboardHelper.copyString(text);
+
+    if (aEvent) {
+      aEvent.preventDefault();
+    }
+  },
+
+  /**
+   * Copy declaration.
+   *
+   * @param aEvent The event object
+   */
+  computedViewCopyDeclaration: function si_computedViewCopyDeclaration(aEvent)
+  {
+    let node = this.doc.popupNode;
+    if (!node.classList.contains("property-view")) {
+      while (node = node.parentElement) {
+        if (node.classList.contains("property-view")) {
+          break;
+        }
+      }
+    }
+    if (node) {
+      let name = node.querySelector(".property-name").textContent;
+      let value = node.querySelector(".property-value").textContent;
+
+      clipboardHelper.copyString(name + ": " + value + ";");
+    }
+  },
+
+  /**
+   * Copy property name.
+   *
+   * @param aEvent The event object
+   */
+  computedViewCopyProperty: function si_computedViewCopyProperty(aEvent)
+  {
+    let node = this.doc.popupNode;
+    if (!node.classList.contains("property-view")) {
+      while (node = node.parentElement) {
+        if (node.classList.contains("property-view")) {
+          break;
+        }
+      }
+    }
+    if (node) {
+      node = node.querySelector(".property-name");
+      clipboardHelper.copyString(node.textContent);
+    }
+  },
+
+  /**
+   * Copy property value.
+   *
+   * @param aEvent The event object
+   */
+  computedViewCopyPropertyValue: function si_computedViewCopyPropertyValue(aEvent)
+  {
+    let node = this.doc.popupNode;
+    if (!node.classList.contains("property-view")) {
+      while (node = node.parentElement) {
+        if (node.classList.contains("property-view")) {
+          break;
+        }
+      }
+    }
+    if (node) {
+      node = node.querySelector(".property-value");
+      clipboardHelper.copyString(node.textContent);
+    }
+  },
+
+  /**
    * Destructor for CssHtmlTree.
    */
   destroy: function CssHtmlTree_destroy()
   {
     delete this.viewedElement;
 
     // Remove event listeners
     this.onlyUserStylesCheckbox.removeEventListener("command",
       this.onlyUserStylesChanged);
     this.searchField.removeEventListener("command", this.filterChanged);
 
     // Cancel tree construction
     if (this._refreshProcess) {
       this._refreshProcess.cancel();
     }
 
+    // Remove context menu
+    let menu = this.doc.querySelector("#computed-view-context-menu");
+    if (menu) {
+      // Copy selected
+      let menuitem = this.doc.querySelector("#computed-view-copy");
+      menuitem.removeEventListener("command", this.siBoundCopy);
+
+      // Copy property
+      menuitem = this.doc.querySelector("#computed-view-copy-declaration");
+      menuitem.removeEventListener("command", this.siBoundCopyDeclaration);
+
+      // Copy property name
+      menuitem = this.doc.querySelector("#computed-view-copy-property");
+      menuitem.removeEventListener("command", this.siBoundCopyProperty);
+
+      // Copy property value
+      menuitem = this.doc.querySelector("#computed-view-copy-property-value");
+      menuitem.removeEventListener("command", this.siBoundCopyPropertyValue);
+
+      menu.removeEventListener("popupshowing", this.siBoundMenuUpdate);
+      menu.parentNode.removeChild(menu);
+    }
+
+    // Remove bound listeners
+    this.styleDocument.removeEventListener("copy", this.siBoundCopy);
+
     // Nodes used in templating
     delete this.root;
     delete this.propertyContainer;
     delete this.panel;
 
     // The document in which we display the results (csshtmltree.xul).
     delete this.styleDocument;
 
@@ -653,42 +866,45 @@ PropertyView.prototype = {
     return "property-content-hidden";
   },
 
   buildMain: function PropertyView_buildMain()
   {
     let doc = this.tree.doc;
     this.element = doc.createElementNS(HTML_NS, "tr");
     this.element.setAttribute("class", this.propertyHeaderClassName);
-    this.element.addEventListener("click", this.propertyRowClick.bind(this), false);
 
     this.propertyHeader = doc.createElementNS(HTML_NS, "td");
     this.element.appendChild(this.propertyHeader);
     this.propertyHeader.setAttribute("class", "property-header");
 
     this.matchedExpander = doc.createElementNS(HTML_NS, "div");
-    this.propertyHeader.appendChild(this.matchedExpander);
     this.matchedExpander.setAttribute("class", "match expander");
-
-    this.nameNode = doc.createElementNS(HTML_NS, "div");
-    this.propertyHeader.appendChild(this.nameNode);
-    this.nameNode.setAttribute("tabindex", "0");
-    this.nameNode.addEventListener("keydown", function(aEvent) {
+    this.matchedExpander.setAttribute("tabindex", "0");
+    this.matchedExpander.addEventListener("click",
+      this.matchedExpanderClick.bind(this), false);
+    this.matchedExpander.addEventListener("keydown", function(aEvent) {
       let keyEvent = Ci.nsIDOMKeyEvent;
       if (aEvent.keyCode == keyEvent.DOM_VK_F1) {
         this.mdnLinkClick();
       }
       if (aEvent.keyCode == keyEvent.DOM_VK_RETURN ||
-          aEvent.keyCode == keyEvent.DOM_VK_SPACE) {
-        this.propertyRowClick(aEvent);
+        aEvent.keyCode == keyEvent.DOM_VK_SPACE) {
+        this.matchedExpanderClick(aEvent);
       }
     }.bind(this), false);
+    this.propertyHeader.appendChild(this.matchedExpander);
 
+    this.nameNode = doc.createElementNS(HTML_NS, "div");
+    this.propertyHeader.appendChild(this.nameNode);
     this.nameNode.setAttribute("class", "property-name");
     this.nameNode.textContent = this.name;
+    this.nameNode.addEventListener("click", function(aEvent) {
+      this.matchedExpander.focus();
+    }.bind(this), false);
 
     let helpcontainer = doc.createElementNS(HTML_NS, "td");
     this.element.appendChild(helpcontainer);
     helpcontainer.setAttribute("class", "helplink-container");
 
     let helplink = doc.createElementNS(HTML_NS, "a");
     helpcontainer.appendChild(helplink);
     helplink.setAttribute("class", "helplink");
@@ -749,19 +965,19 @@ PropertyView.prototype = {
    * Refresh the panel matched rules.
    */
   refreshMatchedSelectors: function PropertyView_refreshMatchedSelectors()
   {
     let hasMatchedSelectors = this.hasMatchedSelectors;
     this.matchedSelectorsContainer.parentNode.hidden = !hasMatchedSelectors;
 
     if (hasMatchedSelectors) {
-      this.propertyHeader.parentNode.classList.add("expandable");
+      this.matchedExpander.classList.add("expandable");
     } else {
-      this.propertyHeader.parentNode.classList.remove("expandable");
+      this.matchedExpander.classList.remove("expandable");
     }
 
     if (this.matchedExpanded && hasMatchedSelectors) {
       CssHtmlTree.processTemplate(this.templateMatchedSelectors,
         this.matchedSelectorsContainer, this);
       this.matchedExpander.setAttribute("open", "");
     } else {
       this.matchedSelectorsContainer.innerHTML = "";
@@ -847,27 +1063,23 @@ PropertyView.prototype = {
 
     return this._unmatchedSelectorViews;
   },
 
   /**
    * The action when a user expands matched selectors.
    *
    * @param {Event} aEvent Used to determine the class name of the targets click
-   * event. If the class name is "helplink" then the event is allowed to bubble
-   * to the mdn link icon.
+   * event.
    */
-  propertyRowClick: function PropertyView_propertyRowClick(aEvent)
+  matchedExpanderClick: function PropertyView_matchedExpanderClick(aEvent)
   {
-    if (aEvent.target.className != "helplink") {
-      this.matchedExpanded = !this.matchedExpanded;
-      this.refreshAllSelectors();
-      this.nameNode.focus();
-      aEvent.preventDefault();
-    }
+    this.matchedExpanded = !this.matchedExpanded;
+    this.refreshAllSelectors();
+    aEvent.preventDefault();
   },
 
   /**
    * The action when a user expands unmatched selectors.
    */
   unmatchedSelectorsClick: function PropertyView_unmatchedSelectorsClick(aEvent)
   {
     this.unmatchedExpanded = !this.unmatchedExpanded;
@@ -981,16 +1193,24 @@ SelectorView.prototype = {
           aEvent.preventDefault();
         }.bind(this), false);
       result += ".style";
     }
 
     return result;
   },
 
+  maybeOpenStyleEditor: function(aEvent)
+  {
+    let keyEvent = Ci.nsIDOMKeyEvent;
+    if (aEvent.keyCode == keyEvent.DOM_VK_RETURN) {
+      this.openStyleEditor();
+    }
+  },
+
   /**
    * When a css link is clicked this method is called in order to either:
    *   1. Open the link in view source (for element style attributes).
    *   2. Open the link in the style editor.
    *
    * @param aEvent The click event
    */
   openStyleEditor: function(aEvent)
--- a/browser/devtools/styleinspector/CssLogic.jsm
+++ b/browser/devtools/styleinspector/CssLogic.jsm
@@ -922,17 +922,18 @@ CssLogic.shortSource = function CssLogic
   if (url.filePath) {
     return url.filePath;
   }
 
   if (url.query) {
     return url.query;
   }
 
-  return aSheet.href;
+  let dataUrl = aSheet.href.match(/^(data:[^,]*),/);
+  return dataUrl ? dataUrl[1] : aSheet.href;
 }
 
 /**
  * A safe way to access cached bits of information about a stylesheet.
  *
  * @constructor
  * @param {CssLogic} aCssLogic pointer to the CssLogic instance working with
  * this CssSheet object.
--- a/browser/devtools/styleinspector/CssRuleView.jsm
+++ b/browser/devtools/styleinspector/CssRuleView.jsm
@@ -18,16 +18,17 @@
  * The Initial Developer of the Original Code is
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Dave Camp <dcamp@mozilla.com> (Original Author)
  *   Rob Campbell <rcampbell@mozilla.com>
+ *   Mike Ratcliffe <mratcliffe@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -802,34 +803,36 @@ CssRuleView.prototype = {
   /**
    * Creates editor UI for each of the rules in _elementStyle.
    */
   _createEditors: function CssRuleView_createEditors()
   {
     for each (let rule in this._elementStyle.rules) {
       // Don't hold a reference to this editor beyond the one held
       // by the node.
-      let editor = new RuleEditor(this.doc, rule);
+      let editor = new RuleEditor(this, rule);
       this.element.appendChild(editor.element);
     }
   },
 };
 
 /**
  * Create a RuleEditor.
  *
- * @param object aDoc
- *        The document holding this rule editor.
+ * @param CssRuleView aRuleView
+ *        The CssRuleView containg the document holding this rule editor and the
+ *        _selectionMode flag.
  * @param Rule aRule
  *        The Rule object we're editing.
  * @constructor
  */
-function RuleEditor(aDoc, aRule)
+function RuleEditor(aRuleView, aRule)
 {
-  this.doc = aDoc;
+  this.ruleView = aRuleView;
+  this.doc = this.ruleView.doc;
   this.rule = aRule;
 
   this._onNewProperty = this._onNewProperty.bind(this);
 
   this._create();
 }
 
 RuleEditor.prototype = {
@@ -888,18 +891,26 @@ RuleEditor.prototype = {
     this.closeBrace = createChild(code, "div", {
       class: "ruleview-ruleclose",
       tabindex: "0",
       textContent: "}"
     });
 
     // We made the close brace focusable, tabbing to it
     // or clicking on it should start the new property editor.
-    this.closeBrace.addEventListener("focus", function() {
-      this.newProperty();
+    this.closeBrace.addEventListener("focus", function(aEvent) {
+      if (!this.ruleView._selectionMode) {
+        this.newProperty();
+      }
+    }.bind(this), true);
+    this.closeBrace.addEventListener("mousedown", function(aEvent) {
+      aEvent.preventDefault();
+    }.bind(this), true);
+    this.closeBrace.addEventListener("click", function(aEvent) {
+      this.closeBrace.focus();
     }.bind(this), true);
   },
 
   /**
    * Create a text input for a property name.  If a non-empty property
    * name is given, we'll create a real TextProperty and add it to the
    * rule.
    */
@@ -1256,16 +1267,31 @@ TextPropertyEditor.prototype = {
  *       If any characters in advanceChars are typed, focus will advance
  *       to the next element.
  */
 function editableField(aOptions)
 {
   aOptions.element.addEventListener("focus", function() {
     new InplaceEditor(aOptions);
   }, false);
+
+  // In order to allow selection on the element, prevent focus on
+  // mousedown.  Focus on click instead.
+  aOptions.element.addEventListener("mousedown", function(evt) {
+    evt.preventDefault();
+  }, false);
+  aOptions.element.addEventListener("click", function(evt) {
+    let win = this.ownerDocument.defaultView;
+    let selection = win.getSelection();
+    if (selection.isCollapsed) {
+      aOptions.element.focus();
+    } else {
+      selection.removeAllRanges();
+    }
+  }, false);
 }
 var _editableField = editableField;
 
 function InplaceEditor(aOptions)
 {
   this.elt = aOptions.element;
   this.elt.inplaceEditor = this;
 
--- a/browser/devtools/styleinspector/StyleInspector.jsm
+++ b/browser/devtools/styleinspector/StyleInspector.jsm
@@ -50,17 +50,17 @@ var EXPORTED_SYMBOLS = ["StyleInspector"
  * StyleInspector Constructor Function.
  * @param {window} aContext, the chrome window context we're calling from.
  * @param {InspectorUI} aIUI (optional) An InspectorUI instance if called from the
  *        Highlighter.
  */
 function StyleInspector(aContext, aIUI)
 {
   this._init(aContext, aIUI);
-};
+}
 
 StyleInspector.prototype = {
 
   /**
    * Initialization method called from constructor.
    * @param {window} aContext, the chrome window context we're calling from.
    * @param {InspectorUI} aIUI (optional) An InspectorUI instance if called from
    *        the Highlighter.
--- a/browser/devtools/styleinspector/csshtmltree.xul
+++ b/browser/devtools/styleinspector/csshtmltree.xul
@@ -34,16 +34,17 @@
    - decision by deleting the provisions above and replace them with the notice
    - and other provisions required by the LGPL or the GPL. 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://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://browser/content/devtools/styleinspector.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/csshtmltree.css" type="text/css"?>
 
 <!DOCTYPE window [
   <!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/devtools/styleinspector.dtd">
   %inspectorDTD;
   <!ELEMENT loop ANY>
   <!ATTLIST li foreach CDATA #IMPLIED>
   <!ATTLIST div foreach CDATA #IMPLIED>
@@ -109,18 +110,21 @@ To visually debug the templates without 
   <div id="templateMatchedSelectors">
     <table>
       <loop foreach="selector in ${matchedSelectorViews}">
         <tr>
           <td dir="ltr" class="rule-text ${selector.statusClass}">
             ${selector.humanReadableText(__element)}
           </td>
           <td class="rule-link">
-            <a target="_blank" onclick="${selector.openStyleEditor}" class="link"
-               title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
+            <a target="_blank" class="link"
+               onclick="${selector.openStyleEditor}"
+               onkeydown="${selector.maybeOpenStyleEditor}"
+               title="${selector.selectorInfo.href}"
+               tabindex="0">${selector.selectorInfo.source}</a>
           </td>
         </tr>
       </loop>
     </table>
   </div>
 </div>
 
 </xul:window>
--- a/browser/devtools/styleinspector/styleinspector.css
+++ b/browser/devtools/styleinspector/styleinspector.css
@@ -30,21 +30,49 @@
  * 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 ***** */
 
+#root {
+  display: -moz-box;
+}
+
+.helplink {
+  display: block;
+}
+
+.expander,
+.property-name,
+.ruleview-propertyname,
+.ruleview-warning,
+.ruleview-expander {
+  display: inline-block;
+}
+
+#propertyContainer {
+  display: -moz-box;
+  -moz-box-orient: vertical;
+  -moz-box-flex: 1;
+  overflow-y: auto;
+  -moz-user-select: text;
+}
+
 .ruleview {
   overflow: auto;
+  -moz-user-select: text;
 }
 
-.ruleview-computedlist:not(.styleinspector-open) {
+.property-view-hidden,
+.property-content-hidden,
+.ruleview-computedlist:not(.styleinspector-open),
+.ruleview-warning[hidden] {
   display: none;
 }
 
 .ruleview-code {
   direction: ltr;
 }
 
 .ruleview-property:not(:hover) > .ruleview-enableproperty {
--- a/browser/devtools/styleinspector/test/Makefile.in
+++ b/browser/devtools/styleinspector/test/Makefile.in
@@ -60,16 +60,18 @@ include $(topsrcdir)/config/rules.mk
   browser_ruleview_manipulation.js \
   browser_ruleview_override.js \
   browser_ruleview_ui.js \
   browser_ruleview_focus.js \
   browser_bug705707_is_content_stylesheet.js \
   browser_bug722196_property_view_media_queries.js \
   browser_bug722196_rule_view_media_queries.js \
   browser_bug_592743_specificity.js \
+  browser_ruleview_bug_703643_context_menu_copy.js \
+  browser_computedview_bug_703643_context_menu_copy.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
   browser_bug683672.html \
   browser_bug705707_is_content_stylesheet.html \
   browser_bug705707_is_content_stylesheet_imported.css \
   browser_bug705707_is_content_stylesheet_imported2.css \
--- a/browser/devtools/styleinspector/test/browser_bug589375_keybindings.js
+++ b/browser/devtools/styleinspector/test/browser_bug589375_keybindings.js
@@ -50,36 +50,36 @@ function SI_test()
   Services.obs.removeObserver(SI_test, "StyleInspector-populated", false);
 
   info("checking keybindings");
 
   let iframe = stylePanel.iframe;
   let searchbar = stylePanel.cssHtmlTree.searchField;
   let propView = getFirstVisiblePropertyView();
   let rulesTable = propView.matchedSelectorsContainer;
-  let nameNode = propView.nameNode;
+  let matchedExpander = propView.matchedExpander;
 
-  info("Adding focus event handler to property name node");
-  nameNode.addEventListener("focus", function nameFocused() {
-    this.removeEventListener("focus", nameFocused);
-    info("property name is focused");
+  info("Adding focus event handler to property expander");
+  matchedExpander.addEventListener("focus", function expanderFocused() {
+    this.removeEventListener("focus", expanderFocused);
+    info("property expander is focused");
     info("checking expand / collapse");
     testKey(iframe.contentWindow, "VK_SPACE", rulesTable);
     testKey(iframe.contentWindow, "VK_RETURN", rulesTable);
 
     checkHelpLinkKeybinding();
     Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
     stylePanel.close();
   });
 
   info("Adding focus event handler to search filter");
   searchbar.addEventListener("focus", function searchbarFocused() {
     this.removeEventListener("focus", searchbarFocused);
     info("search filter is focused");
-    info("tabbing to property name node");
+    info("tabbing to property expander node");
     EventUtils.synthesizeKey("VK_TAB", {}, iframe.contentWindow);
   });
 
   info("Making sure that the style inspector panel is focused");
   SimpleTest.waitForFocus(function windowFocused() {
     info("window is focused");
     info("focusing search filter");
     searchbar.focus();
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_computedview_bug_703643_context_menu_copy.js
@@ -0,0 +1,163 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the style inspector works properly
+
+let doc;
+let stylePanel;
+let cssHtmlTree;
+
+function createDocument()
+{
+  doc.body.innerHTML = '<style type="text/css"> ' +
+    'span { font-variant: small-caps; color: #000000; } ' +
+    '.nomatches {color: #ff0000;}</style> <div id="first" style="margin: 10em; ' +
+    'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">\n' +
+    '<h1>Some header text</h1>\n' +
+    '<p id="salutation" style="font-size: 12pt">hi.</p>\n' +
+    '<p id="body" style="font-size: 12pt">I am a test-case. This text exists ' +
+    'solely to provide some things to <span style="color: yellow">' +
+    'highlight</span> and <span style="font-weight: bold">count</span> ' +
+    'style list-items in the box at right. If you are reading this, ' +
+    'you should go do something else instead. Maybe read a book. Or better ' +
+    'yet, write some test-cases for another bit of code. ' +
+    '<span style="font-style: italic">some text</span></p>\n' +
+    '<p id="closing">more text</p>\n' +
+    '<p>even more text</p>' +
+    '</div>';
+  doc.title = "Computed view context menu test";
+
+  let span = doc.querySelector("span");
+  ok(span, "captain, we have the span");
+
+  stylePanel = new StyleInspector(window);
+  Services.obs.addObserver(runStyleInspectorTests, "StyleInspector-populated", false);
+  stylePanel.createPanel(false, function() {
+    stylePanel.open(span);
+  });
+}
+
+function runStyleInspectorTests()
+{
+  Services.obs.removeObserver(runStyleInspectorTests, "StyleInspector-populated", false);
+
+  ok(stylePanel.isOpen(), "style inspector is open");
+
+  cssHtmlTree = stylePanel.cssHtmlTree;
+
+  let contentDocument = stylePanel.iframe.contentDocument;
+  let prop = contentDocument.querySelector(".property-view");
+  ok(prop, "captain, we have the property-view node");
+
+  // We need the context menu to open in the correct place in order for
+  // popupNode to be propertly set.
+  EventUtils.synthesizeMouse(prop, 1, 1, { type: "contextmenu", button: 2 },
+    stylePanel.iframe.contentWindow);
+
+  checkCopyProperty()
+}
+
+function checkCopyProperty()
+{
+  info("Checking that cssHtmlTree.siBoundCopyDeclaration() returns the " +
+       "correct clipboard value");
+  let expectedPattern = "color: rgb\\(255, 255, 0\\);";
+  info("Expected pattern: " + expectedPattern);
+
+  SimpleTest.waitForClipboard(function CS_boundCopyPropCheck() {
+      return checkClipboardData(expectedPattern);
+    },
+    cssHtmlTree.siBoundCopyDeclaration,
+    checkCopyPropertyName, checkCopyPropertyName);
+}
+
+function checkCopyPropertyName()
+{
+  info("Checking that cssHtmlTree.siBoundCopyProperty() returns the " +
+       "correct clipboard value");
+  let expectedPattern = "color";
+  info("Expected pattern: " + expectedPattern);
+
+  SimpleTest.waitForClipboard(function CS_boundCopyPropNameCheck() {
+      return checkClipboardData(expectedPattern);
+    },
+    cssHtmlTree.siBoundCopyProperty,
+    checkCopyPropertyValue, checkCopyPropertyValue);
+}
+
+function checkCopyPropertyValue()
+{
+  info("Checking that cssHtmlTree.siBoundCopyPropertyValue() returns the " +
+       "correct clipboard value");
+  let expectedPattern = "rgb\\(255, 255, 0\\)";
+  info("Expected pattern: " + expectedPattern);
+
+  SimpleTest.waitForClipboard(function CS_boundCopyPropValueCheck() {
+      return checkClipboardData(expectedPattern);
+    },
+    cssHtmlTree.siBoundCopyPropertyValue,
+    checkCopySelection, checkCopySelection);
+}
+
+function checkCopySelection()
+{
+  let contentDocument = stylePanel.iframe.contentDocument;
+  let contentWindow = stylePanel.iframe.contentWindow;
+  let props = contentDocument.querySelectorAll(".property-view");
+  ok(props, "captain, we have the property-view nodes");
+
+  let range = document.createRange();
+  range.setStart(props[0], 0);
+  range.setEnd(props[3], 3);
+  contentWindow.getSelection().addRange(range);
+
+  info("Checking that cssHtmlTree.siBoundCopyPropertyValue() " +
+       " returns the correct clipboard value");
+
+  let expectedPattern = "color: rgb\\(255, 255, 0\\)[\\r\\n]+" +
+                 "font-family: helvetica,sans-serif[\\r\\n]+" +
+                 "font-size: 16px[\\r\\n]+" +
+                 "font-variant: small-caps[\\r\\n]*";
+  info("Expected pattern: " + expectedPattern);
+
+  SimpleTest.waitForClipboard(function CS_boundCopyCheck() {
+      return checkClipboardData(expectedPattern);
+    },
+    cssHtmlTree.siBoundCopy, closeStyleInspector, closeStyleInspector);
+}
+
+function checkClipboardData(aExpectedPattern)
+{
+  let actual = SpecialPowers.getClipboardData("text/unicode");
+  let expectedRegExp = new RegExp(aExpectedPattern, "g");
+  return expectedRegExp.test(actual);
+}
+
+function closeStyleInspector()
+{
+  Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
+  stylePanel.close();
+}
+
+function finishUp()
+{
+  Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
+  ok(!stylePanel.isOpen(), "style inspector is closed");
+  doc = stylePanel = cssHtmlTree = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
+    doc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html,computed view context menu test";
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_bug_703643_context_menu_copy.js
@@ -0,0 +1,209 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let doc;
+
+function createDocument()
+{
+  doc.body.innerHTML = '<style type="text/css"> ' +
+    'html { color: #000000; } ' +
+    'span { font-variant: small-caps; color: #000000; } ' +
+    '.nomatches {color: #ff0000;}</style> <div id="first" style="margin: 10em; ' +
+    'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA">\n' +
+    '<h1>Some header text</h1>\n' +
+    '<p id="salutation" style="font-size: 12pt">hi.</p>\n' +
+    '<p id="body" style="font-size: 12pt">I am a test-case. This text exists ' +
+    'solely to provide some things to <span style="color: yellow">' +
+    'highlight</span> and <span style="font-weight: bold">count</span> ' +
+    'style list-items in the box at right. If you are reading this, ' +
+    'you should go do something else instead. Maybe read a book. Or better ' +
+    'yet, write some test-cases for another bit of code. ' +
+    '<span style="font-style: italic">some text</span></p>\n' +
+    '<p id="closing">more text</p>\n' +
+    '<p>even more text</p>' +
+    '</div>';
+  doc.title = "Rule view context menu test";
+
+  openInspector();
+}
+
+function openInspector()
+{
+  ok(window.InspectorUI, "InspectorUI variable exists");
+  ok(!InspectorUI.inspecting, "Inspector is not highlighting");
+  ok(InspectorUI.store.isEmpty(), "Inspector.store is empty");
+
+  Services.obs.addObserver(inspectorUIOpen,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
+  InspectorUI.openInspectorUI();
+}
+
+function inspectorUIOpen()
+{
+  Services.obs.removeObserver(inspectorUIOpen,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
+
+  // Make sure the inspector is open.
+  ok(InspectorUI.inspecting, "Inspector is highlighting");
+  ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
+  ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
+  ok(!InspectorUI.store.isEmpty(), "InspectorUI.store is not empty");
+  is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
+
+  // Highlight a node.
+  let div = content.document.getElementsByTagName("div")[0];
+  InspectorUI.inspectNode(div);
+  InspectorUI.stopInspecting();
+  is(InspectorUI.selection, div, "selection matches the div element");
+
+  Services.obs.addObserver(testClip,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
+
+  InspectorUI.showSidebar();
+  InspectorUI.openRuleView();
+}
+
+function testClip()
+{
+  Services.obs.removeObserver(testClip,
+    InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
+
+  executeSoon(function() {
+    info("Checking that InspectorUI.ruleViewCopyRule() returns " +
+         "the correct clipboard value");
+    let expectedPattern = "element {[\\r\\n]+" +
+      "    margin: 10em;[\\r\\n]+" +
+      "    font-size: 14pt;[\\r\\n]+" +
+      "    font-family: helvetica,sans-serif;[\\r\\n]+" +
+      "    color: rgb\\(170, 170, 170\\);[\\r\\n]+" +
+      "}[\\r\\n]*";
+    info("Expected pattern: " + expectedPattern);
+
+    SimpleTest.waitForClipboard(function IUI_boundCopyPropCheck() {
+        return checkClipboardData(expectedPattern);
+      },
+      checkCopyRule, checkCopyProperty, checkCopyProperty);
+  });
+}
+
+function checkCopyRule() {
+  let ruleView = document.querySelector("#devtools-sidebar-iframe-ruleview");
+  let contentDoc = ruleView.contentDocument;
+  let props = contentDoc.querySelectorAll(".ruleview-property");
+
+  is(props.length, 5, "checking property length");
+
+  let prop = props[2];
+  let propName = prop.querySelector(".ruleview-propertyname").textContent;
+  let propValue = prop.querySelector(".ruleview-propertyvalue").textContent;
+
+  is(propName, "font-family", "checking property name");
+  is(propValue, "helvetica,sans-serif", "checking property value");
+
+  // We need the context menu to open in the correct place in order for
+  // popupNode to be propertly set.
+  EventUtils.synthesizeMouse(prop, 1, 1, { type: "contextmenu", button: 2 },
+    ruleView.contentWindow);
+
+  InspectorUI.ruleViewCopyRule();
+}
+
+function checkCopyProperty()
+{
+  info("Checking that InspectorUI.cssRuleViewBoundCopyDeclaration() returns " +
+       "the correct clipboard value");
+  let expectedPattern = "font-family: helvetica,sans-serif;";
+  info("Expected pattern: " + expectedPattern);
+
+  SimpleTest.waitForClipboard(function IUI_boundCopyPropCheck() {
+      return checkClipboardData(expectedPattern);
+    },
+    InspectorUI.cssRuleViewBoundCopyDeclaration,
+    checkCopyPropertyName, checkCopyPropertyName);
+}
+
+function checkCopyPropertyName()
+{
+  info("Checking that InspectorUI.cssRuleViewBoundCopyProperty() returns " +
+       "the correct clipboard value");
+  let expectedPattern = "font-family";
+  info("Expected pattern: " + expectedPattern);
+
+  SimpleTest.waitForClipboard(function IUI_boundCopyPropNameCheck() {
+      return checkClipboardData(expectedPattern);
+    },
+    InspectorUI.cssRuleViewBoundCopyProperty,
+    checkCopyPropertyValue, checkCopyPropertyValue);
+}
+
+function checkCopyPropertyValue()
+{
+  info("Checking that InspectorUI.cssRuleViewBoundCopyPropertyValue() " +
+       " returns the correct clipboard value");
+  let expectedPattern = "helvetica,sans-serif";
+  info("Expected pattern: " + expectedPattern);
+
+  SimpleTest.waitForClipboard(function IUI_boundCopyPropValueCheck() {
+      return checkClipboardData(expectedPattern);
+    },
+    InspectorUI.cssRuleViewBoundCopyPropertyValue,
+    checkCopySelection, checkCopySelection);
+}
+
+function checkCopySelection()
+{
+  let ruleView = document.querySelector("#devtools-sidebar-iframe-ruleview");
+  let contentDoc = ruleView.contentDocument;
+  let props = contentDoc.querySelectorAll(".ruleview-property");
+
+  let range = document.createRange();
+  range.setStart(props[0], 0);
+  range.setEnd(props[4], 8);
+  ruleView.contentWindow.getSelection().addRange(range);
+
+  info("Checking that InspectorUI.cssRuleViewBoundCopy()  returns the correct" +
+       "clipboard value");
+  let expectedPattern = "    margin: 10em;[\\r\\n]+" +
+                        "    font-size: 14pt;[\\r\\n]+" +
+                        "    font-family: helvetica,sans-serif;[\\r\\n]+" +
+                        "    color: rgb\\(170, 170, 170\\);[\\r\\n]+" +
+                        "}[\\r\\n]+" +
+                        "html {[\\r\\n]+" +
+                        "    color: rgb\\(0, 0, 0\\);[\\r\\n]*";
+  info("Expected pattern: " + expectedPattern);
+
+  SimpleTest.waitForClipboard(function IUI_boundCopyCheck() {
+      return checkClipboardData(expectedPattern);
+    },InspectorUI.cssRuleViewBoundCopy, finishup, finishup);
+}
+
+function checkClipboardData(aExpectedPattern)
+{
+  let actual = SpecialPowers.getClipboardData("text/unicode");
+  let expectedRegExp = new RegExp(aExpectedPattern, "g");
+  return expectedRegExp.test(actual);
+}
+
+function finishup()
+{
+  InspectorUI.closeInspectorUI();
+  gBrowser.removeCurrentTab();
+  doc = null;
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function(evt) {
+    gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
+      true);
+    doc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+
+  content.location = "data:text/html,<p>rule view context menu test</p>";
+}
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -139,16 +139,17 @@
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.xpt
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/content_xtf.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
+@BINPATH@/components/dom_apps.xpt
 @BINPATH@/components/dom_base.xpt
 #ifdef MOZ_B2G_RIL
 @BINPATH@/components/dom_telephony.xpt
 @BINPATH@/components/dom_wifi.xpt
 @BINPATH@/components/dom_system_b2g.xpt
 #endif
 @BINPATH@/components/dom_battery.xpt
 #ifdef MOZ_B2G_BT
@@ -405,16 +406,18 @@
 #ifdef MOZ_SERVICES_SYNC
 @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/Webapps.js
+@BINPATH@/components/Webapps.manifest
 
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
 
 ; Modules
 @BINPATH@/modules/*
 
 ; Safe Browsing
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -208,18 +208,16 @@ can reach it easily. -->
   -  "Scratchpad" in your locale. You should feel free to find a close
   -  approximation to it or choose a word (or words) that means
   -  "simple discardable text editor". -->
 <!ENTITY scratchpad.label             "Scratchpad">
 <!ENTITY scratchpad.accesskey         "s">
 <!ENTITY scratchpad.keycode           "VK_F4">
 <!ENTITY scratchpad.keytext           "F4">
 
-<!ENTITY inspectButton.label            "Inspect">
-<!ENTITY inspectButton.accesskey        "I">
 <!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
 
 <!ENTITY inspectorHTMLCopyInner.label       "Copy Inner HTML">
 <!ENTITY inspectorHTMLCopyInner.accesskey   "I">
 
 <!ENTITY inspectorHTMLCopyOuter.label       "Copy Outer HTML">
 <!ENTITY inspectorHTMLCopyOuter.accesskey   "O">
 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -329,16 +329,22 @@ syncPromoNotification.learnMoreLinkText=
 # 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
 
+# Webapps notification popup
+webapps.install = Install
+webapps.install.accesskey = I
+#LOCALIZATION NOTE (webapps.requestInstall) %1$S is the web app name, %2$S is the site from which the web app is installed
+webapps.requestInstall = Do you want to install "%1$S" from this site (%2$S)?
+
 # Keyword.URL reset prompt
 # LOCALIZATION NOTE (keywordPrompt.message):
 #  - %1$S is brandShortName
 #  - %2$S is a host name (e.g. "somewebsearch.com") from the current value of keyword.URL
 #  - %3$S is the name of the default search engine (e.g. "Google")
 keywordPrompt.message = %1$S is using '%2$S' for searches from the location bar. Would you like to restore the default search (%3$S)?
 
 # LOCALIZATION NOTE (keywordPrompt.yesButton): %1$S is the name of the default search engine
--- a/browser/locales/en-US/chrome/browser/devtools/inspector.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/inspector.properties
@@ -20,8 +20,15 @@ breadcrumbs.siblings=Siblings
 # LOCALIZATION NOTE (htmlPanel): Used in the Inspector tool's openInspectorUI
 # method when registering the HTML panel.
 
 # LOCALIZATION NOTE (ruleView.*): Button label, accesskey and tooltip text
 # associated with the Highlighter's CSS Rule View in the Style Sidebar.
 ruleView.label=Rules
 ruleView.accesskey=R
 ruleView.tooltiptext=View and Edit CSS
+
+# LOCALIZATION NOTE (inspectButton.tooltiptext):
+# This button appears in the Inspector Toolbar. inspectButton is stateful,
+# if it's pressed users can select an element with the mouse. Pressing the
+# "Return" key # changes that state. %S is the keyboard shortcut (VK_RETURN in
+# chrome://global/locale/keys.properties).
+inspectButton.tooltiptext=Select element with mouse (%S)
--- a/browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/styleinspector.properties
@@ -44,8 +44,80 @@ style.highlighter.button.tooltip2=Inspec
 # quickly jump to the documentation from the Mozilla Developer Network site.
 # This is the link title shown in the hover tooltip.
 helpLinkTitle=Read the documentation for this property
 
 # LOCALIZATION NOTE (rule.warning.title): When an invalid property value is
 # entered into the rule view a warning icon is displayed. This text is used for
 # the title attribute of the warning icon.
 rule.warning.title=Invalid property value
+
+# LOCALIZATION NOTE (style.contextmenu.copyselection): The computed view's
+# context menu copy entry.
+style.contextmenu.copyselection=Copy selection
+
+# LOCALIZATION NOTE (style.contextmenu.copyselection.accesskey): The computed
+# view's context menu copy entry access key.
+style.contextmenu.copyselection.accesskey=C
+
+# LOCALIZATION NOTE (style.contextmenu.copydeclaration): The style inspector's
+# context menu copy property entry allows a complete CSS property to be copied.
+style.contextmenu.copydeclaration=Copy declaration line
+
+# LOCALIZATION NOTE (style.contextmenu.copydeclaration.accesskey): The style
+# inspector's context menu copy property access key.
+style.contextmenu.copydeclaration.accesskey=D
+
+# LOCALIZATION NOTE (style.contextmenu.copyproperty): The style inspector's
+# context menu copy property name entry allows a CSS property name to be copied.
+style.contextmenu.copyproperty=Copy property
+
+# LOCALIZATION NOTE (style.contextmenu.copyproperty.accesskey): The style
+# inspector's context menu copy property name access key.
+style.contextmenu.copyproperty.accesskey=P
+
+# LOCALIZATION NOTE (style.contextmenu.copypropertyvalue): The style inspector's
+# context menu copy property value entry allows a CSS property name to be copied.
+style.contextmenu.copypropertyvalue=Copy property value
+
+# LOCALIZATION NOTE (style.contextmenu.copypropertyvalue.accesskey): The style
+# inspector's context menu copy property value access key.
+style.contextmenu.copypropertyvalue.accesskey=U
+
+# LOCALIZATION NOTE (rule.contextmenu.copyselection): The rule view's context
+# menu copy entry.
+rule.contextmenu.copyselection=Copy selection
+
+# LOCALIZATION NOTE (rule.contextmenu.copyselection.accesskey): The rule view's
+# context menu copy entry access key.
+rule.contextmenu.copyselection.accesskey=C
+
+# LOCALIZATION NOTE (rule.contextmenu.copyrule): The rule view's context menu
+# copy rule entry allows a complete CSS rule to be copied.
+rule.contextmenu.copyrule=Copy rule
+
+# LOCALIZATION NOTE (rule.contextmenu.copyrule.accesskey): The rule view's
+# context menu copy rule access key.
+rule.contextmenu.copyrule.accesskey=R
+
+# LOCALIZATION NOTE (rule.contextmenu.copydeclaration): The rule view's context
+# menu copy property entry allows a complete CSS property to be copied.
+rule.contextmenu.copydeclaration=Copy declaration line
+
+# LOCALIZATION NOTE (rule.contextmenu.copydeclaration.accesskey): The rule view's
+# context menu copy property access key.
+rule.contextmenu.copydeclaration.accesskey=D
+
+# LOCALIZATION NOTE (rule.contextmenu.copyproperty): The rule view's context
+# menu copy property entry allows a CSS property name to be copied.
+rule.contextmenu.copyproperty=Copy property
+
+# LOCALIZATION NOTE (rule.contextmenu.copyproperty.accesskey): The rule
+# view's context menu copy property name access key.
+rule.contextmenu.copyproperty.accesskey=P
+
+# LOCALIZATION NOTE (rule.contextmenu.copypropertyvalue): The rule view's
+# context menu copy property entry allows a CSS property value to be copied.
+rule.contextmenu.copypropertyvalue=Copy property value
+
+# LOCALIZATION NOTE (rule.contextmenu.copypropertyvalue.accesskey): The rule
+# view's context menu copy property value access key.
+rule.contextmenu.copypropertyvalue.accesskey=U
--- a/browser/locales/en-US/chrome/browser/newTab.dtd
+++ b/browser/locales/en-US/chrome/browser/newTab.dtd
@@ -1,6 +1,2 @@
 <!-- These strings are used in the about:newtab page -->
 <!ENTITY newtab.pageTitle "New Tab">
-
-<!ENTITY newtab.show "Show the New Tab Page">
-<!ENTITY newtab.hide "Hide the New Tab Page">
-<!ENTITY newtab.reset "Reset the New Tab Page">
--- a/browser/locales/en-US/chrome/browser/newTab.properties
+++ b/browser/locales/en-US/chrome/browser/newTab.properties
@@ -1,3 +1,5 @@
 newtab.pin=Pin this site at its current position
 newtab.unpin=Unpin this site
 newtab.block=Remove this site
+newtab.show=Show the new tab page
+newtab.hide=Hide the new tab page
--- a/browser/modules/Makefile.in
+++ b/browser/modules/Makefile.in
@@ -48,16 +48,17 @@ TEST_DIRS += test
 
 EXTRA_JS_MODULES = \
 	openLocationLastURL.jsm \
 	NetworkPrioritizer.jsm \
 	NewTabUtils.jsm \
 	offlineAppCache.jsm \
 	TelemetryTimestamps.jsm \
 	KeywordURLResetPrompter.jsm \
+	webappsUI.jsm \
 	$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows) 
 EXTRA_JS_MODULES += \
 	WindowsPreviewPerTab.jsm \
 	WindowsJumpLists.jsm \
 	$(NULL)
 endif
new file mode 100644
--- /dev/null
+++ b/browser/modules/webappsUI.jsm
@@ -0,0 +1,133 @@
+/* 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/. */
+
+let EXPORTED_SYMBOLS = ["webappsUI"];
+
+let Ci = Components.interfaces;
+let Cc = Components.classes;
+let Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Webapps.jsm");
+
+let webappsUI = {
+  init: function webappsUI_init() {
+    Services.obs.addObserver(this, "webapps-ask-install", false);
+    Services.obs.addObserver(this, "webapps-launch", false);
+  },
+  
+  uninit: function webappsUI_uninit() {
+    Services.obs.removeObserver(this, "webapps-ask-install");
+    Services.obs.removeObserver(this, "webapps-launch");
+  },
+
+  observe: function webappsUI_observe(aSubject, aTopic, aData) {
+    let data = JSON.parse(aData);
+
+    switch(aTopic) {
+      case "webapps-ask-install":
+        let [chromeWin, browser] = this._getBrowserForId(data.oid);
+        if (chromeWin)
+          this.doInstall(data, browser, chromeWin);
+        break;
+      case "webapps-launch":
+        DOMApplicationRegistry.getManifestFor(data.origin, (function(aManifest) {
+          if (!aManifest)
+            return;
+          let manifest = new DOMApplicationManifest(aManifest, data.origin);
+          this.openURL(manifest.fullLaunchPath(), data.origin);
+        }).bind(this));
+        break;
+    }
+  },
+
+  openURL: function(aUrl, aOrigin) {
+    let browserEnumerator = Services.wm.getEnumerator("navigator:browser");  
+    let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
+
+    // Check each browser instance for our URL
+    let found = false;
+    while (!found && browserEnumerator.hasMoreElements()) {
+      let browserWin = browserEnumerator.getNext();
+      let tabbrowser = browserWin.gBrowser;
+
+      // Check each tab of this browser instance
+      let numTabs = tabbrowser.tabs.length;
+      for (let index = 0; index < numTabs; index++) {
+        let tab = tabbrowser.tabs[index];
+        let appURL = ss.getTabValue(tab, "appOrigin");
+        if (appURL == aOrigin) {
+          // The URL is already opened. Select this tab.
+          tabbrowser.selectedTab = tab;
+          browserWin.focus();
+          found = true;
+          break;
+        }
+      }
+    }
+
+    // Our URL isn't open. Open it now.
+    if (!found) {
+      let recentWindow = Services.wm.getMostRecentWindow("navigator:browser");
+      if (recentWindow) {
+        // Use an existing browser window
+        let browser = recentWindow.gBrowser;
+        let tab = browser.addTab(aUrl);
+        browser.pinTab(tab);
+        browser.selectedTab = tab;
+        ss.setTabValue(tab, "appOrigin", aOrigin);
+      }
+    }
+  },
+
+  _getBrowserForId: function(aId) {
+    let someWindow = Services.wm.getMostRecentWindow(null);
+
+    if (someWindow) {
+      let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                  .getInterface(Ci.nsIDOMWindowUtils);
+      let content = windowUtils.getOuterWindowWithId(aId);
+      if (content) {
+        let browser = content.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIWebNavigation)
+                      .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
+        let win = browser.ownerDocument.defaultView;
+        return [win, browser];
+      }
+    }
+
+    return [null, null];
+  },
+
+  doInstall: function(aData, aBrowser, aWindow) {
+    let bundle = aWindow.gNavigatorBundle;
+
+    let mainAction = {
+      label: bundle.getString("webapps.install"),
+      accessKey: bundle.getString("webapps.install.accesskey"),
+      callback: function(notification) {
+        installDone = true;
+        DOMApplicationRegistry.confirmInstall(aData);
+      }
+    };
+
+    let requestingURI = aWindow.makeURI(aData.from);
+    let manifest = new DOMApplicationManifest(aData.app.manifest, aData.app.origin);
+
+    let host;
+    try {
+      host = requestingURI.host;
+    } catch(e) {
+      host = requestingURI.spec;
+    }
+
+    let message = bundle.getFormattedString("webapps.requestInstall",
+                                            [manifest.name, host], 2);
+
+    aWindow.PopupNotifications.show(aBrowser, "webapps-install", message, "webapps-notification-icon",
+                                                       mainAction, null, { popupIconURL: manifest.iconURLForSize(64) });
+
+  }
+}
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -1225,16 +1225,20 @@ toolbar[iconsize="small"] #feed-button {
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
 .popup-notification-icon[popupid="password-save"],
 .popup-notification-icon[popupid="password-change"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
 }
 
+.popup-notification-icon[popupid="webapps-install"] {
+  list-style-image: url(chrome://browser/skin/webapps-64.png);
+}
+
 /* Notification icon box */
 #notification-popup-box {
   position: relative;
   background-color: #fff;
   background-clip: padding-box;
   padding-left: 4px;
   border-radius: 2.5px 0 0 2.5px;
   border-width: 0 8px 0 0;
@@ -1279,16 +1283,20 @@ toolbar[iconsize="small"] #feed-button {
 #indexedDB-notification-icon {
   list-style-image: url(chrome://global/skin/icons/question-16.png);
 }
 
 #password-notification-icon {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
 }
 
+#webapps-notification-icon {
+  list-style-image: url(chrome://browser/skin/webapps-16.png);
+}
+
 #treecolAutoCompleteImage {
   max-width : 36px; 
 }
 
 .ac-result-type-bookmark,
 .autocomplete-treebody::-moz-tree-image(bookmark, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/pageStarred.png");
   width: 16px;
@@ -1983,16 +1991,25 @@ panel[dimmed="true"] {
 
 #highlighter-veil-container[locked] > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
 
 /* Highlighter toolbar */
 
+#inspector-inspect-toolbutton {
+  list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
+  -moz-image-region: rect(0px 16px 16px 0px);
+}
+
+#inspector-inspect-toolbutton[checked] {
+  -moz-image-region: rect(0px 32px 16px 16px);
+}
+
 #inspector-toolbar {
   border-top: 1px solid hsla(210, 8%, 5%, .65);
 }
 
 #devtools-side-splitter {
   -moz-appearance: none;
   border: 0;
   -moz-border-start: 1px solid #242b33;
--- a/browser/themes/gnomestripe/devtools/common.css
+++ b/browser/themes/gnomestripe/devtools/common.css
@@ -52,16 +52,20 @@
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border: 1px solid hsla(210,8%,5%,.45);
   border-radius: 3px;
   background: -moz-linear-gradient(hsla(212,7%,57%,.35), hsla(212,7%,57%,.1)) padding-box;
   box-shadow: 0 1px 0 hsla(210,16%,76%,.15) inset, 0 0 0 1px hsla(210,16%,76%,.15) inset, 0 1px 0 hsla(210,16%,76%,.15);
   margin: 0 3px;
 }
 
+.devtools-toolbarbutton:not([label]) {
+  min-width: 32px;
+}
+
 .devtools-toolbarbutton:not([checked]):hover:active {
   border-color: hsla(210,8%,5%,.6);
   background: -moz-linear-gradient(hsla(220,6%,10%,.3), hsla(212,7%,57%,.15) 65%, hsla(212,7%,57%,.3));
   box-shadow: 0 0 3px hsla(210,8%,5%,.25) inset, 0 1px 3px hsla(210,8%,5%,.25) inset, 0 1px 0 hsla(210,16%,76%,.15);
 }
 
 .devtools-toolbarbutton[checked] {
   color: hsl(208,100%,60%) !important;
--- a/browser/themes/gnomestripe/devtools/csshtmltree.css
+++ b/browser/themes/gnomestripe/devtools/csshtmltree.css
@@ -40,21 +40,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 :root {
   -moz-appearance: none;
   background: -moz-Field;
   color: -moz-FieldText;
 }
 
-#root {
-  display: -moz-box;
-}
-
-
 .property-header {
   padding: 5px 0;
   white-space: nowrap;
   vertical-align: text-top;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
@@ -68,17 +63,16 @@
 .helplink:visited {
   text-decoration: none;
 }
 .link:hover {
   text-decoration: underline;
 }
 
 .helplink {
-  display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
   -moz-margin-end: 2px;
   cursor: pointer;
 }
@@ -92,54 +86,44 @@
   padding: 0;
 }
 
 .expander {
   -moz-appearance: treetwisty;
   padding-top: 12px;
   -moz-margin-start: 5px;
   -moz-margin-end: 5px;
-  display: inline-block;
   vertical-align: middle;
 }
 
 .expander[open] {
   -moz-appearance: treetwistyopen;
 }
 
-.expandable {
-  cursor: pointer;
-}
-
 .match {
   visibility: hidden;
 }
 
-.expandable > .property-header > .match {
+.expandable {
+  cursor: pointer;
   visibility: visible;
 }
 
 .property-name {
   font-size: 12px;
   color: -moz-FieldText;
-  display: inline-block;
 }
 .property-value {
   padding: 0;
   font-size: 10px;
   color: grey;
   vertical-align: text-top;
   width: 100%;
 }
 
-.property-view-hidden,
-.property-content-hidden {
-  display: none;
-}
-
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
   cursor: pointer;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
@@ -155,20 +139,16 @@
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 
 #propertyContainer {
-  display: -moz-box;
-  -moz-box-orient: vertical;
-  -moz-box-flex: 1;
-  overflow-y: auto;
   border-collapse: collapse;
 }
 
 .darkrow {
   background-color: rgba(0,0,0,.022);
 }
 
 #noResults {
@@ -215,46 +195,45 @@
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
 .ruleview-warning {
   background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  display: inline-block;
   -moz-margin-start: 5px;
   vertical-align: middle;
   width: 13px;
   height: 12px;
 }
 
-.ruleview-warning[hidden] {
-  display: none;
+.ruleview-ruleopen {
+  -moz-padding-end: 5px;
 }
 
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
+.ruleview-ruleclose {
+  width: -moz-min-content;
+  padding-right: 20px;
 }
 
 .ruleview-propertylist {
   list-style: none;
   padding: 0;
   margin: 0;
 }
 
 .ruleview-enableproperty {
   height: 10px;
   width: 10px;
   -moz-margin-start: 2px;
   -moz-margin-end: 0;
 }
 
 .ruleview-expander {
-  display: inline-block;
   width: 8px;
   height: 8px;
   background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
   cursor: pointer;
   -moz-margin-start: 2px;
   -moz-margin-end: 5px;
 }
 
@@ -263,17 +242,16 @@
 }
 
 .ruleview-newproperty {
   /* (enable checkbox width: 12px) + (expander width: 15px) */
   -moz-margin-start: 27px;
 }
 
 .ruleview-propertyname {
-  display: inline-block;
   padding: 1px 0;
   cursor: text;
   color: #0060C0;
   text-decoration: inherit;
 }
 
 .ruleview-propertyvalue {
   cursor: text;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ebfd9586d201416665b64e4fe57af05c1a967edb
GIT binary patch
literal 1321
zc$@(#1=jkBP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyS_
z05usk)smk800gN?L_t(Y$K{l1Y*a-6$A9zQUOjeu&=$I-(1MhZQV@|K5n=%`MvM?t
zA|`@dO7J!qFc>BJ$;23=h#Yc<s2CDN3J3&>fIzuKkaEc(bPMg$?RMGSw{PBi;|CV9
z7z})OKEBCs<~RTOzk&bz5CHDHpa&=b@&Wff7zwlk5g84c0IXFykPT!3`aO6XNCFAQ
z3)_|cSh#q>m(xc-^<>rkSl4aZa^{tpZ!Q6@0?>LXcW71c^IWfc%Kh*+QgYdzGog2Z
z=q-WbQKLqdTecIsp9MyZ8d(k$-x3g!=76GX;?;zGU$N)tVxovN&r=x!Ihv-Y0A8Lp
zBeG*>ePcT6%;6p}ytdDZZx<G5nr;I*w`Za)SuxXbDd5_lhd&MPUSE$itUGC+t7zER
z+RoJjXUA+@L|d`|Tp3-k0Cw!GZ%~Q@0yG4Ez*35MdM*Zx%<Rw2Ta`juH}`8jao{KI
z*tWB(xI$3T&qFHdh%@_5jF@Q6>)hU{cmLV9m`njOP8<QkLQuZ9e%q7{b(@=(EM2~@
ztu1mzK}#Z$l-b!?sI>5HSf=s3l6Km!U3X@!EgW1?vN3L{_2=WPN=Q2_4sK{OP16uU
z_(&xk0PSA_Qh;N3gcMNNsi>GYX1>~E_l~VEe*EFwm&!^@ONS1B{OsyA-(5|M-XS2R
z1h?0*J3>l?FZ;uZR4<{dd3|!NhHAh1#NTT`$(8-vC&j~8*AQ)q|5pNDcV18jyk4)z
zv>j#o{eCfJ^2DMEFO2W}bKRznufJJ*3NYPyK}|+O4uCYx+jq@crLljVH)YDKWD0aa
zQMOCGRasUt%_z$IC3Nw^QgZSoYn8}Mzy!=O&y4N|Q~?1^(@elrkg^>W^LV|{=bszr
zTC-|d^_*Gnbj>_~DJ7<q1bg;=npC0$pWkbkQZuC_X-cjqOqy?)Ifl~4l~wlqs$$U4
z!Q%8j{bmvJf`iUA{!#1kcyQ@jwh+Qq^U&b)M;d-B%8Yr(&U$UuoVm$x`1)bsFCc71
zLzZ}Lb+16*M@|B+LZ6OD7yRAaI@%K`sLSM?RPuQ8V&i8{^SPrK@er|a`>g~b%T}&7
z0cqJzR9g0R%d)+Iv@FY-zhIGOS(Y`t_Az_dqeCnpgd(C8cKSDro6)unQcAAH3@*1P
zabgi)x))9=(y~=b>A2kP>in)1-IUwc%ISSEacHA+Gl4)b0Q5l674QM=MV&hNk2LHp
zdvDHM&ksMYYo0oJQrSlzyl)srGHd#b*N^?Wd+#0@4J81yAro@&<(A{}l%VS#gdTHO
zJseQoYqmPk@N(zGuJ85!Bc_Vng7JkuJ)UyJvk^<*$=kh69YA>fGTrJczy+YGw6u##
z8b)B@;-x2096$Q|F{698@-8(seNzH*wrt&g#!1Bt0Ij3V7R_g4qUlttxO}o%v^BN5
z9~kJ7?ku4WZk$ik=?f|zJ*GNW4ltCc%oettjD)waYlReddn#RdK@CL!$OUdFxFMjR
zpfJDxxUpkOmo8t~2sB#JQ2cJZ9taBc;1jtdV>w78A<iF7sOs8)sHo}dR1O#`&K+7r
fEPTn?{Dtuko9Z^s$RVN?00000NkvXXu0mjf0U~aI
--- a/browser/themes/gnomestripe/jar.mn
+++ b/browser/themes/gnomestripe/jar.mn
@@ -39,18 +39,18 @@ browser.jar:
   skin/classic/browser/feeds/feedIcon16.png           (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/subscribe.css            (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css         (feeds/subscribe-ui.css)
   skin/classic/browser/newtab/newTab.css              (newtab/newTab.css)
-  skin/classic/browser/newtab/strip.png               (newtab/strip.png)
-  skin/classic/browser/newtab/toolbar.png             (newtab/toolbar.png)
+  skin/classic/browser/newtab/controls.png            (newtab/controls.png)
+  skin/classic/browser/newtab/noise.png               (newtab/noise.png)
   skin/classic/browser/places/bookmarksMenu.png       (places/bookmarksMenu.png)
   skin/classic/browser/places/bookmarksToolbar.png    (places/bookmarksToolbar.png)
   skin/classic/browser/places/calendar.png            (places/calendar.png)
 * skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
   skin/classic/browser/places/livemark-item.png       (places/livemark-item.png)
   skin/classic/browser/places/pageStarred.png         (places/pageStarred.png)
   skin/classic/browser/places/starred48.png           (places/starred48.png)
   skin/classic/browser/places/unstarred48.png         (places/unstarred48.png)
@@ -124,23 +124,26 @@ browser.jar:
   skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
   skin/classic/browser/devtools/splitview.css         (devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css       (devtools/styleeditor.css)
   skin/classic/browser/devtools/debugger.css          (devtools/debugger.css)
   skin/classic/browser/devtools/magnifying-glass.png  (devtools/magnifying-glass.png)
   skin/classic/browser/devtools/itemToggle.png        (devtools/itemToggle.png)
   skin/classic/browser/devtools/itemArrow-rtl.png     (devtools/itemArrow-rtl.png)
   skin/classic/browser/devtools/itemArrow-ltr.png     (devtools/itemArrow-ltr.png)
+  skin/classic/browser/devtools/inspect-button.png    (devtools/inspect-button.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-16-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-24-throbber.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-128.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-mobileIcon.png
   skin/classic/browser/sync-notification-24.png
   skin/classic/browser/syncSetup.css
   skin/classic/browser/syncCommon.css
   skin/classic/browser/syncQuota.css
   skin/classic/browser/syncProgress.css
 #endif
+  skin/classic/browser/webapps-16.png
+  skin/classic/browser/webapps-64.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14f382fbdd18a1209f3dcd63831014b5ad2fc428
GIT binary patch
literal 4180
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
--- a/browser/themes/gnomestripe/newtab/newTab.css
+++ b/browser/themes/gnomestripe/newtab/newTab.css
@@ -1,148 +1,131 @@
-#scrollbox {
-  padding-bottom: 18px;
-  background-color: #fff;
-}
-
-#body {
-  padding-top: 106px;
-  font-family: sans-serif;
-}
-
-.button {
-  padding: 0;
-  border: 0 none;
+:root {
+  -moz-appearance: none;
+  background-color: transparent;
 }
 
-/* TOOLBAR */
-#toolbar {
-  top: 8px;
-  right: 8px;
-  width: 13px;
-  height: 30px;
-  padding: 0;
-  margin: 0;
-}
-
-.toolbar-button {
-  background: transparent url(chrome://browser/skin/newtab/toolbar.png);
-}
-
-#toolbar-button-show {
-  width: 11px;
-  height: 11px;
-  background-position: -10px 0;
-}
-
-#toolbar-button-show:hover {
-  background-position: -10px -12px;
+/* SCROLLBOX */
+#newtab-scrollbox:not([page-disabled]) {
+  background-color: rgb(229,229,229);
+  background-image: url(chrome://browser/skin/newtab/noise.png),
+                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+  background-attachment: fixed;
 }
 
-#toolbar-button-show:active {
-  background-position: -10px -24px;
-}
-
-#toolbar-button-hide {
-  width: 10px;
-  height: 10px;
-}
-
-#toolbar-button-hide:hover {
-  background-position: 0 -12px;
-}
-
-#toolbar-button-hide:active {
-  background-position: 0 -24px;
+/* TOGGLE */
+#newtab-toggle {
+  width: 16px;
+  height: 16px;
+  padding: 0;
+  border: none;
+  background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-#toolbar-button-reset {
-  top: 17px;
-  width: 11px;
-  height: 12px;
-}
-
-#toolbar-button-reset {
-  background-position: -21px 0;
+#newtab-toggle[page-disabled] {
+  background-position: -232px 0;
 }
 
-#toolbar-button-reset:hover {
-  background-position: -21px -12px;
+/* ROWS */
+.newtab-row {
+  margin-bottom: 20px;
 }
 
-#toolbar-button-reset:active {
-  background-position: -21px -24px;
-}
-
-/* GRID */
-#grid {
-  padding: 1px;
-  margin: 0 auto;
+.newtab-row:last-child {
+  margin-bottom: 0;
 }
 
 /* CELLS */
-.cell {
-  outline: 1px dashed #ccc;
-  outline-offset: -1px;
+.newtab-cell {
+  -moz-margin-end: 20px;
+  background-color: rgba(255,255,255,.2);
+  border: 1px solid;
+  border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
+  border-radius: 1px;
+  -moz-transition: border-color 100ms ease-out;
+}
+
+.newtab-cell:empty {
+  border: 1px dashed;
+  border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
+}
+
+.newtab-cell:last-child {
+  -moz-margin-end: 0;
+}
+
+.newtab-cell:hover:not(:empty) {
+  border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
-.site {
-  background-color: #ececec;
-  -moz-transition: 200ms ease-out;
-  -moz-transition-property: top, left, box-shadow, opacity;
+.newtab-site {
+  text-decoration: none;
+  -moz-transition-property: top, left, opacity, box-shadow, background-color;
 }
 
-.site[dragged] {
-  -moz-transition-property: box-shadow;
+.newtab-site:hover,
+.newtab-site[dragged] {
+  box-shadow: 0 0 10px rgba(8,22,37,.3);
+}
+
+.newtab-site[dragged] {
+  -moz-transition-property: box-shadow, background-color;
+  background-color: rgb(242,242,242);
 }
 
-.site[ontop] {
-  box-shadow: 0 1px 4px #000;
-  outline: none;
+/* THUMBNAILS */
+.newtab-thumbnail {
+  background-origin: padding-box;
+  background-clip: padding-box;
+  background-repeat: no-repeat;
+  background-size: cover;
 }
 
-/* SITE TITLE */
-.site-title {
-  height: 2.4em;
-  width: 189px;
-  padding: 0 6px;
-  background-color: rgba(0,0,0,0.5);
-  border: solid transparent;
-  border-width: 6px 0;
-  color: #fff;
-  text-decoration: none;
-  line-height: 1.2em;
-  font-weight: 700;
+/* TITLES */
+.newtab-title {
+  padding: 0 8px;
+  background-color: rgba(248,249,251,.95);
+  color: #1f364c;
+  font-size: 12px;
+  line-height: 24px;
 }
 
-/* SITE STRIP */
-.site-strip {
-  padding: 4px 3px;
-  background-color: rgba(0,0,0,0.5);
+/* CONTROLS */
+.newtab-control {
+  width: 24px;
+  height: 24px;
+  padding: 1px 2px 3px;
+  border: none;
+  background: transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-.strip-button {
-  width: 17px;
-  height: 17px;
-  background: transparent url(chrome://browser/skin/newtab/strip.png);
+.newtab-control-pin:hover {
+  background-position: -24px 0;
 }
 
-.strip-button-pin:hover {
-  background-position: 0 -17px;
+.newtab-control-pin:active {
+  background-position: -48px 0;
 }
 
-.strip-button-pin:active,
-.site[pinned] .strip-button-pin {
-  background-position: 0 -34px;
+.newtab-control-pin[pinned] {
+  background-position: -72px 0;
+}
+
+.newtab-control-pin[pinned]:hover {
+  background-position: -96px 0;
+}
+
+.newtab-control-pin[pinned]:active {
+  background-position: -120px 0;
 }
 
-.strip-button-block {
-  background-position: -17px 0;
+.newtab-control-block {
+  background-position: -144px 0;
 }
 
-.strip-button-block:hover {
-  background-position: -17px -17px;
+.newtab-control-block:hover {
+  background-position: -168px 0;
 }
 
-.strip-button-block:active {
-  background-position: -17px -34px;
+.newtab-control-block:active {
+  background-position: -192px 0;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01d340aaa9095a54d19071516cf9e0ca75b1f72e
GIT binary patch
literal 2118
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
deleted file mode 100644
index 2527df6e72b5c80b91e180af9644ba96a5c148d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 389f689aa2a7611f53977594c048f79c4991affd..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cf59fa3ca1e903968f793d940b2dc651f6ac4e1f
GIT binary patch
literal 366
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@
z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)Zhm0~jSb$HZUBYedAc};Se!n4
zX}y<Apa9#4`Sk&U%?dhM@$w0glU-SErd(CXGt9sEK>CGrL^$uhrbNRVc_tAd0UIN9
z!UW4s$5_Oi6ZN$+n3K3Ke_!#whaavRPJEf0EdRcuJC3_O;y~=&2yT4|w|U8ImtUy=
z4d1f*aCZgQA=76@;%AZs=A`R9kK6c>`S$D51AZ&&6Lg!`AB$_dv9_uANb=0>oN*~1
zmaaOXvQEf}o!#P4+9mk}Em^I{+~yWXCC(KHepTJpbpJ^DT{*c&(|%j@7Ydbj+Ad>$
zEZUf-Q>dzZk0<B7btBW~7ph|3v-ck8x?l6v?}>e%pyf;J<ieGucY!`<@O1TaS?83{
F1OTL^jTis`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..442132d987b04e37e7cd24b45785e7b605be2e32
GIT binary patch
literal 1096
zc$@)91h@N%P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq|
z6AUK%MzGTW00YQLL_t(|+U=T2XcR#dhQGKVLPl|mOI(vk3}`@&UKA9gf(pUq;sV};
zfPxnxdXV695l<e>K@V<-1{4K7=tV(66csnz1w{l`P-Db}nD&rrcotnV-96pa6R97X
z>8|B%UG?g{*8>g?4h{|u4h{~9U?y+`s7!(O2;cxPzZ4bE0p|fvT%EuPpb6*`lkQUB
zDDXw2eHj>5D$4H{f_00_)2_$BE?@@GKY&g@pdM%i?gz~8)_y(UP?m~s3sBt4Be;Kk
zRYuTJ2Ye_n*Tiq9O~uy%T_J?j`~Co{L(p#me#W5h0UOd(d@k@Vf?%?LM~W*<m*q3C
zI7!7P0rx^GuJ@l-d%GAMi^=<m+E%eKLG$cUnO7zF5-NeaF=e>~)Wl)B9C#jL8OpXF
zz_Jv#;R5AE^BF>y^EI%x7^d~WHN#OS8MRn+#G6CNa~o(#lIb|$On}7?XLuC11;}#&
zs7^cTJEZpH=n@FTh5|Q$c6IMy1LeTp5|U?&&DGdXMRgwVTSabJVFvJC?Ejoi<-4^+
zXT0SVc*$@a=4>l3?~hwhevg57szxv=ZwfxPq@ehkh(TG-mhvV6Iufeh)B-PKhQT?T
z%A16^2@H?HyDxAyg5rrAVN6WsCPCUF@ZKIF6%NBYRx(r#JW9w2a_;OrJST>%2t`r;
z6)?4!ZLl`Mw{a>$e4m8!%}ILU<3;Yri-J}&JtcG>v(&QJdBxrL=h8ZZ>wu3jJo0rx
zqfxcVf=P{PlQqNh5qS7xI+Za~M@z`ctp_|5^BP3IOj#$3_9deIN=P0aJtcRm7yw)?
z5S6_W<ELoC2N}ShH%Ii{EfDqH0|whvyuViHT%^SczHpz!n6UxEn+)LhPZRww3{H4e
zK-^*l9<W|(+sD73#e57gygAbrkYgr^F>f({5o%KH*ff9#JOwJW>g@xdOg#_G<10)C
z(8o&p_tjXL72XnKtsB6<_8LOje2y}o0rWZL0rXn~=2$m?+>^h7d1B130v^1O0ra^8
z)Y$2mOXHcX0R3ywn-FJs7z0QepXvEjo^MrUW`IHkied~9MAt++R=S%c$_)3VN;mdD
zH@<1BAuCAU9X1Ux2-qavi0wV-^Yd53M%&S##KD+ZViX@>@&^Yf5sU)vL^MQH14x>8
zfRU6S76RWx8Y1d3=!e*i^a5-RacqT&1he}5o*3E_$OTT)%TWb9i;xcc<DO~RV6VqY
zQ8&;_VsZs^0W0{Av0EuB)7sjs%34{Wf}TG=%jXIl92^`R92^`R?BOqH7L8M0{IIqF
O0000<MNUMnLSTaKyWXDw
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -2354,16 +2354,20 @@ toolbarbutton.chevron > .toolbarbutton-m
 #addons-notification-icon {
   list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
 }
 
 #password-notification-icon {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
 }
 
+#webapps-notification-icon {
+  list-style-image: url(chrome://browser/skin/webapps-16.png);
+}
+
 .popup-notification-icon {
   width: 64px;
   height: 64px;
   -moz-margin-end: 10px;
 }
 
 .popup-notification-icon[popupid="geolocation"] {
   list-style-image: url(chrome://browser/skin/Geolocation-64.png);
@@ -2420,16 +2424,20 @@ toolbarbutton.chevron > .toolbarbutton-m
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
 .popup-notification-icon[popupid="password-save"],
 .popup-notification-icon[popupid="password-change"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
 }
 
+.popup-notification-icon[popupid="webapps-install"] {
+  list-style-image: url(chrome://browser/skin/webapps-64.png);
+}
+
 /* Popup Buttons */
 #identity-popup-more-info-button {
   @hudButton@
   margin: 10px 0 0;
   min-height: 0px;
 }
 
 #identity-popup-more-info-button:focus {
@@ -2716,16 +2724,25 @@ panel[dimmed="true"] {
 
 #highlighter-veil-container[locked] > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
 
 /* Highlighter toolbar */
 
+#inspector-inspect-toolbutton {
+  list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
+  -moz-image-region: rect(0px 16px 16px 0px);
+}
+
+#inspector-inspect-toolbutton[checked] {
+  -moz-image-region: rect(0px 32px 16px 16px);
+}
+
 #inspector-toolbar {
   border-top: 1px solid hsla(210, 8%, 5%, .65);
   padding-top: 4px;
   padding-bottom: 4px;
 }
 
 #inspector-toolbar:-moz-locale-dir(ltr) {
   padding-left: 2px;
--- a/browser/themes/pinstripe/devtools/common.css
+++ b/browser/themes/pinstripe/devtools/common.css
@@ -57,16 +57,20 @@
   background: -moz-linear-gradient(hsla(212,7%,57%,.35), hsla(212,7%,57%,.1)) padding-box;
   box-shadow: 0 1px 0 hsla(210,16%,76%,.15) inset, 0 0 0 1px hsla(210,16%,76%,.15) inset, 0 1px 0 hsla(210,16%,76%,.15);
 }
 
 .devtools-toolbarbutton > .toolbarbutton-text {
   margin: 1px 6px;
 }
 
+.devtools-toolbarbutton:not([label]) {
+  min-width: 32px;
+}
+
 .devtools-toolbarbutton:not([checked]):hover:active {
   border-color: hsla(210,8%,5%,.6);
   background: -moz-linear-gradient(hsla(220,6%,10%,.3), hsla(212,7%,57%,.15) 65%, hsla(212,7%,57%,.3));
   box-shadow: 0 0 3px hsla(210,8%,5%,.25) inset, 0 1px 3px hsla(210,8%,5%,.25) inset, 0 1px 0 hsla(210,16%,76%,.15);
 }
 
 .devtools-toolbarbutton[checked] {
   color: hsl(208,100%,60%) !important;
--- a/browser/themes/pinstripe/devtools/csshtmltree.css
+++ b/browser/themes/pinstripe/devtools/csshtmltree.css
@@ -40,21 +40,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 :root {
   -moz-appearance: none;
   background: -moz-Field;
   color: -moz-FieldText;
 }
 
-#root {
-  display: -moz-box;
-}
-
-
 .property-header {
   padding: 5px 0;
   white-space: nowrap;
   vertical-align: text-top;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
@@ -68,17 +63,16 @@
 .helplink:visited {
   text-decoration: none;
 }
 .link:hover {
   text-decoration: underline;
 }
 
 .helplink {
-  display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
   -moz-margin-end: 2px;
   cursor: pointer;
 }
@@ -94,54 +88,44 @@
 
 .expander {
   -moz-appearance: treetwisty;
   width: 12px;
   height: 12px;
   padding-top: 12px;
   -moz-margin-start: 5px;
   -moz-margin-end: 5px;
-  display: inline-block;
   vertical-align: middle;
 }
 
 .expander[open] {
   -moz-appearance: treetwistyopen;
 }
 
-.expandable {
-  cursor: pointer;
-}
-
 .match {
   visibility: hidden;
 }
 
-.expandable > .property-header > .match {
+.expandable {
+  cursor: pointer;
   visibility: visible;
 }
 
 .property-name {
   font-size: 12px;
   color: -moz-FieldText;
-  display: inline-block;
 }
 .property-value {
   padding: 0;
   font-size: 10px;
   color: grey;
   vertical-align: text-top;
   width: 100%;
 }
 
-.property-view-hidden,
-.property-content-hidden {
-  display: none;
-}
-
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
   cursor: pointer;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
@@ -157,20 +141,16 @@
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 
 #propertyContainer {
-  display: -moz-box;
-  -moz-box-orient: vertical;
-  -moz-box-flex: 1;
-  overflow-y: auto;
   border-collapse: collapse;
 }
 
 .darkrow {
   background-color: rgba(0,0,0,.022);
 }
 
 #noResults {
@@ -217,46 +197,45 @@
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
 .ruleview-warning {
   background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  display: inline-block;
   -moz-margin-start: 5px;
   vertical-align: middle;
   width: 13px;
   height: 12px;
 }
 
-.ruleview-warning[hidden] {
-  display: none;
+.ruleview-ruleopen {
+  -moz-padding-end: 5px;
 }
 
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
+.ruleview-ruleclose {
+  width: -moz-min-content;
+  padding-right: 20px;
 }
 
 .ruleview-propertylist {
   list-style: none;
   padding: 0;
   margin: 0;
 }
 
 .ruleview-enableproperty {
   height: 10px;
   width: 10px;
   -moz-margin-start: 2px;
   -moz-margin-end: 0;
 }
 
 .ruleview-expander {
-  display: inline-block;
   width: 8px;
   height: 8px;
   background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
   cursor: pointer;
   -moz-margin-start: 2px;
   -moz-margin-end: 5px;
 }
 
@@ -265,17 +244,16 @@
 }
 
 .ruleview-newproperty {
   /* (enable checkbox width: 12px) + (expander width: 15px) */
   -moz-margin-start: 27px;
 }
 
 .ruleview-propertyname {
-  display: inline-block;
   padding: 1px 0;
   cursor: text;
   color: #0060C0;
   text-decoration: inherit;
 }
 
 .ruleview-propertyvalue {
   cursor: text;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ebfd9586d201416665b64e4fe57af05c1a967edb
GIT binary patch
literal 1321
zc$@(#1=jkBP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyS_
z05usk)smk800gN?L_t(Y$K{l1Y*a-6$A9zQUOjeu&=$I-(1MhZQV@|K5n=%`MvM?t
zA|`@dO7J!qFc>BJ$;23=h#Yc<s2CDN3J3&>fIzuKkaEc(bPMg$?RMGSw{PBi;|CV9
z7z})OKEBCs<~RTOzk&bz5CHDHpa&=b@&Wff7zwlk5g84c0IXFykPT!3`aO6XNCFAQ
z3)_|cSh#q>m(xc-^<>rkSl4aZa^{tpZ!Q6@0?>LXcW71c^IWfc%Kh*+QgYdzGog2Z
z=q-WbQKLqdTecIsp9MyZ8d(k$-x3g!=76GX;?;zGU$N)tVxovN&r=x!Ihv-Y0A8Lp
zBeG*>ePcT6%;6p}ytdDZZx<G5nr;I*w`Za)SuxXbDd5_lhd&MPUSE$itUGC+t7zER
z+RoJjXUA+@L|d`|Tp3-k0Cw!GZ%~Q@0yG4Ez*35MdM*Zx%<Rw2Ta`juH}`8jao{KI
z*tWB(xI$3T&qFHdh%@_5jF@Q6>)hU{cmLV9m`njOP8<QkLQuZ9e%q7{b(@=(EM2~@
ztu1mzK}#Z$l-b!?sI>5HSf=s3l6Km!U3X@!EgW1?vN3L{_2=WPN=Q2_4sK{OP16uU
z_(&xk0PSA_Qh;N3gcMNNsi>GYX1>~E_l~VEe*EFwm&!^@ONS1B{OsyA-(5|M-XS2R
z1h?0*J3>l?FZ;uZR4<{dd3|!NhHAh1#NTT`$(8-vC&j~8*AQ)q|5pNDcV18jyk4)z
zv>j#o{eCfJ^2DMEFO2W}bKRznufJJ*3NYPyK}|+O4uCYx+jq@crLljVH)YDKWD0aa
zQMOCGRasUt%_z$IC3Nw^QgZSoYn8}Mzy!=O&y4N|Q~?1^(@elrkg^>W^LV|{=bszr
zTC-|d^_*Gnbj>_~DJ7<q1bg;=npC0$pWkbkQZuC_X-cjqOqy?)Ifl~4l~wlqs$$U4
z!Q%8j{bmvJf`iUA{!#1kcyQ@jwh+Qq^U&b)M;d-B%8Yr(&U$UuoVm$x`1)bsFCc71
zLzZ}Lb+16*M@|B+LZ6OD7yRAaI@%K`sLSM?RPuQ8V&i8{^SPrK@er|a`>g~b%T}&7
z0cqJzR9g0R%d)+Iv@FY-zhIGOS(Y`t_Az_dqeCnpgd(C8cKSDro6)unQcAAH3@*1P
zabgi)x))9=(y~=b>A2kP>in)1-IUwc%ISSEacHA+Gl4)b0Q5l674QM=MV&hNk2LHp
zdvDHM&ksMYYo0oJQrSlzyl)srGHd#b*N^?Wd+#0@4J81yAro@&<(A{}l%VS#gdTHO
zJseQoYqmPk@N(zGuJ85!Bc_Vng7JkuJ)UyJvk^<*$=kh69YA>fGTrJczy+YGw6u##
z8b)B@;-x2096$Q|F{698@-8(seNzH*wrt&g#!1Bt0Ij3V7R_g4qUlttxO}o%v^BN5
z9~kJ7?ku4WZk$ik=?f|zJ*GNW4ltCc%oettjD)waYlReddn#RdK@CL!$OUdFxFMjR
zpfJDxxUpkOmo8t~2sB#JQ2cJZ9taBc;1jtdV>w78A<iF7sOs8)sHo}dR1O#`&K+7r
fEPTn?{Dtuko9Z^s$RVN?00000NkvXXu0mjf0U~aI
--- a/browser/themes/pinstripe/jar.mn
+++ b/browser/themes/pinstripe/jar.mn
@@ -49,18 +49,18 @@ browser.jar:
   skin/classic/browser/feeds/subscribe-ui.css               (feeds/subscribe-ui.css)
   skin/classic/browser/feeds/feedIcon.png                   (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                 (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/newtab/newTab.css                    (newtab/newTab.css)
-  skin/classic/browser/newtab/strip.png                     (newtab/strip.png)
-  skin/classic/browser/newtab/toolbar.png                   (newtab/toolbar.png)
+  skin/classic/browser/newtab/controls.png                  (newtab/controls.png)
+  skin/classic/browser/newtab/noise.png                     (newtab/noise.png)
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/places/allBookmarks.png              (places/allBookmarks.png)
 * skin/classic/browser/places/places.css                    (places/places.css)
 * skin/classic/browser/places/organizer.css                 (places/organizer.css)
   skin/classic/browser/places/query.png                     (places/query.png)
   skin/classic/browser/places/bookmarksMenu.png             (places/bookmarksMenu.png)
@@ -165,16 +165,17 @@ browser.jar:
   skin/classic/browser/devtools/splitview.css               (devtools/splitview.css)
   skin/classic/browser/devtools/styleeditor.css             (devtools/styleeditor.css)
   skin/classic/browser/devtools/debugger.css                (devtools/debugger.css)
   skin/classic/browser/devtools/magnifying-glass.png        (devtools/magnifying-glass.png)
   skin/classic/browser/devtools/itemToggle.png              (devtools/itemToggle.png)
   skin/classic/browser/devtools/itemArrow-rtl.png           (devtools/itemArrow-rtl.png)
   skin/classic/browser/devtools/itemArrow-ltr.png           (devtools/itemArrow-ltr.png)
   skin/classic/browser/devtools/background-noise-toolbar.png (devtools/background-noise-toolbar.png)
+  skin/classic/browser/devtools/inspect-button.png          (devtools/inspect-button.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-throbber.png
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-128.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-mobileIcon.png
@@ -185,15 +186,17 @@ browser.jar:
   skin/classic/browser/syncProgress.css
 #endif
   skin/classic/browser/lion/keyhole-circle.png              (keyhole-circle-lion.png)
   skin/classic/browser/lion/Toolbar.png                     (Toolbar-lion.png)
   skin/classic/browser/lion/toolbarbutton-dropmarker.png    (toolbarbutton-dropmarker-lion.png)
   skin/classic/browser/lion/tabbrowser/alltabs-box-bkgnd-icon.png      (tabbrowser/alltabs-box-bkgnd-icon-lion.png)
   skin/classic/browser/lion/tabview/tabview.png                        (tabview/tabview-lion.png)
   skin/classic/browser/lion/places/toolbar.png              (places/toolbar-lion.png)
+  skin/classic/browser/webapps-16.png
+  skin/classic/browser/webapps-64.png
 
 % override chrome://browser/skin/keyhole-circle.png                        chrome://browser/skin/lion/keyhole-circle.png                           os=Darwin osversion>=10.7
 % override chrome://browser/skin/Toolbar.png                               chrome://browser/skin/lion/Toolbar.png                                  os=Darwin osversion>=10.7
 % override chrome://browser/skin/toolbarbutton-dropmarker.png              chrome://browser/skin/lion/toolbarbutton-dropmarker.png                 os=Darwin osversion>=10.7
 % override chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png     chrome://browser/skin/lion/tabbrowser/alltabs-box-bkgnd-icon.png        os=Darwin osversion>=10.7
 % override chrome://browser/skin/tabview/tabview.png                       chrome://browser/skin/lion/tabview/tabview.png                          os=Darwin osversion>=10.7
 % override chrome://browser/skin/places/toolbar.png                        chrome://browser/skin/lion/places/toolbar.png                           os=Darwin osversion>=10.7
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14f382fbdd18a1209f3dcd63831014b5ad2fc428
GIT binary patch
literal 4180
zc$@)L5UcNrP)<h;3K|Lk000e1NJLTq008&^000;W1^@s6*Of4d00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyW3
z3po`Ymn>!g01wnjL_t(|+U=ZqR1{af$G^37(<}-RL{S73g}8w$#L2jfU~q|vxCPB(
zo=J>boWv||#JIeXmzNmFGh>XH%zK$Pal_}9NnD7EQAq^RxS$CHP(X}gBtnY>Z0g=S
ze{^-zOLbRuE64LD)H(Nb)wged&hOs({qDW>tFGd1-@c8&j$JvJHx2+Ve_D!`joB0`
zf5Le4M+Tsc|1ZpM-@ZLKpLVUnXLsuvfdBXW2f1-_<17sm0f@hOB+<9&?p?uTG6?{{
z7~_<G%rOAa>-EIo<3mp5pKJsm$;H~xHhvrb*UD#i>)8kYyDJC4X!&PHUU_~>l2#1>
zMm?VPn7@BOAOJKp+%X>An{`mDCdx1#fd24-F9ycP_1{1l<r$@%tA;5xl;e5Eb38p?
zcwv6>xQS;0m;jJAejC4yZw*@8eXSZoLqmPKckfXR0OjSEgFMkhdGrzi=;Px0W$r!r
zRapMF=R>?%4m>hAzGlK>qcQ=EkVh~oe`VztoVytI!{sYp@nd^L)C?Wa&n^FxP20i_
z9Qw*D{<tx}tNFKQ)7<jkKYcSStK^PX{Ir;Wnm2~HxBugdbzxsrG<wCK80A~@Qk;AK
zd&kPcwiZ@<#h)41x#q2r?)k0lKfYgl9_E*q=N12#VZ&<TCQfwAuiLsMtnu(+ulT;n
z$u)5^XFBp3W7K&~uTcX4UteES$Iy;V08m|h-Q<bJ+bm6di6jXpzby=Al);;F^4r2-
zB1r-OUzzE|FS%3|%qZYZDY;ao%0HNMEEtTzn{qJcm@0oqX?-wb6yB5_rS+=(eH9H}
z^Y>LWsPea8s19a~!JD%ELbWQtwf)DCpC3#qg*U~JpRdYq$jR}V-;k4|#0R4++oqk_
zo@f9N9T{$@tf=&_tf=&ljtn<=qFHC~sL03wN-0k$QC*gdO&Wphoa0V9p@gH9@==kI
z0Tq>%jW$UND__#UPZ-z_1!pfh>6Ag8Pb5|TjA@gxZO3jWT_TbyzgbeZfBujz*l_xq
zlip0V*iTjY&&7q})54#e?Fa6Q{R@Z3V0~_hSN3c1A6J_e{~;!m*L)ClK5cIHo=>SF
z|MxFUALm$As|Ene-dtD>AXGlAUjEiAnl(#+3lfp^lro-D3M~OnDOC(|N*ON^Ne@7<
z=|GS82?P6qQmP!}DtyM&6PHg<pA5#BVvwuaPlzgi!O$+Clw!lFA6un=o{I|wr3{}I
z-e?v6!Vxi`jA8xpA6kX)K1SU0B@O+5FZ|Z9f9=QH?2>1T=gdgbssTXqlTQZ(1_f~d
zV63YP@I<o)I3+}6jB!ju0~uu)moyTLGGyl*bGVLR93@0_>_7`&OMo!OkT|G67^OIQ
z=7L9jM%4qHGK!hgQ^6?3wjFys<P!~ih6M>-!5GDcf~y|!LACS`Fe|<j7^B#9zPc6o
z46lrc0izTj9xwK=f9@?n)cE%r;A(u*3ieY*oswr-H2`QI6yz5f8CeSe6+n<DnrLH~
zz!>AyMzFC-BVp-;6zfcW%&viqF+ri>0%MFL%soGGP#mZnqzQxKKp4ZxGliP@YBPA+
z)JY(+lcY_X1WGBgc7CRrPl@D~KQAEyl5GFnq2VBeBD3I%2YmMq{7ifpB)R{eiR%PH
zC^nzJuAQ$E;PXfHw%R{`L@WrU*l@ha1HS$FeQVLnh>8eD#g(gAz3wBInpVCf+4q0D
zWy>J+=mB#1GU`{Ya;bT1fA2MG;NPnk8cIu1^u`-5HFtcaK~Jj&0KNu;DI_GM2>@=~
zxMA`{6K(DT%1aFDHn=T8ZP}E9+>vR=C)90lCl2gy$4?yCACyqLAa}=SZU&I2rcOfI
z)Jb+Wq)nX!$|$zm1i4$jn*g7i7>T(F-9T(s5pxr|fl`8vCo8q_scZf-1G?bZ0i8i@
z2C-)cbOvJto6lXlXZz=k>|+h;mVl21r39JBzSnks9sK8ytN)Dj*B7FDWCUJc_!0o1
zTX+|gl~>@MKdpye@8k0BlhS^(Lx5jSUyATme}r#zGy;|`HBZM;QD`hJ#nolY5u_76
z;ybPozFD*g32WCPFeV1E@4W{A@axe7bwx!eSiBhR1woZhDa{5jRzA%3L<4|cQQZtz
zu3YiA?0ce#&est34IGy|3Mok=ZSoW?-|zb}2Ya&*K@fEiMNw-a#qN06kO6pPP#lyT
zBsc#Qj-4ogUhe~)Ua##M$YBPbF*Oy_r#uOz6PUGgH@0lw1)dkc^Sm~`Lx9X1)*UY=
zMz!#5?EfgY7@5b50KEaw88q_k`{&s~;dpvLR~vpy`!*Mp;qUon;PnP@dS9>j3r6+D
z+>w23`lrSIjX7tr;m{c{oev=TXuJls=Zm6<|9t;1czkR!9v?df0Pxw~1K68=7&^TV
zDD`Z~?HJ(x98jK~jt;4l5jr{5oL$P=j$3<nBS;jT>Z|)Fb>MTzfAv*#pD_bH)6xI{
zC7U*(eA_m(69i~k(*OH{S>wFb0AS^kSM8E#|B?QhW=$c$?G65X|3R2cCX7!>veWl}
znS<=ZN1>BPV6DjsM+ZBan}@rNjTk;`sGXjhcM5r@&%xK%Pw{uI^8@yFY|h#NNovMZ
zQ&a8q?K}4%Yv*SWc){)R$jN>Ohxzcx1(2o&%o*O>PX9Q!2pdma27ChK$kFC#jx+4v
zzbOW3Y{1irz3lWYCrh#UOci+FcB(V8JO27F3qbESVovfvd;1Tc#fGC70KK2=`I5!}
zckV|))IlN?rsihrAR>r5c$3gl3Rr&td~-9H$ppyz{x0eYs)=@IKl1~?nM|NEpEH@@
z=c2CC_RhLb?2>2ci)JTj)c|1Bgr@=m0|U*;GovxU6HQbLK#t?E|H~W%wQq+<5(e7^
zxFCv}1J61`NcJa{<3;4=pMk%>KjQm6Y%_bGfljY?s;?zM<Y@o49edEB!$TN7a=2CB
zwqp-?o`;sKySx4YufvAiQiS>&@OXU7Ouiwv)I4i@*gsB}FoGVRo~lF#e;<tL6K<71
zJyi)#ZvZ2n^^a3f@j9$OQizW2{V;KGOiSP&DFj44;9(Fd`NN{QFCZek3(CsM0RUr0
z4M%LxXsp}#KldfTJEy0^r+atQ7n>7;4^0>kzdpTD{mwi0CBXY<WFR0q8b5#c9RMIA
zH5DD=;&9>Zw>A2tbMj291^|J9fqva0y43;zu9%Z&S~XtD0US$@9#QDqI~Mt;&VUdC
zLI^mXSFEeW0US$2co+2Q9*M$>#h`?O5(+^O6zgi4!5vHQm|hq>ARb4Lf74>Wi@I87
zK*ti_ts@@o*%|u_D?lg(p%jc473-?oPn=4huE7`@6^fkiuYwQ;LKq<G6zh6re`F^-
z8XJy%-~IrJ5J-f8alBXdJNm<d7iXbM=TKZKufUphnOL(f6PL;>(4})I7Q8siWB+NE
zB)by&=9|!khoiov1jQ>?qIl&>)R&Y%7aoq#H{W!suQ~xyYFGNMSOLF?2;3?z#)&0M
zaAL_4+$t`HUql4@u2|tz-_>0w+v14^00x7>6cQZL6cQZLWH1;^o@lB|^zKm+cz)(I
ze6lGE#U*99@zYI=du%kky<g~f4c;}Z6DFpN!mhmsP;uoNYHrnH#BYW=)zdtKILyco
z$MnSF-_OU|4>EE7!bM!Wb{$hEKj~CY`wV68B=KDz!n;qzW9hCF$gikDWsMQDNAv|H
z(tY9g=^Th9$+1|y|1{2At;LVEw~>|@dk=j3ejO0e5v!;F7E8D0Ag}BiDsR@|g`~kA
zugqNe&zcW1!6*gC^U&$cd6c#5KXTHvuK?}aUAS^3B*q|e90KKp*Y^sVxBZiwo^E9Y
z$a$JP1x;mD>6ARvssTVubd;g0s><K8?}=s!aHe#EEW!P^%~>cZD+ezKIB@8Q*3p(J
z?b|LvyM}eb6Dgyy>+@_>UAqBM)Zy#=(_oak&9=Ma+b+3dV|wDXMf33I^_eKVSOkva
z@qfGj0m7)3rMV0HC7a;xfOnr5fMq+sMqX7NAn5SX@gfjHv;?5C{Wb$z@6LhvLvnAd
z-gg@3s_y_gA8aYO3`&`n*;<t!9}$Z8o*Is~w;n=X`AxI^IcGsB^_uVK7lI&K*Tt6a
zlr*h;$645~<-}XRQ_{5Z9cN*K`8v<;J0;B>f7#+WPRTQ^8UU<Xy4WsxmhtxMnl;hp
zT9t4d$1Ka#prAlJKVusHwkZpxm&(o8tCWK0cw`?sVm?Vq_XaqQaU4e!bi#2QBeLVS
zZx?_kQhtYBpYKQ2kJaD>0fb24c^=2}PC=*BdBwNfCJPSkfY%nz#b4HM#D(vQz;T>8
zs5xNg?tg%DG4iVN<q^J9dtdz5lY_8)=hw)ussnftAOwsT@z>lUFc(>8t^AMx1OAZQ
z2W$2f;N0~)fMDiB&|zyq88{bNdCm3*`s3Z{!?AqJL342Pg4upfz{iKrfQfqV`1kln
z5jDOfNv+DK_xMK|SNwZqp7d4|<&lP5yI$R7e(Vj55X$|0>lWT$_aSQQZiDA}P@DV9
zoWpU;Xw5T@<Jh(9)lD!zDrXtRtbFsOFXd|MjQH<OS-8{C2wo8EMsmU7*qRUG)%iTn
zGeQVgQ}Z*Hu3UwmZvNa7+$}w!ID-p<pvo6OnM4^^U3(iZ{q+E<?lhZ&+h)dN4#(Ec
z<~a>~#w5zPo5nkMW6M{#(a6lfZQCD$UNK*wiO(@6QOZ@<8u8-#ov6CqWDag-W4~a3
z+`?Dye~bTk<H%b4hX4%3%m2G;IKRw12ztfmT=O5;##;g$fQjch`e@=1Bcl{x47IgJ
zm&qul@@V1^BhPabEziO-M}B;t7%Try!!PFG)5wqS6Qjx>J7%=e@^skEpK8qiHqiJq
z+1N3oRrzW0U5%7dPzF@iH-m!L{IpS8d{<TegoisCDWjkOt~WAJc`(&dCOq6x-TtA`
zMoO94eq)ntKhspwhDNLME&k(8(c(XTDJe!vBGc32my)8&4;eq+NEw4SC1m_~CH@25
zEHk(SplSP#-OHy>NzF)|IPMl9M35ie;MA5RJkL=<5Qt9HN!xeqUJjs1W?C9(<xiWE
znlb9P39ZI|dG@S~+0V^vHU9D`sToU>Vq1;BXi93vyu^rB<FA;Knvp(!P^<A<-GAo1
zoDnp8cI)xyFUaUNXU_fRKd_DCeA@8<^m6VX06<{JkdPpWNPdhlAI6xd(m;vhxVxet
z{&KUXrVfA+z#X}fCb?Q0zm5N^<g>f=^g#zWC*S|q%f(l2tX`hsRsS0xk5(qRQH}Dx
z?JH~A_-*`OCI3Occv11Ci#83jG>%ib6+mnns`^s9Hhvrb*TR3`0p9l7<Tn1j@Y`OS
etj>Rs+dl!+gL0AI@-6HD0000<MNUMnLSTYF%@Pp+
--- a/browser/themes/pinstripe/newtab/newTab.css
+++ b/browser/themes/pinstripe/newtab/newTab.css
@@ -1,147 +1,131 @@
-#scrollbox {
-  padding-bottom: 18px;
-  background-color: #fff;
-}
-
-#body {
-  padding-top: 106px;
-  font-family: sans-serif;
-}
-
-.button {
-  padding: 0;
-  border: 0 none;
+:root {
+  -moz-appearance: none;
+  background-color: transparent;
 }
 
-/* TOOLBAR */
-#toolbar {
-  top: 8px;
-  right: 8px;
-  width: 13px;
-  height: 30px;
-  padding: 0;
-  margin: 0;
-}
-
-.toolbar-button {
-  background: transparent url(chrome://browser/skin/newtab/toolbar.png);
-}
-
-#toolbar-button-show {
-  width: 11px;
-  height: 11px;
-  background-position: -10px 0;
-}
-
-#toolbar-button-show:hover {
-  background-position: -10px -12px;
+/* SCROLLBOX */
+#newtab-scrollbox:not([page-disabled]) {
+  background-color: rgb(229,229,229);
+  background-image: url(chrome://browser/skin/newtab/noise.png),
+                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+  background-attachment: fixed;
 }
 
-#toolbar-button-show:active {
-  background-position: -10px -24px;
-}
-
-#toolbar-button-hide {
-  width: 10px;
-  height: 10px;
-}
-
-#toolbar-button-hide:hover {
-  background-position: 0 -12px;
-}
-
-#toolbar-button-hide:active {
-  background-position: 0 -24px;
+/* TOGGLE */
+#newtab-toggle {
+  width: 16px;
+  height: 16px;
+  padding: 0;
+  border: none;
+  background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-#toolbar-button-reset {
-  top: 17px;
-  width: 11px;
-  height: 12px;
-}
-
-#toolbar-button-reset {
-  background-position: -21px 0;
+#newtab-toggle[page-disabled] {
+  background-position: -232px 0;
 }
 
-#toolbar-button-reset:hover {
-  background-position: -21px -12px;
+/* ROWS */
+.newtab-row {
+  margin-bottom: 20px;
 }
 
-#toolbar-button-reset:active {
-  background-position: -21px -24px;
-}
-
-/* GRID */
-#grid {
-  padding: 1px;
-  margin: 0 auto;
+.newtab-row:last-child {
+  margin-bottom: 0;
 }
 
 /* CELLS */
-.cell {
-  outline: 1px dashed #ccc;
-  outline-offset: -1px;
+.newtab-cell {
+  -moz-margin-end: 20px;
+  background-color: rgba(255,255,255,.2);
+  border: 1px solid;
+  border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
+  border-radius: 1px;
+  -moz-transition: border-color 100ms ease-out;
+}
+
+.newtab-cell:empty {
+  border: 1px dashed;
+  border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
+}
+
+.newtab-cell:last-child {
+  -moz-margin-end: 0;
+}
+
+.newtab-cell:hover:not(:empty) {
+  border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
-.site {
-  background-color: #ececec;
-  -moz-transition: 200ms ease-out;
-  -moz-transition-property: top, left, box-shadow, opacity;
+.newtab-site {
+  text-decoration: none;
+  -moz-transition-property: top, left, opacity, box-shadow, background-color;
 }
 
-.site[dragged] {
-  -moz-transition-property: box-shadow;
+.newtab-site:hover,
+.newtab-site[dragged] {
+  box-shadow: 0 0 10px rgba(8,22,37,.3);
+}
+
+.newtab-site[dragged] {
+  -moz-transition-property: box-shadow, background-color;
+  background-color: rgb(242,242,242);
 }
 
-.site[ontop] {
-  box-shadow: 0 1px 4px #000;
+/* THUMBNAILS */
+.newtab-thumbnail {
+  background-origin: padding-box;
+  background-clip: padding-box;
+  background-repeat: no-repeat;
+  background-size: cover;
 }
 
-/* SITE TITLE */
-.site-title {
-  height: 2.4em;
-  width: 189px;
-  padding: 0 6px;
-  background-color: rgba(0,0,0,0.5);
-  border: solid transparent;
-  border-width: 6px 0;
-  color: #fff;
-  text-decoration: none;
-  line-height: 1.2em;
-  font-weight: 700;
+/* TITLES */
+.newtab-title {
+  padding: 0 8px;
+  background-color: rgba(248,249,251,.95);
+  color: #1f364c;
+  font-size: 12px;
+  line-height: 24px;
 }
 
-/* SITE STRIP */
-.site-strip {
-  padding: 4px 3px;
-  background-color: rgba(0,0,0,0.5);
+/* CONTROLS */
+.newtab-control {
+  width: 24px;
+  height: 24px;
+  padding: 1px 2px 3px;
+  border: none;
+  background: transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-.strip-button {
-  width: 17px;
-  height: 17px;
-  background: transparent url(chrome://browser/skin/newtab/strip.png);
+.newtab-control-pin:hover {
+  background-position: -24px 0;
 }
 
-.strip-button-pin:hover {
-  background-position: 0 -17px;
+.newtab-control-pin:active {
+  background-position: -48px 0;
 }
 
-.strip-button-pin:active,
-.site[pinned] .strip-button-pin {
-  background-position: 0 -34px;
+.newtab-control-pin[pinned] {
+  background-position: -72px 0;
+}
+
+.newtab-control-pin[pinned]:hover {
+  background-position: -96px 0;
+}
+
+.newtab-control-pin[pinned]:active {
+  background-position: -120px 0;
 }
 
-.strip-button-block {
-  background-position: -17px 0;
+.newtab-control-block {
+  background-position: -144px 0;
 }
 
-.strip-button-block:hover {
-  background-position: -17px -17px;
+.newtab-control-block:hover {
+  background-position: -168px 0;
 }
 
-.strip-button-block:active {
-  background-position: -17px -34px;
+.newtab-control-block:active {
+  background-position: -192px 0;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01d340aaa9095a54d19071516cf9e0ca75b1f72e
GIT binary patch
literal 2118
zc$@)72)Xx(P)<h;3K|Lk000e1NJLTq001xm001xu1ONa4{R=S+00002VoOIv0RM-N
z%)bBt010qNS#tmY3ljhU3ljkVnw%H_000Sga6xAP001xm001xm&hCs?000MbNkl<Z
zSi@D=+jZMW5(eOpwjTOXjzG-}lmVL&j2!_R5zK4^AR@3G0e}d09Ra`yb{qk~46F#S
z4=8cG(mA|<V53p>--?HvdIhUa_M+;X6tf#nR@I;yaMwDUa5OpE3_1&rij$kwgjpBQ
zt3#iPRi|LEXk0XkRWCbQbWSK%v(W`v*6DR-WWA&6B3sSwR;^XR%$E8zr7dl#rkb`?
z(w44iNhS4ZOV>EEr7d0Kvn_2Yr<%4jrIM~`OH;~8%ITV>w56I#x~3BAeymTUXV1R-
z!%xrdKFhMvCpTADS?Ag8)!nmdHu|bDdh>@LI)AyTep!v46?eb<fghfI{Q30kt}3!$
zp8at5>Whn?zRF&$Uh!<yTOA$z!hbxw`r@lMRq?}DZ@wD+<+Ja;`GTvbN#le;MR9YI
zO**R?18y#|-r1xE6u6;{-re+Q9c9g<D+4U4PfOa;l9sfknyzU|HBD(tqVhGK_s1#K
zw4^2V>6)%-OV^a6H#IG(PdQCV+LE-SoJ#tTRoU55hu%pEm=+whIGYVRtX5g4(P`uT
zqG+6~R@GwEn{65ehb^(n8eA06Xk|2dM@4pWbHW-RJ*s+xn+w6CStj0fPDU5m2SKtO
z(fi-NOM0DNA1o*uqoQC#qdFPgbUK~t7H6H!kFD4%x%Z)@Eluf~N?MY%1pfOpC25M!
z-n+F0=5y*(iPu}Kl2eISH9ZX$XMM1DRx}oaMW;7o)Y>#wcPBJavRTz*&>BM=#NDo7
z!l9&Mun-E9&2FJSy#|ZH9kU5%Yp73Fv<^1MkQllEuE+7imUeXX&a&0ytk+?V%MKbv
zj@@QCwlanq^*ULraj_a@v&D>?)(2XvjEj?OHtC$4RD&~aHuN}Z6tm72`&>;%*$Y~Y
zEL&xR&dn7EX)~zi*xUX$Ta7M?#-xi)9Arh0hPdc#Rh;FhIcJmegUwHyH4wl103BXr
zlR3!J>Z~rR)yeGqUSFFo=(RfPyaW$Q^sHfr;_{m;>~gTfFsDAixeJCkH>Z+H+ESl#
zx~3B6_m8#uw4^DOw56v5u3BeYtU8ydBxhN6)9N0~-s#xuqI7pm0ZR`MXS2J>(P2wx
z1()BvXg_^48Bjx)_QwXjSusbO$wpc0?4pKH>|iK9G_s3X=N>zwy31y>YQ$)Wx}L4k
z)<LlvQPFFW-JEq^6kTld<A0yNc=M-cZ(e+t@x?FMCqMAX%`bPKK~)@l)_K$U=DTmP
zwMO>CzwzvD^tT_r8mSLmDZi=D?#tKIrzKreP5q<kesk(~HCjTkrZmMjrda2i>=v<w
z?eCpm0yFQ6msHa=NlU5^d)iH@56dr)t-XI|-{6*>ZWf(RF~~}=BFE!way01-u7Rx*
zLR@sgkj2qaZzNPJ8v-teEj4;gIPD&*{_(C=(LNx!Gk*VkGAKHI$lvZEr;w1@&Bcn3
z_op>1`(NJl2H*W5d(->n&7XexTh{4(b9PYi(@oX*kL;T_XWtyX;$JGV;)|>7u%#W-
zqdpQuAAaj`AK5t^SbUk)8O6ou6s}Q%u49m~vF^!En$i-UwKqCPn@hCnT`p?c{tp!I
z_^a{UN2^Pcwp7!S4t?6G@^0}<WQoRRFe+NdsO+wv;;hb#(Qa3V@afLQIV@^7s1Mbs
zasJKn8?72SqiD@~vr}N`Jx_Brnw%7?YBD>9=&wdET8*<qN$q3d5<WJBFIBBsaki>f
zS!)mH@5b20k=sMBc6`+b?(CAgrSg#5fBs7lZ)fQi+<xc!_TcmqBL5Hnuc;>Knzr=u
z_VmpU#ZP~E)wzXYzH0obxXZFHK3OsPr19AeqsFsWZ@wsQp8f6BD?Tee8~xkS)9k3q
zPBEq26*twO)fipOA=#6&_CdVHWYrt2CMEPWM}%9AQKmyp`C<FbgA22Y7gU3y2{VV2
zESv2k)eyZ{q6-|9=tIM9IBjVC6ltaprJt~BOfgEWPDayjw$oUgT>_NHpy5kgx>`LQ
z19Y9)*%gaDt(7qKDR{6NT(ml;Fw`jwKD#SnN`0__>bx_#M&_T=5_8xRv)46{@NW4z
z@YDas+AWw|l9(uJ%E5lAq$d$rb}f8)7&o-`LH1pZilg43bC0pNI9g2BDBaHXvjMHe
z>M*6z$=#rOQO#~vr-#+=^0mJk9?QI6uIL}r#B3zUxJH<6eJHZ5RkgCC8+y0k^)42b
zSiX(rXC;JtjSRle%h`*;If8LEI`pZA%<ba_`7zWTwQi3PyiYKl)v7nj4}00=Z*`O{
z;e=%u3Qu=Oy*;E)j#2$7P%_8OuK~O+aI>pXW7VjS7*nI4_vqbX_B6zpx5xATw-!$Z
z*<F>bT2wWRW;d6j%F&mDEr7BA%CX<u%^{~L798S-kP&-~%rR~5YJZNfxNCk6DZhCM
zA-_N7&e5ukw0`K*j*xf4c~o_8(_W-=<c)p0+2#A>X0RCCypJop^|xU-7nz+td%Bsz
z?xqKYu8)+ogm}Ln*;93nke1Vyq-*L^j!d+L1^*ArT{R<!oMR>c001R)MObuXVRU6W
zV{&C-bY%cCFflSMFf%PNGE^}$IxsalF*qwQF*-0Xc5IQR0000bbVXQnWMOn=I&E)c
wX=Zr<GB7bREif}JF)~y!GdeIdIyE&bFflqXFb!@k9smFU07*qoM6N<$g5J3onE(I)
deleted file mode 100644
index 2527df6e72b5c80b91e180af9644ba96a5c148d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 75d6f13d8c6e6a1cfc0d5766cfec91378e0b60c0..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cf59fa3ca1e903968f793d940b2dc651f6ac4e1f
GIT binary patch
literal 366
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@
z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)Zhm0~jSb$HZUBYedAc};Se!n4
zX}y<Apa9#4`Sk&U%?dhM@$w0glU-SErd(CXGt9sEK>CGrL^$uhrbNRVc_tAd0UIN9
z!UW4s$5_Oi6ZN$+n3K3Ke_!#whaavRPJEf0EdRcuJC3_O;y~=&2yT4|w|U8ImtUy=
z4d1f*aCZgQA=76@;%AZs=A`R9kK6c>`S$D51AZ&&6Lg!`AB$_dv9_uANb=0>oN*~1
zmaaOXvQEf}o!#P4+9mk}Em^I{+~yWXCC(KHepTJpbpJ^DT{*c&(|%j@7Ydbj+Ad>$
zEZUf-Q>dzZk0<B7btBW~7ph|3v-ck8x?l6v?}>e%pyf;J<ieGucY!`<@O1TaS?83{
F1OTL^jTis`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..442132d987b04e37e7cd24b45785e7b605be2e32
GIT binary patch
literal 1096
zc$@)91h@N%P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq|
z6AUK%MzGTW00YQLL_t(|+U=T2XcR#dhQGKVLPl|mOI(vk3}`@&UKA9gf(pUq;sV};
zfPxnxdXV695l<e>K@V<-1{4K7=tV(66csnz1w{l`P-Db}nD&rrcotnV-96pa6R97X
z>8|B%UG?g{*8>g?4h{|u4h{~9U?y+`s7!(O2;cxPzZ4bE0p|fvT%EuPpb6*`lkQUB
zDDXw2eHj>5D$4H{f_00_)2_$BE?@@GKY&g@pdM%i?gz~8)_y(UP?m~s3sBt4Be;Kk
zRYuTJ2Ye_n*Tiq9O~uy%T_J?j`~Co{L(p#me#W5h0UOd(d@k@Vf?%?LM~W*<m*q3C
zI7!7P0rx^GuJ@l-d%GAMi^=<m+E%eKLG$cUnO7zF5-NeaF=e>~)Wl)B9C#jL8OpXF
zz_Jv#;R5AE^BF>y^EI%x7^d~WHN#OS8MRn+#G6CNa~o(#lIb|$On}7?XLuC11;}#&
zs7^cTJEZpH=n@FTh5|Q$c6IMy1LeTp5|U?&&DGdXMRgwVTSabJVFvJC?Ejoi<-4^+
zXT0SVc*$@a=4>l3?~hwhevg57szxv=ZwfxPq@ehkh(TG-mhvV6Iufeh)B-PKhQT?T
z%A16^2@H?HyDxAyg5rrAVN6WsCPCUF@ZKIF6%NBYRx(r#JW9w2a_;OrJST>%2t`r;
z6)?4!ZLl`Mw{a>$e4m8!%}ILU<3;Yri-J}&JtcG>v(&QJdBxrL=h8ZZ>wu3jJo0rx
zqfxcVf=P{PlQqNh5qS7xI+Za~M@z`ctp_|5^BP3IOj#$3_9deIN=P0aJtcRm7yw)?
z5S6_W<ELoC2N}ShH%Ii{EfDqH0|whvyuViHT%^SczHpz!n6UxEn+)LhPZRww3{H4e
zK-^*l9<W|(+sD73#e57gygAbrkYgr^F>f({5o%KH*ff9#JOwJW>g@xdOg#_G<10)C
z(8o&p_tjXL72XnKtsB6<_8LOje2y}o0rWZL0rXn~=2$m?+>^h7d1B130v^1O0ra^8
z)Y$2mOXHcX0R3ywn-FJs7z0QepXvEjo^MrUW`IHkied~9MAt++R=S%c$_)3VN;mdD
zH@<1BAuCAU9X1Ux2-qavi0wV-^Yd53M%&S##KD+ZViX@>@&^Yf5sU)vL^MQH14x>8
zfRU6S76RWx8Y1d3=!e*i^a5-RacqT&1he}5o*3E_$OTT)%TWb9i;xcc<DO~RV6VqY
zQ8&;_VsZs^0W0{Av0EuB)7sjs%34{Wf}TG=%jXIl92^`R92^`R?BOqH7L8M0{IIqF
O0000<MNUMnLSTaKyWXDw
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -2318,16 +2318,20 @@ toolbarbutton.bookmark-item[dragover="tr
   list-style-image: url(chrome://global/skin/icons/question-64.png);
 }
 
 .popup-notification-icon[popupid="password-save"],
 .popup-notification-icon[popupid="password-change"] {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
 }
 
+.popup-notification-icon[popupid="webapps-install"] {
+  list-style-image: url(chrome://browser/skin/webapps-64.png);
+}
+
 /* Notification icon box */
 #notification-popup-box {
   position: relative;
   background-color: #fff;
   background-clip: padding-box;
   padding-left: 3px;
   border-radius: 2.5px 0 0 2.5px;
   border-width: 0 8px 0 0;
@@ -2370,16 +2374,20 @@ toolbarbutton.bookmark-item[dragover="tr
 #indexedDB-notification-icon {
   list-style-image: url(chrome://global/skin/icons/question-16.png);
 }
 
 #password-notification-icon {
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
 }
 
+#webapps-notification-icon {
+  list-style-image: url(chrome://browser/skin/webapps-16.png);
+}
+
 #identity-popup-container {
   min-width: 280px;
 }
 
 #download-monitor {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
   -moz-image-region: rect(0, 108px, 18px, 90px);
 }
@@ -2678,16 +2686,25 @@ panel[dimmed="true"] {
 
 #highlighter-veil-container[locked] > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
 
 /* Highlighter toolbar */
 
+#inspector-inspect-toolbutton {
+  list-style-image: url("chrome://browser/skin/devtools/inspect-button.png");
+  -moz-image-region: rect(0px 16px 16px 0px);
+}
+
+#inspector-inspect-toolbutton[checked] {
+  -moz-image-region: rect(0px 32px 16px 16px);
+}
+
 #inspector-toolbar {
   border-top: 1px solid hsla(211,68%,6%,.65) !important;
 }
 
 #devtools-side-splitter {
   border: 0;
   -moz-border-start: 1px solid #242b33;
   min-width: 0;
--- a/browser/themes/winstripe/devtools/common.css
+++ b/browser/themes/winstripe/devtools/common.css
@@ -56,16 +56,20 @@
   box-shadow: 0 1px 0 hsla(209,29%,72%,.15) inset, 0 0 0 1px hsla(209,29%,72%,.1) inset, 0 0 0 1px hsla(209,29%,72%,.1), 0 1px 0 hsla(210,16%,76%,.1);
   -moz-margin-end: 3px;
 }
 
 .devtools-toolbarbutton > .toolbarbutton-icon {
   margin: 0;
 }
 
+.devtools-toolbarbutton:not([label]) {
+  min-width: 32px;
+}
+
 .devtools-toolbarbutton:not([checked]):hover:active {
   background-color: hsla(210,18%,9%,.1);
   background-image: -moz-linear-gradient(hsla(209,13%,54%,.35), hsla(209,13%,54%,.1) 85%, hsla(209,13%,54%,.2));
   box-shadow: 0 1px 3px hsla(211,68%,6%,.5) inset, 0 0 0 1px hsla(209,29%,72%,.1), 0 1px 0 hsla(210,16%,76%,.1);
 }
 
 .devtools-toolbarbutton[checked] {
   border-color: hsla(211,68%,6%,.6);
--- a/browser/themes/winstripe/devtools/csshtmltree.css
+++ b/browser/themes/winstripe/devtools/csshtmltree.css
@@ -40,20 +40,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 :root {
   -moz-appearance: none;
   background: -moz-Field;
   color: -moz-FieldText;
 }
 
-#root {
-  display: -moz-box;
-}
-
 .property-header {
   padding: 5px 0;
   white-space: nowrap;
   vertical-align: text-top;
 }
 
 /* Take away these two :visited rules to get a core dumper     */
 /* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
@@ -67,17 +63,16 @@
 .helplink:visited {
   text-decoration: none;
 }
 .link:hover {
   text-decoration: underline;
 }
 
 .helplink {
-  display: block;
   height: 14px;
   width: 0;
   overflow: hidden;
   -moz-padding-start: 14px;
   background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
   -moz-margin-end: 2px;
   cursor: pointer;
 }
@@ -92,54 +87,44 @@
 }
 
 .expander {
   width: 9px;
   height: 9px;
   -moz-margin-start: 5px;
   -moz-margin-end: 5px;
   background: url("chrome://global/skin/tree/twisty-clsd.png") center center no-repeat;
-  display: inline-block;
   vertical-align: middle;
 }
 
 .expander[open] {
   background-image: url("chrome://global/skin/tree/twisty-open.png");
 }
 
-.expandable {
-  cursor: pointer;
-}
-
 .match {
   visibility: hidden;
 }
 
-.expandable > .property-header > .match {
+.expandable {
+  cursor: pointer;
   visibility: visible;
 }
 
 .property-name {
   font-size: 12px;
   color: -moz-FieldText;
-  display: inline-block;
 }
 .property-value {
   padding: 0;
   font-size: 10px;
   color: grey;
   vertical-align: text-top;
   width: 100%;
 }
 
-.property-view-hidden,
-.property-content-hidden {
-  display: none;
-}
-
 .rule-link {
   text-align: end;
   -moz-padding-start: 10px;
   cursor: pointer;
 }
 
 /* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
 .rule-text {
@@ -155,20 +140,16 @@
 .matched {
   text-decoration: line-through;
 }
 .parentmatch {
   color: #666;
 }
 
 #propertyContainer {
-  display: -moz-box;
-  -moz-box-orient: vertical;
-  -moz-box-flex: 1;
-  overflow-y: auto;
   border-collapse: collapse;
 }
 
 .darkrow {
   background-color: rgba(0,0,0,.022);
 }
 
 #noResults {
@@ -215,46 +196,45 @@
 }
 
 .ruleview-code {
   padding: 2px 5px;
 }
 
 .ruleview-warning {
   background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  display: inline-block;
   -moz-margin-start: 5px;
   vertical-align: middle;
   width: 13px;
   height: 12px;
 }
 
-.ruleview-warning[hidden] {
-  display: none;
+.ruleview-ruleopen {
+  -moz-padding-end: 5px;
 }
 
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
+.ruleview-ruleclose {
+  width: -moz-min-content;
+  padding-right: 20px;
 }
 
 .ruleview-propertylist {
   list-style: none;
   padding: 0;
   margin: 0;
 }
 
 .ruleview-enableproperty {
   height: 10px;
   width: 10px;
   -moz-margin-start: 2px;
   -moz-margin-end: 0;
 }
 
 .ruleview-expander {
-  display: inline-block;
   width: 8px;
   height: 8px;
   background: url("chrome://browser/skin/devtools/arrows.png") 24px 0;
   cursor: pointer;
   -moz-margin-start: 2px;
   -moz-margin-end: 5px;
 }
 
@@ -263,17 +243,16 @@
 }
 
 .ruleview-newproperty {
   /* (enable checkbox width: 12px) + (expander width: 15px) */
   -moz-margin-start: 27px;
 }
 
 .ruleview-propertyname {
-  display: inline-block;
   padding: 1px 0;
   cursor: text;
   color: #0060C0;
   text-decoration: inherit;
 }
 
 .ruleview-propertyvalue {
   cursor: text;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ebfd9586d201416665b64e4fe57af05c1a967edb
GIT binary patch
literal 1321
zc$@(#1=jkBP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iyS_
z05usk)smk800gN?L_t(Y$K{l1Y*a-6$A9zQUOjeu&=$I-(1MhZQV@|K5n=%`MvM?t
zA|`@dO7J!qFc>BJ$;23=h#Yc<s2CDN3J3&>fIzuKkaEc(bPMg$?RMGSw{PBi;|CV9
z7z})OKEBCs<~RTOzk&bz5CHDHpa&=b@&Wff7zwlk5g84c0IXFykPT!3`aO6XNCFAQ
z3)_|cSh#q>m(xc-^<>rkSl4aZa^{tpZ!Q6@0?>LXcW71c^IWfc%Kh*+QgYdzGog2Z
z=q-WbQKLqdTecIsp9MyZ8d(k$-x3g!=76GX;?;zGU$N)tVxovN&r=x!Ihv-Y0A8Lp
zBeG*>ePcT6%;6p}ytdDZZx<G5nr;I*w`Za)SuxXbDd5_lhd&MPUSE$itUGC+t7zER
z+RoJjXUA+@L|d`|Tp3-k0Cw!GZ%~Q@0yG4Ez*35MdM*Zx%<Rw2Ta`juH}`8jao{KI
z*tWB(xI$3T&qFHdh%@_5jF@Q6>)hU{cmLV9m`njOP8<QkLQuZ9e%q7{b(@=(EM2~@
ztu1mzK}#Z$l-b!?sI>5HSf=s3l6Km!U3X@!EgW1?vN3L{_2=WPN=Q2_4sK{OP16uU
z_(&xk0PSA_Qh;N3gcMNNsi>GYX1>~E_l~VEe*EFwm&!^@ONS1B{OsyA-(5|M-XS2R
z1h?0*J3>l?FZ;uZR4<{dd3|!NhHAh1#NTT`$(8-vC&j~8*AQ)q|5pNDcV18jyk4)z
zv>j#o{eCfJ^2DMEFO2W}bKRznufJJ*3NYPyK}|+O4uCYx+jq@crLljVH)YDKWD0aa
zQMOCGRasUt%_z$IC3Nw^QgZSoYn8}Mzy!=O&y4N|Q~?1^(@elrkg^>W^LV|{=bszr
zTC-|d^_*Gnbj>_~DJ7<q1bg;=npC0$pWkbkQZuC_X-cjqOqy?)Ifl~4l~wlqs$$U4
z!Q%8j{bmvJf`iUA{!#1kcyQ@jwh+Qq^U&b)M;d-B%8Yr(&U$UuoVm$x`1)bsFCc71
zLzZ}Lb+16*M@|B+LZ6OD7yRAaI@%K`sLSM?RPuQ8V&i8{^SPrK@er|a`>g~b%T}&7
z0cqJzR9g0R%d)+Iv@FY-zhIGOS(Y`t_Az_dqeCnpgd(C8cKSDro6)unQcAAH3@*1P
zabgi)x))9=(y~=b>A2kP>in)1-IUwc%ISSEacHA+Gl4)b0Q5l674QM=MV&hNk2LHp
zdvDHM&ksMYYo0oJQrSlzyl)srGHd#b*N^?Wd+#0@4J81yAro@&<(A{}l%VS#gdTHO
zJseQoYqmPk@N(zGuJ85!Bc_Vng7JkuJ)UyJvk^<*$=kh69YA>fGTrJczy+YGw6u##
z8b)B@;-x2096$Q|F{698@-8(seNzH*wrt&g#!1Bt0Ij3V7R_g4qUlttxO}o%v^BN5
z9~kJ7?ku4WZk$ik=?f|zJ*GNW4ltCc%oettjD)waYlReddn#RdK@CL!$OUdFxFMjR
zpfJDxxUpkOmo8t~2sB#JQ2cJZ9taBc;1jtdV>w78A<iF7sOs8)sHo}dR1O#`&K+7r
fEPTn?{Dtuko9Z^s$RVN?00000NkvXXu0mjf0U~aI
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -16,16 +16,18 @@ browser.jar:
 #endif
         skin/classic/browser/actionicon-tab.png
         skin/classic/browser/appmenu-icons.png
         skin/classic/browser/appmenu-dropmarker.png
 *       skin/classic/browser/browser.css                             (browser.css)
 *       skin/classic/browser/engineManager.css                       (engineManager.css)
         skin/classic/browser/Geolocation-16.png
         skin/classic/browser/Geolocation-64.png
+        skin/classic/browser/webapps-16.png
+        skin/classic/browser/webapps-64.png
         skin/classic/browser/Info.png                                (Info.png)
         skin/classic/browser/identity.png                            (identity.png)
         skin/classic/browser/keyhole-forward-mask.svg
         skin/classic/browser/KUI-background.png
         skin/classic/browser/KUI-close.png
         skin/classic/browser/pageInfo.css
         skin/classic/browser/pageInfo.png                            (pageInfo.png)
         skin/classic/browser/page-livemarks.png                      (feeds/feedIcon16.png)
@@ -52,18 +54,18 @@ browser.jar:
         skin/classic/browser/feeds/feedIcon16.png                    (feeds/feedIcon16.png)
         skin/classic/browser/feeds/audioFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/audioFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/videoFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/videoFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/subscribe.css                     (feeds/subscribe.css)
         skin/classic/browser/feeds/subscribe-ui.css                  (feeds/subscribe-ui.css)
         skin/classic/browser/newtab/newTab.css                       (newtab/newTab.css)
-        skin/classic/browser/newtab/strip.png                        (newtab/strip.png)
-        skin/classic/browser/newtab/toolbar.png                      (newtab/toolbar.png)
+        skin/classic/browser/newtab/controls.png                     (newtab/controls.png)
+        skin/classic/browser/newtab/noise.png                        (newtab/noise.png)
         skin/classic/browser/places/places.css                       (places/places.css)
 *       skin/classic/browser/places/organizer.css                    (places/organizer.css)
         skin/classic/browser/places/bookmark.png                     (places/bookmark.png)
         skin/classic/browser/places/editBookmark.png                 (places/editBookmark.png)
         skin/classic/browser/places/query.png                        (places/query.png)
         skin/classic/browser/places/bookmarksMenu.png                (places/bookmarksMenu.png)
         skin/classic/browser/places/bookmarksToolbar.png             (places/bookmarksToolbar.png)
         skin/classic/browser/places/calendar.png                     (places/calendar.png)
@@ -149,16 +151,17 @@ browser.jar:
         skin/classic/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
         skin/classic/browser/devtools/splitview.css                 (devtools/splitview.css)
         skin/classic/browser/devtools/styleeditor.css               (devtools/styleeditor.css)
         skin/classic/browser/devtools/debugger.css                  (devtools/debugger.css)
         skin/classic/browser/devtools/magnifying-glass.png          (devtools/magnifying-glass.png)
         skin/classic/browser/devtools/itemToggle.png                (devtools/itemToggle.png)
         skin/classic/browser/devtools/itemArrow-rtl.png             (devtools/itemArrow-rtl.png)
         skin/classic/browser/devtools/itemArrow-ltr.png             (devtools/itemArrow-ltr.png)
+        skin/classic/browser/devtools/inspect-button.png            (devtools/inspect-button.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/sync-throbber.png
         skin/classic/browser/sync-16.png
         skin/classic/browser/sync-32.png
         skin/classic/browser/sync-128.png
         skin/classic/browser/sync-bg.png
         skin/classic/browser/sync-desktopIcon.png
         skin/classic/browser/sync-mobileIcon.png
@@ -185,16 +188,18 @@ browser.jar:
 #endif
         skin/classic/aero/browser/actionicon-tab.png                 (actionicon-tab.png)
         skin/classic/aero/browser/appmenu-dropmarker.png
         skin/classic/aero/browser/appmenu-icons.png
 *       skin/classic/aero/browser/browser.css                        (browser-aero.css)
 *       skin/classic/aero/browser/engineManager.css                  (engineManager.css)
         skin/classic/aero/browser/Geolocation-16.png
         skin/classic/aero/browser/Geolocation-64.png
+        skin/classic/aero/browser/webapps-16.png
+        skin/classic/aero/browser/webapps-64.png
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/keyhole-forward-mask.svg
         skin/classic/aero/browser/KUI-background.png
         skin/classic/aero/browser/KUI-close.png
         skin/classic/aero/browser/pageInfo.css
         skin/classic/aero/browser/pageInfo.png                       (pageInfo-aero.png)
         skin/classic/aero/browser/page-livemarks.png                 (feeds/feedIcon16-aero.png)
@@ -221,18 +226,18 @@ browser.jar:
         skin/classic/aero/browser/feeds/feedIcon16.png               (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/subscribe.css                (feeds/subscribe.css)
         skin/classic/aero/browser/feeds/subscribe-ui.css             (feeds/subscribe-ui.css)
         skin/classic/aero/browser/newtab/newTab.css                  (newtab/newTab.css)
-        skin/classic/aero/browser/newtab/strip.png                   (newtab/strip.png)
-        skin/classic/aero/browser/newtab/toolbar.png                 (newtab/toolbar.png)
+        skin/classic/aero/browser/newtab/controls.png                (newtab/controls.png)
+        skin/classic/aero/browser/newtab/noise.png                   (newtab/noise.png)
 *       skin/classic/aero/browser/places/places.css                  (places/places-aero.css)
 *       skin/classic/aero/browser/places/organizer.css               (places/organizer-aero.css)
         skin/classic/aero/browser/places/bookmark.png                (places/bookmark.png)
         skin/classic/aero/browser/places/editBookmark.png            (places/editBookmark.png)
         skin/classic/aero/browser/places/query.png                   (places/query-aero.png)
         skin/classic/aero/browser/places/bookmarksMenu.png           (places/bookmarksMenu-aero.png)
         skin/classic/aero/browser/places/bookmarksToolbar.png        (places/bookmarksToolbar-aero.png)
         skin/classic/aero/browser/places/calendar.png                (places/calendar-aero.png)
@@ -318,16 +323,17 @@ browser.jar:
         skin/classic/aero/browser/devtools/breadcrumbs/rtl-start-selected.png           (devtools/breadcrumbs/rtl-start-selected.png)
         skin/classic/aero/browser/devtools/splitview.css             (devtools/splitview.css)
         skin/classic/aero/browser/devtools/styleeditor.css           (devtools/styleeditor.css)
         skin/classic/aero/browser/devtools/debugger.css              (devtools/debugger.css)
         skin/classic/aero/browser/devtools/magnifying-glass.png      (devtools/magnifying-glass.png)
         skin/classic/aero/browser/devtools/itemToggle.png            (devtools/itemToggle.png)
         skin/classic/aero/browser/devtools/itemArrow-rtl.png         (devtools/itemArrow-rtl.png)
         skin/classic/aero/browser/devtools/itemArrow-ltr.png         (devtools/itemArrow-ltr.png)
+        skin/classic/aero/browser/devtools/inspect-button.png        (devtools/inspect-button.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/sync-throbber.png
         skin/classic/aero/browser/sync-16.png
         skin/classic/aero/browser/sync-32.png
         skin/classic/aero/browser/sync-128.png
         skin/classic/aero/browser/sync-bg.png
         skin/classic/aero/browser/sync-desktopIcon.png
         skin/classic/aero/browser/sync-mobileIcon.png
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..14f382fbdd18a1209f3dcd63831014b5ad2fc428
GIT binary patch
literal 4180
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
--- a/browser/themes/winstripe/newtab/newTab.css
+++ b/browser/themes/winstripe/newtab/newTab.css
@@ -1,148 +1,131 @@
-#scrollbox {
-  padding-bottom: 18px;
-  background-color: #fff;
-}
-
-#body {
-  padding-top: 106px;
-  font-family: sans-serif;
-}
-
-.button {
-  padding: 0;
-  border: 0 none;
+:root {
+  -moz-appearance: none;
+  background-color: transparent;
 }
 
-/* TOOLBAR */
-#toolbar {
-  top: 8px;
-  right: 8px;
-  width: 13px;
-  height: 30px;
-  padding: 0;
-  margin: 0;
-}
-
-.toolbar-button {
-  background: transparent url(chrome://browser/skin/newtab/toolbar.png);
-}
-
-#toolbar-button-show {
-  width: 11px;
-  height: 11px;
-  background-position: -10px 0;
-}
-
-#toolbar-button-show:hover {
-  background-position: -10px -12px;
+/* SCROLLBOX */
+#newtab-scrollbox:not([page-disabled]) {
+  background-color: rgb(229,229,229);
+  background-image: url(chrome://browser/skin/newtab/noise.png),
+                    -moz-linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.2));
+  background-attachment: fixed;
 }
 
-#toolbar-button-show:active {
-  background-position: -10px -24px;
-}
-
-#toolbar-button-hide {
-  width: 10px;
-  height: 10px;
-}
-
-#toolbar-button-hide:hover {
-  background-position: 0 -12px;
-}
-
-#toolbar-button-hide:active {
-  background-position: 0 -24px;
+/* TOGGLE */
+#newtab-toggle {
+  width: 16px;
+  height: 16px;
+  padding: 0;
+  border: none;
+  background: -216px 0 transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-#toolbar-button-reset {
-  top: 17px;
-  width: 11px;
-  height: 12px;
-}
-
-#toolbar-button-reset {
-  background-position: -21px 0;
+#newtab-toggle[page-disabled] {
+  background-position: -232px 0;
 }
 
-#toolbar-button-reset:hover {
-  background-position: -21px -12px;
+/* ROWS */
+.newtab-row {
+  margin-bottom: 20px;
 }
 
-#toolbar-button-reset:active {
-  background-position: -21px -24px;
-}
-
-/* GRID */
-#grid {
-  padding: 1px;
-  margin: 0 auto;
+.newtab-row:last-child {
+  margin-bottom: 0;
 }
 
 /* CELLS */
-.cell {
-  outline: 1px dashed #ccc;
-  outline-offset: -1px;
+.newtab-cell {
+  -moz-margin-end: 20px;
+  background-color: rgba(255,255,255,.2);
+  border: 1px solid;
+  border-color: rgba(8,22,37,.12) rgba(8,22,37,.14) rgba(8,22,37,.16);
+  border-radius: 1px;
+  -moz-transition: border-color 100ms ease-out;
+}
+
+.newtab-cell:empty {
+  border: 1px dashed;
+  border-color: rgba(8,22,37,.15) rgba(8,22,37,.17) rgba(8,22,37,.19);
+}
+
+.newtab-cell:last-child {
+  -moz-margin-end: 0;
+}
+
+.newtab-cell:hover:not(:empty) {
+  border-color: rgba(8,22,37,.25) rgba(8,22,37,.27) rgba(8,22,37,.3);
 }
 
 /* SITES */
-.site {
-  background-color: #ececec;
-  -moz-transition: 200ms ease-out;
-  -moz-transition-property: top, left, box-shadow, opacity;
+.newtab-site {
+  text-decoration: none;
+  -moz-transition-property: top, left, opacity, box-shadow, background-color;
 }
 
-.site[dragged] {
-  -moz-transition-property: box-shadow;
+.newtab-site:hover,
+.newtab-site[dragged] {
+  box-shadow: 0 0 10px rgba(8,22,37,.3);
+}
+
+.newtab-site[dragged] {
+  -moz-transition-property: box-shadow, background-color;
+  background-color: rgb(242,242,242);
 }
 
-.site[ontop] {
-  box-shadow: 0 1px 4px #000;
-  outline: none;
+/* THUMBNAILS */
+.newtab-thumbnail {
+  background-origin: padding-box;
+  background-clip: padding-box;
+  background-repeat: no-repeat;
+  background-size: cover;
 }
 
-/* SITE TITLE */
-.site-title {
-  height: 2.4em;
-  width: 189px;
-  padding: 0 6px;
-  background-color: rgba(0,0,0,0.5);
-  border: solid transparent;
-  border-width: 6px 0;
-  color: #fff;
-  text-decoration: none;
-  line-height: 1.2em;
-  font-weight: 700;
+/* TITLES */
+.newtab-title {
+  padding: 0 8px;
+  background-color: rgba(248,249,251,.95);
+  color: #1f364c;
+  font-size: 12px;
+  line-height: 24px;
 }
 
-/* SITE STRIP */
-.site-strip {
-  padding: 4px 3px;
-  background-color: rgba(0,0,0,0.5);
+/* CONTROLS */
+.newtab-control {
+  width: 24px;
+  height: 24px;
+  padding: 1px 2px 3px;
+  border: none;
+  background: transparent url(chrome://browser/skin/newtab/controls.png);
 }
 
-.strip-button {
-  width: 17px;
-  height: 17px;
-  background: transparent url(chrome://browser/skin/newtab/strip.png);
+.newtab-control-pin:hover {
+  background-position: -24px 0;
 }
 
-.strip-button-pin:hover {
-  background-position: 0 -17px;
+.newtab-control-pin:active {
+  background-position: -48px 0;
 }
 
-.strip-button-pin:active,
-.site[pinned] .strip-button-pin {
-  background-position: 0 -34px;
+.newtab-control-pin[pinned] {
+  background-position: -72px 0;
+}
+
+.newtab-control-pin[pinned]:hover {
+  background-position: -96px 0;
+}
+
+.newtab-control-pin[pinned]:active {
+  background-position: -120px 0;
 }
 
-.strip-button-block {
-  background-position: -17px 0;
+.newtab-control-block {
+  background-position: -144px 0;
 }
 
-.strip-button-block:hover {
-  background-position: -17px -17px;
+.newtab-control-block:hover {
+  background-position: -168px 0;
 }
 
-.strip-button-block:active {
-  background-position: -17px -34px;
+.newtab-control-block:active {
+  background-position: -192px 0;
 }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01d340aaa9095a54d19071516cf9e0ca75b1f72e
GIT binary patch
literal 2118
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
deleted file mode 100644
index 2527df6e72b5c80b91e180af9644ba96a5c148d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 33bb4a320e76cc7a346ca4beb60e89a85a48aa2c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cf59fa3ca1e903968f793d940b2dc651f6ac4e1f
GIT binary patch
literal 366
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@
z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPgg)Zhm0~jSb$HZUBYedAc};Se!n4
zX}y<Apa9#4`Sk&U%?dhM@$w0glU-SErd(CXGt9sEK>CGrL^$uhrbNRVc_tAd0UIN9
z!UW4s$5_Oi6ZN$+n3K3Ke_!#whaavRPJEf0EdRcuJC3_O;y~=&2yT4|w|U8ImtUy=
z4d1f*aCZgQA=76@;%AZs=A`R9kK6c>`S$D51AZ&&6Lg!`AB$_dv9_uANb=0>oN*~1
zmaaOXvQEf}o!#P4+9mk}Em^I{+~yWXCC(KHepTJpbpJ^DT{*c&(|%j@7Ydbj+Ad>$
zEZUf-Q>dzZk0<B7btBW~7ph|3v-ck8x?l6v?}>e%pyf;J<ieGucY!`<@O1TaS?83{
F1OTL^jTis`
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..442132d987b04e37e7cd24b45785e7b605be2e32
GIT binary patch
literal 1096
zc$@)91h@N%P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipq|
z6AUK%MzGTW00YQLL_t(|+U=T2XcR#dhQGKVLPl|mOI(vk3}`@&UKA9gf(pUq;sV};
zfPxnxdXV695l<e>K@V<-1{4K7=tV(66csnz1w{l`P-Db}nD&rrcotnV-96pa6R97X
z>8|B%UG?g{*8>g?4h{|u4h{~9U?y+`s7!(O2;cxPzZ4bE0p|fvT%EuPpb6*`lkQUB
zDDXw2eHj>5D$4H{f_00_)2_$BE?@@GKY&g@pdM%i?gz~8)_y(UP?m~s3sBt4Be;Kk
zRYuTJ2Ye_n*Tiq9O~uy%T_J?j`~Co{L(p#me#W5h0UOd(d@k@Vf?%?LM~W*<m*q3C
zI7!7P0rx^GuJ@l-d%GAMi^=<m+E%eKLG$cUnO7zF5-NeaF=e>~)Wl)B9C#jL8OpXF
zz_Jv#;R5AE^BF>y^EI%x7^d~WHN#OS8MRn+#G6CNa~o(#lIb|$On}7?XLuC11;}#&
zs7^cTJEZpH=n@FTh5|Q$c6IMy1LeTp5|U?&&DGdXMRgwVTSabJVFvJC?Ejoi<-4^+
zXT0SVc*$@a=4>l3?~hwhevg57szxv=ZwfxPq@ehkh(TG-mhvV6Iufeh)B-PKhQT?T
z%A16^2@H?HyDxAyg5rrAVN6WsCPCUF@ZKIF6%NBYRx(r#JW9w2a_;OrJST>%2t`r;
z6)?4!ZLl`Mw{a>$e4m8!%}ILU<3;Yri-J}&JtcG>v(&QJdBxrL=h8ZZ>wu3jJo0rx
zqfxcVf=P{PlQqNh5qS7xI+Za~M@z`ctp_|5^BP3IOj#$3_9deIN=P0aJtcRm7yw)?
z5S6_W<ELoC2N}ShH%Ii{EfDqH0|whvyuViHT%^SczHpz!n6UxEn+)LhPZRww3{H4e
zK-^*l9<W|(+sD73#e57gygAbrkYgr^F>f({5o%KH*ff9#JOwJW>g@xdOg#_G<10)C
z(8o&p_tjXL72XnKtsB6<_8LOje2y}o0rWZL0rXn~=2$m?+>^h7d1B130v^1O0ra^8
z)Y$2mOXHcX0R3ywn-FJs7z0QepXvEjo^MrUW`IHkied~9MAt++R=S%c$_)3VN;mdD
zH@<1BAuCAU9X1Ux2-qavi0wV-^Yd53M%&S##KD+ZViX@>@&^Yf5sU)vL^MQH14x>8
zfRU6S76RWx8Y1d3=!e*i^a5-RacqT&1he}5o*3E_$OTT)%TWb9i;xcc<DO~RV6VqY
zQ8&;_VsZs^0W0{Av0EuB)7sjs%34{Wf}TG=%jXIl92^`R92^`R?BOqH7L8M0{IIqF
O0000<MNUMnLSTaKyWXDw
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -454,17 +454,17 @@ def wrapCommand(cmd):
   return cmd
 
 class ShutdownLeakLogger(object):
   """
   Parses the mochitest run log when running a debug build, assigns all leaked
   DOM windows (that are still around after test suite shutdown, despite running
   the GC) to the tests that created them and prints leak statistics.
   """
-  MAX_LEAK_COUNT = 120
+  MAX_LEAK_COUNT = 121
 
   def __init__(self, logger):
     self.logger = logger
     self.tests = []
     self.leakedWindows = {}
     self.leakedDocShells = set()
     self.currentTest = None
     self.seenShutdown = False
@@ -486,17 +486,17 @@ class ShutdownLeakLogger(object):
       self.seenShutdown = True
 
   def parse(self):
     leakingTests = self._parseLeakingTests()
 
     if leakingTests:
       totalWindows = sum(len(test["leakedWindows"]) for test in leakingTests)
       totalDocShells = sum(len(test["leakedDocShells"]) for test in leakingTests)
-      msgType = "INFO" if totalWindows + totalDocShells < self.MAX_LEAK_COUNT else "UNEXPECTED-FAIL"
+      msgType = "INFO" if totalWindows + totalDocShells <= self.MAX_LEAK_COUNT else "UNEXPECTED-FAIL"
       self.logger.info("TEST-%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
 
     for test in leakingTests:
       self.logger.info("\n[%s]", test["fileName"])
 
       for url, count in self._zipLeakedWindows(test["leakedWindows"]):
         self.logger.info("  %d window(s) [url = %s]", count, url)
 
--- a/build/mobile/robocop/Actions.java.in
+++ b/build/mobile/robocop/Actions.java.in
@@ -34,16 +34,19 @@
  * 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 ***** */
 
 package @ANDROID_PACKAGE_NAME@;
 import java.util.List;
+import java.util.ArrayList;
+
+import android.database.Cursor;
 
 public interface Actions {
 
     /** Special keys supported by sendSpecialKey() */
     public enum SpecialKey {
         DOWN, UP, LEFT, RIGHT, ENTER, MENU, BACK
     }
 
@@ -87,9 +90,14 @@ public interface Actions {
     /**
      * Send a special keycode to the element
      *
      * @param key The special key to send
      */
     void sendSpecialKey(SpecialKey key);
 
     void drag(int startingX, int endingX, int startingY, int endingY);
+
+    /**
+     * Run a sql query on the specified database
+     */
+    public Cursor querySql(String dbPath, String sql);
 }
--- a/build/mobile/robocop/FennecMochitestAssert.java.in
+++ b/build/mobile/robocop/FennecMochitestAssert.java.in
@@ -161,31 +161,23 @@ public class FennecMochitestAssert imple
 
     public void ok(boolean condition, String name, String diag) {
         testInfo test = new testInfo(condition, name, diag, false);
         _logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
         mTestList.add(test);
     }
 
     public void is(Object a, Object b, String name) {
-        boolean pass = a.equals(b);
-        String diag = "got " + a.toString() + ", expected " + b.toString();
-        if (pass) {
-            diag = a.toString() + " should equal " + b.toString();
-        }
-        ok(pass, name, diag);
+        boolean pass = checkObjectsEqual(a,b);
+        ok(pass, name, getEqualString(a,b, pass));
     }
     
     public void isnot(Object a, Object b, String name) {
-        boolean pass = !a.equals(b);
-        String diag = "didn't expect " + a.toString() + ", but got it";
-        if (pass) {
-            diag = a.toString() + " should not equal " + b.toString();
-        }
-        ok(pass, name, diag);
+        boolean pass = checkObjectsNotEqual(a,b);
+        ok(pass, name, getNotEqualString(a,b,pass));
     }
 
     public void ispixel(int actual, int r, int g, int b, String name) {
         // When we read GL pixels the GPU has already processed them and they
         // are usually off by a little bit. For example a CSS-color pixel of color #64FFF5
         // was turned into #63FFF7 when it came out of glReadPixels. So in order to compare
         // against the expected value, we use a little fuzz factor. For the alpha we just
         // make sure it is always 0xFF.
@@ -202,30 +194,59 @@ public class FennecMochitestAssert imple
 
     public void todo(boolean condition, String name, String diag) {
         testInfo test = new testInfo(condition, name, diag, true);
         _logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
         mTestList.add(test);
     }
 
     public void todo_is(Object a, Object b, String name) {
-        boolean pass = a.equals(b);
-        String diag = "got " + a.toString() + ", expected " + b.toString();
-        if (pass) {
-            diag = a.toString() + " should equal " + b.toString();
+        boolean pass = checkObjectsEqual(a,b);
+        todo(pass, name, getEqualString(a,b,pass));
+    }
+
+    public void todo_isnot(Object a, Object b, String name) {
+        boolean pass = checkObjectsNotEqual(a,b);
+        todo(pass, name, getNotEqualString(a,b,pass));
+    }
+
+    private boolean checkObjectsEqual(Object a, Object b) {
+        if (a == null || b == null) {
+            if (a == null && b == null) {
+                return true;
+            }
+            return false;
+        } else {
+            return a.equals(b);
         }
-        todo(pass, name, diag);
     }
-    
-    public void todo_isnot(Object a, Object b, String name) {
-        boolean pass = !a.equals(b);
-        String diag = "didn't expect " + a.toString() + ", but got it";
+
+    private String getEqualString(Object a, Object b, boolean pass) {
         if (pass) {
-            diag = a.toString() + " should not equal " + b.toString();
+            return a + " should equal " + b;
         }
-        todo(pass, name, diag);
+        return "got " + a + ", expected " + b;
+    }
+
+    private boolean checkObjectsNotEqual(Object a, Object b) {
+        if (a == null || b == null) {
+            if ((a == null && b != null) || (a != null && b == null)) {
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            return !a.equals(b);
+        }
+    }
+
+    private String getNotEqualString(Object a, Object b, boolean pass) {
+        if(pass) {
+            return a + " should not equal " + b;
+        }
+        return "didn't expect " + a + ", but got it";
     }
 
     public void info(String name, String message) {
         testInfo test = new testInfo(true, name, message, false);
         _logMochitestResult(test, "TEST-INFO", "INFO FAILED?");
     }
 }
--- a/build/mobile/robocop/FennecNativeActions.java.in
+++ b/build/mobile/robocop/FennecNativeActions.java.in
@@ -35,29 +35,34 @@
  * 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 ***** */
 
 package @ANDROID_PACKAGE_NAME@;
 
 import java.lang.Class;
+import java.lang.ClassLoader;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.InvocationHandler;
 import java.lang.Long;
+import java.util.concurrent.SynchronousQueue;
+import java.util.ArrayList;
 
 import android.app.Activity;
+import android.content.Context;
 import android.app.Instrumentation;
+import android.database.Cursor;
 import android.os.SystemClock;
 import android.view.View;
 import android.view.KeyEvent;
-
-import java.util.concurrent.SynchronousQueue;
+import android.util.Log;
 
 import org.json.*;
 
 import com.jayway.android.robotium.solo.Solo;
 
 public class FennecNativeActions implements Actions {
     private Solo mSolo;
     private Instrumentation mInstr;
@@ -69,16 +74,17 @@ public class FennecNativeActions impleme
     private Class mGe;
     private Class mGas;
     private Class mDrawListener;
     private Method mRegisterGEL;
     private Method mUnregisterGEL;
     private Method mSendGE;
     private Method mGetLayerClient;
     private Method mSetDrawListener;
+    private static final String LOGTAG = "FennecNativeActions";
 
     public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation) {
         mSolo = robocop;
         mInstr = instrumentation;
         mGeckoApp = activity;
         // Set up reflexive access of java classes and methods.
         try {
             mClassLoader = activity.getClassLoader();
@@ -344,9 +350,41 @@ public class FennecNativeActions impleme
     @Override