Merge last green changeset of mozilla-inbound to mozilla-central AURORA_BASE_20111220
authorEd Morley <bmo@edmorley.co.uk>
Tue, 20 Dec 2011 16:52:57 +0000
changeset 83130 a8506ab2c65480cf2f85f54e203ea746522c62bb
parent 83113 c7101dec8deb827a2c91eafe3ba2fafd506fc8c9 (current diff)
parent 83129 eeb4b35a1ea8ffce448e11fd66d3908a0e0d5273 (diff)
child 83131 00dc96a6c12b3070371d291adad110e6afc8bd14
push id21732
push userbmo@edmorley.co.uk
push dateTue, 20 Dec 2011 16:54:34 +0000
treeherdermozilla-central@a8506ab2c654 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone11.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 last green changeset of mozilla-inbound to mozilla-central
build/unix/gnu-ld-scripts/jemalloc-standalone-linkage-version-script
layout/tools/reftest/quit.js
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/strings.xml.in
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -101,19 +101,17 @@ nsHTMLTableCellAccessible::NativeState()
 {
   PRUint64 state = nsHyperTextAccessibleWrap::NativeState();
 
   nsIFrame *frame = mContent->GetPrimaryFrame();
   NS_ASSERTION(frame, "No frame for valid cell accessible!");
 
   if (frame) {
     state |= states::SELECTABLE;
-    bool isSelected = false;
-    frame->GetSelected(&isSelected);
-    if (isSelected)
+    if (frame->IsSelected())
       state |= states::SELECTED;
   }
 
   return state;
 }
 
 nsresult
 nsHTMLTableCellAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
--- a/accessible/tests/mochitest/table/test_table_1.html
+++ b/accessible/tests/mochitest/table/test_table_1.html
@@ -21,28 +21,34 @@ function doTest()
 
   var cell = getNode("col2b");
   var range = document.createRange();
   range.selectNode(cell);
   s.addRange(range);
 
   is(accTable.selectedCellCount, 1, "only one cell selected");
   cell = getNode("col2a");
+  range = document.createRange();
   range.selectNode(cell);
   s.addRange(range);
   cell = getNode("col2c");
+  range = document.createRange();
   range.selectNode(cell);
   s.addRange(range);
   is(accTable.selectedColumnCount, 1, "only one column selected");
+
   cell = getNode("row2a");
+  range = document.createRange();
   range.selectNode(cell);
   s.addRange(range);
   cell = getNode("row2b");
+  range = document.createRange();
   range.selectNode(cell);
   s.addRange(range);
+  range = document.createRange();
   cell = getNode("row2c");
   range.selectNode(cell);
   s.addRange(range);
 
   is(accTable.selectedRowCount, 1, "no cells selected");
 
   var columnDescription;
   works = true;
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -44,19 +44,16 @@ pref("browser.chromeURL", "chrome://brow
 pref("browser.homescreenURL", "file:///system/home/homescreen.html");
 #else
 pref("browser.homescreenURL", "file:///data/local/homescreen.html,file:///system/home/homescreen.html");
 #endif
 
 // Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
 pref("browser.viewport.scaleRatio", -1);
 
-/* allow scrollbars to float above chrome ui */
-pref("ui.scrollbarsCanOverlapContent", 1);
-
 /* disable text selection */
 pref("browser.ignoreNativeFrameTextSelection", true);
 
 /* cache prefs */
 pref("browser.cache.disk.enable", false);
 pref("browser.cache.disk.capacity", 0); // kilobytes
 pref("browser.cache.disk.smart_size.enabled", false);
 pref("browser.cache.disk.smart_size.first_run", false);
new file mode 100644
--- /dev/null
+++ b/b2g/chrome/content/content.css
@@ -0,0 +1,112 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla B2G.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+@namespace url("http://www.w3.org/1999/xhtml");
+@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+
+/* Style the scrollbars */
+xul|window xul|scrollbar {
+  display: none;
+}
+
+html xul|scrollbar {
+  display: block;
+}
+
+xul|scrollbar[orient="vertical"] {
+  -moz-appearance: none !important;
+  position: relative;
+  margin-left: -8px;
+  min-width: 8px;
+  max-width: 8px;
+  background-color: transparent !important;
+  background-image: none !important;
+  border: 0px solid transparent !important;
+}
+
+xul|scrollbar[orient="vertical"]:-moz-locale-dir(rtl) {
+  margin-left: 2px;
+  margin-right: -10px;
+}
+
+xul|scrollbar[orient="vertical"] xul|thumb {
+  max-width: 6px !important;
+  min-width: 6px !important;
+}
+
+xul|scrollbar[orient="horizontal"] {
+  -moz-appearance: none !important;
+  position: relative;
+  min-height: 8px;
+  max-height: 8px;
+  margin-top: -8px;
+  background-color: transparent !important;
+  background-image: none !important;
+  border: 0px solid transparent !important;
+}
+
+xul|scrollbar[orient="horizontal"] xul|thumb {
+  max-height: 6px !important;
+  min-height: 6px !important;
+}
+
+xul|scrollbox {
+  overflow-y: scroll;
+  overflow-x: scroll;
+}
+
+xul|scrollbarbutton {
+  min-height: 8px !important;
+  min-width: 8px !important;
+  -moz-appearance: none !important;
+  visibility: hidden;
+}
+
+xul|scrollbarbutton[sbattr="scrollbar-up-top"],
+xul|scrollbarbutton[sbattr="scrollbar-bottom-top"] {
+  display: none;
+}
+
+xul|thumb {
+  background-color: rgba(0, 0, 0, 0.4) !important;
+  -moz-border-top-colors: none !important;
+  -moz-border-bottom-colors: none !important;
+  -moz-border-right-colors: none !important;
+  -moz-border-left-colors: none !important;
+  border: 1px solid rgba(255, 255, 255, 0.4) !important;
+  -moz-border-radius: 3px;
+}
+
--- a/b2g/chrome/jar.mn
+++ b/b2g/chrome/jar.mn
@@ -4,11 +4,12 @@ chrome.jar:
 % content branding %content/branding/
 % content browser %content/
 
 * content/shell.xul                     (content/shell.xul)
   content/shell.js                      (content/shell.js)
   content/touch.js                      (content/touch.js)
   content/commandUtil.js                (content/commandUtil.js)
   content/httpd.js                      (content/httpd.js)
+  content/content.css                   (content/content.css)
 
 % override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
   content/netError.xhtml                (content/netError.xhtml)
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -0,0 +1,2 @@
+# Scrollbars
+category agent-style-sheets browser-content-stylesheet chrome://browser/content/content.css
deleted file mode 100644
--- a/build/unix/gnu-ld-scripts/jemalloc-standalone-linkage-version-script
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-   global:
-		_malloc_postfork;
-		_malloc_prefork;
-		jemalloc_stats;
-		malloc_usable_size;
-		je_malloc_usable_size_in_advance;
-		posix_memalign;
-		free;
-		realloc;
-		calloc;
-		malloc;
-		memalign;
-		valloc;
-		__free_hook;
-		__malloc_hook;
-		__realloc_hook;
-		__memalign_hook;
-		_IO_stdin_used;
-   local: *;
-};
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -912,16 +912,28 @@ public:
     CheckNotNativeAnonymous();
     return false;
 #else
     return HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE);
 #endif
   }
 
   /**
+   * Returns true if |this| node is the common ancestor of the start/end
+   * nodes of a Range in a Selection or a descendant of such a common ancestor.
+   * This node is definitely not selected when |false| is returned, but it may
+   * or may not be selected when |true| is returned.
+   */
+  bool IsSelectionDescendant() const
+  {
+    return IsDescendantOfCommonAncestorForRangeInSelection() ||
+           IsCommonAncestorForRangeInSelection();
+  }
+
+  /**
    * Get the root content of an editor. So, this node must be a descendant of
    * an editor. Note that this should be only used for getting input or textarea
    * editor's root content. This method doesn't support HTML editors.
    */
   nsIContent* GetTextEditorRootContent(nsIEditor** aEditor = nsnull);
 
   /**
    * Get the nearest selection root, ie. the node that will be selected if the
@@ -1196,16 +1208,21 @@ private:
     // documents with different id mappings.
     ElementHasID,
     // Set if the element might have inline style.
     ElementMayHaveStyle,
     // Set if the element has a name attribute set.
     ElementHasName,
     // Set if the element might have a contenteditable attribute set.
     ElementMayHaveContentEditableAttr,
+    // Set if the node is the common ancestor of the start/end nodes of a Range
+    // that is in a Selection.
+    NodeIsCommonAncestorForRangeInSelection,
+    // Set if the node is a descendant of a node with the above bit set.
+    NodeIsDescendantOfCommonAncestorForRangeInSelection,
     // Guard value
     BooleanFlagCount
   };
 
   void SetBoolFlag(BooleanFlag name, bool value) {
     PR_STATIC_ASSERT(BooleanFlagCount <= 8*sizeof(mBoolFlags));
     mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
   }
@@ -1230,16 +1247,28 @@ public:
     { return GetBoolFlag(NodeHasRenderingObservers); }
   void SetHasRenderingObservers(bool aValue)
     { SetBoolFlag(NodeHasRenderingObservers, aValue); }
   bool HasID() const { return GetBoolFlag(ElementHasID); }
   bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); }
   bool HasName() const { return GetBoolFlag(ElementHasName); }
   bool MayHaveContentEditableAttr() const
     { return GetBoolFlag(ElementMayHaveContentEditableAttr); }
+  bool IsCommonAncestorForRangeInSelection() const
+    { return GetBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
+  void SetCommonAncestorForRangeInSelection()
+    { SetBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
+  void ClearCommonAncestorForRangeInSelection()
+    { ClearBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
+  bool IsDescendantOfCommonAncestorForRangeInSelection() const
+    { return GetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
+  void SetDescendantOfCommonAncestorForRangeInSelection()
+    { SetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
+  void ClearDescendantOfCommonAncestorForRangeInSelection()
+    { ClearBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
 
 protected:
   void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
   void SetInDocument() { SetBoolFlag(IsInDocument); }
   void ClearInDocument() { ClearBoolFlag(IsInDocument); }
   void SetIsElement() { SetBoolFlag(NodeIsElement); }
   void ClearIsElement() { ClearBoolFlag(NodeIsElement); }
   void SetHasID() { SetBoolFlag(ElementHasID); }
--- a/content/base/public/nsIRange.h
+++ b/content/base/public/nsIRange.h
@@ -35,18 +35,20 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsIRange_h___
 #define nsIRange_h___
 
 #include "nsISupports.h"
 #include "nsCOMPtr.h"
+#include "nsHashKeys.h"
 #include "nsINode.h"
 #include "nsIDOMRange.h"
+#include "nsTHashtable.h"
 
 // IID for the nsIRange interface
 #define NS_IRANGE_IID \
 { 0x09dec26b, 0x1ab7, 0x4ff0, \
  { 0xa1, 0x67, 0x7f, 0x22, 0x9c, 0xaa, 0xc3, 0x04 } }
 
 class nsIDOMFontFaceList;
 
@@ -55,17 +57,18 @@ public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IRANGE_IID)
 
   nsIRange()
     : mRoot(nsnull),
       mStartOffset(0),
       mEndOffset(0),
       mIsPositioned(false),
       mIsDetached(false),
-      mMaySpanAnonymousSubtrees(false)
+      mMaySpanAnonymousSubtrees(false),
+      mInSelection(false)
   {
   }
 
   nsINode* GetRoot() const
   {
     return mRoot;
   }
 
@@ -105,16 +108,43 @@ public:
            mStartOffset == mEndOffset;
   }
 
   void SetMaySpanAnonymousSubtrees(bool aMaySpanAnonymousSubtrees)
   {
     mMaySpanAnonymousSubtrees = aMaySpanAnonymousSubtrees;
   }
 
+  /**
+   * Return true iff this range is part of at least one Selection object
+   * and isn't detached.
+   */
+  bool IsInSelection() const
+  {
+    return mInSelection;
+  }
+
+  /**
+   * Called when the range is added/removed from a Selection.
+   */
+  void SetInSelection(bool aInSelection)
+  {
+    if (mInSelection == aInSelection || mIsDetached) {
+      return;
+    }
+    mInSelection = aInSelection;
+    nsINode* commonAncestor = GetCommonAncestor();
+    NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
+    if (mInSelection) {
+      RegisterCommonAncestor(commonAncestor);
+    } else {
+      UnregisterCommonAncestor(commonAncestor);
+    }
+  }
+
   virtual nsINode* GetCommonAncestor() const = 0;
 
   virtual void Reset() = 0;
 
   // XXXbz we could make these non-virtual if a bunch of nsRange stuff
   // became nsIRange stuff... and if no one outside layout needs them.
   virtual nsresult SetStart(nsINode* aParent, PRInt32 aOffset) = 0;
   virtual nsresult SetEnd(nsINode* aParent, PRInt32 aOffset) = 0;
@@ -123,23 +153,29 @@ public:
   // Work around hiding warnings
   NS_IMETHOD SetStart(nsIDOMNode* aParent, PRInt32 aOffset) = 0;
   NS_IMETHOD SetEnd(nsIDOMNode* aParent, PRInt32 aOffset) = 0;
   NS_IMETHOD CloneRange(nsIDOMRange** aNewRange) = 0;
 
   // To support the font inspector API
   NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult) = 0;
 
+  typedef nsTHashtable<nsPtrHashKey<nsIRange> > RangeHashTable;
 protected:
+  void RegisterCommonAncestor(nsINode* aNode);
+  void UnregisterCommonAncestor(nsINode* aNode);
+  nsINode* IsValidBoundary(nsINode* aNode);
+
   nsCOMPtr<nsINode> mRoot;
   nsCOMPtr<nsINode> mStartParent;
   nsCOMPtr<nsINode> mEndParent;
   PRInt32 mStartOffset;
   PRInt32 mEndOffset;
 
   bool mIsPositioned;
   bool mIsDetached;
   bool mMaySpanAnonymousSubtrees;
+  bool mInSelection;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIRange, NS_IRANGE_IID)
 
 #endif /* nsIRange_h___ */
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -58,21 +58,18 @@
 // non-whitespace, we may need to create a frame for it. This bit must
 // not be set on nodes that already have a frame.
 #define NS_CREATE_FRAME_IF_NON_WHITESPACE (1 << NODE_TYPE_SPECIFIC_BITS_OFFSET)
 
 // This bit is set to indicate that if the text node changes to
 // whitespace, we may need to reframe it (or its ancestors).
 #define NS_REFRAME_IF_WHITESPACE (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 1))
 
-// This bit is set to indicate that the text may be part of a selection.
-#define NS_TEXT_IN_SELECTION (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 2))
-
 // Make sure we have enough space for those bits
-PR_STATIC_ASSERT(NODE_TYPE_SPECIFIC_BITS_OFFSET + 2 < 32);
+PR_STATIC_ASSERT(NODE_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
 
 class nsIDOMAttr;
 class nsIDOMEventListener;
 class nsIDOMNodeList;
 class nsIFrame;
 class nsIDOMText;
 class nsINodeInfo;
 class nsURI;
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -86,16 +86,19 @@
 #include "nsMutationEvent.h"
 #include "nsNodeUtils.h"
 #include "nsDocument.h"
 #ifdef MOZ_XUL
 #include "nsXULElement.h"
 #endif /* MOZ_XUL */
 #include "nsFrameManager.h"
 #include "nsFrameSelection.h"
+#ifdef DEBUG
+#include "nsIRange.h"
+#endif
 
 #include "nsBindingManager.h"
 #include "nsXBLBinding.h"
 #include "nsIXBLService.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIBoxObject.h"
 #include "nsClientRect.h"
 #include "nsSVGUtils.h"
@@ -4928,16 +4931,21 @@ nsGenericElement::List(FILE* out, PRInt3
   fputs(NS_LossyConvertUTF16toASCII(mNodeInfo->QualifiedName()).get(), out);
 
   fprintf(out, "@%p", (void *)this);
 
   ListAttributes(out);
 
   fprintf(out, " state=[%llx]", State().GetInternalValue());
   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
+  if (IsCommonAncestorForRangeInSelection()) {
+    nsIRange::RangeHashTable* ranges =
+      static_cast<nsIRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
+    fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
+  }
   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   fprintf(out, " refcount=%d<", mRefCnt.get());
 
   nsIContent* child = GetFirstChild();
   if (child) {
     fputs("\n", out);
     
     for (; child; child = child->GetNextSibling()) {
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -831,16 +831,17 @@ GK_ATOM(properties, "properties")
 GK_ATOM(property, "property")
 GK_ATOM(pubdate, "pubdate")
 GK_ATOM(q, "q")
 GK_ATOM(query, "query")
 GK_ATOM(queryset, "queryset")
 GK_ATOM(querytype, "querytype")
 GK_ATOM(radio, "radio")
 GK_ATOM(radiogroup, "radiogroup")
+GK_ATOM(range, "range")
 GK_ATOM(readonly, "readonly")
 GK_ATOM(rect, "rect")
 GK_ATOM(rectangle, "rectangle")
 GK_ATOM(ref, "ref")
 GK_ATOM(refresh, "refresh")
 GK_ATOM(rel, "rel")
 GK_ATOM(rem, "rem")
 GK_ATOM(removeelement, "removeelement")
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -15,16 +15,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of 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
@@ -151,16 +152,79 @@ nsRange::CompareNodeToRange(nsINode* aNo
   *outNodeAfter = nsContentUtils::ComparePoints(rangeEndParent,
                                                 rangeEndOffset,
                                                 parent, nodeEnd,
                                                 &disconnected) < 0;
   NS_ENSURE_TRUE(!disconnected, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
   return NS_OK;
 }
 
+struct FindSelectedRangeData
+{
+  nsINode*  mNode;
+  nsIRange* mResult;
+  PRUint32  mStartOffset;
+  PRUint32  mEndOffset;
+};
+
+static PLDHashOperator
+FindSelectedRange(nsPtrHashKey<nsIRange>* aEntry, void* userArg)
+{
+  nsIRange* range = aEntry->GetKey();
+  if (range->IsInSelection() && !range->Collapsed()) {
+    FindSelectedRangeData* data = static_cast<FindSelectedRangeData*>(userArg);
+    PRInt32 cmp = nsContentUtils::ComparePoints(data->mNode, data->mEndOffset,
+                                                range->GetStartParent(),
+                                                range->StartOffset());
+    if (cmp == 1) {
+      cmp = nsContentUtils::ComparePoints(data->mNode, data->mStartOffset,
+                                          range->GetEndParent(),
+                                          range->EndOffset());
+      if (cmp == -1) {
+        data->mResult = range;
+        return PL_DHASH_STOP;
+      }
+    }
+  }
+  return PL_DHASH_NEXT;
+}
+
+static nsINode*
+GetNextRangeCommonAncestor(nsINode* aNode)
+{
+  while (aNode && !aNode->IsCommonAncestorForRangeInSelection()) {
+    if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
+      return nsnull;
+    }
+    aNode = aNode->GetNodeParent();
+  }
+  return aNode;
+}
+
+/* static */ bool
+nsRange::IsNodeSelected(nsINode* aNode, PRUint32 aStartOffset,
+                        PRUint32 aEndOffset)
+{
+  NS_PRECONDITION(aNode, "bad arg");
+
+  FindSelectedRangeData data = { aNode, nsnull, aStartOffset, aEndOffset };
+  nsINode* n = GetNextRangeCommonAncestor(aNode);
+  NS_ASSERTION(n || !aNode->IsSelectionDescendant(),
+               "orphan selection descendant");
+  for (; n; n = GetNextRangeCommonAncestor(n->GetNodeParent())) {
+    RangeHashTable* ranges =
+      static_cast<RangeHashTable*>(n->GetProperty(nsGkAtoms::range));
+    ranges->EnumerateEntries(FindSelectedRange, &data);
+    if (data.mResult) {
+      return true;
+    }
+  }
+  return false;
+}
+
 /******************************************************
  * non members
  ******************************************************/
 
 nsresult
 NS_NewRangeUtils(nsIRangeUtils** aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
@@ -220,18 +284,20 @@ NS_NewRange(nsIDOMRange** aResult)
 }
 
 /******************************************************
  * constructor/destructor
  ******************************************************/
 
 nsRange::~nsRange() 
 {
+  NS_ASSERTION(!IsInSelection(), "deleting nsRange that is in use");
+
+  // we want the side effects (releases and list removals)
   DoSetRange(nsnull, 0, nsnull, 0, nsnull);
-  // we want the side effects (releases and list removals)
 } 
 
 /******************************************************
  * nsISupports
  ******************************************************/
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsRange)
 
@@ -255,16 +321,104 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStartParent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEndParent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+static void
+RangeHashTableDtor(void* aObject, nsIAtom* aPropertyName, void* aPropertyValue,
+                   void* aData)
+{
+  nsIRange::RangeHashTable* ranges =
+    static_cast<nsIRange::RangeHashTable*>(aPropertyValue);
+  delete ranges;
+}
+
+static void MarkDescendants(nsINode* aNode)
+{
+  // Set NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
+  // descendants unless aNode is already marked as a range common ancestor
+  // or a descendant of one, in which case all of our descendants have the
+  // bit set already.
+  if (!aNode->IsSelectionDescendant()) {
+    // don't set the Descendant bit on |aNode| itself
+    nsINode* node = aNode->GetNextNode(aNode);
+    while (node) {
+      node->SetDescendantOfCommonAncestorForRangeInSelection();
+      if (!node->IsCommonAncestorForRangeInSelection()) {
+        node = node->GetNextNode(aNode);
+      } else {
+        // optimize: skip this sub-tree since it's marked already.
+        node = node->GetNextNonChildNode(aNode);
+      }
+    }
+  }
+}
+
+static void UnmarkDescendants(nsINode* aNode)
+{
+  // Unset NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
+  // descendants unless aNode is a descendant of another range common ancestor.
+  // Also, exclude descendants of range common ancestors (but not the common
+  // ancestor itself).
+  if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
+    // we know |aNode| doesn't have any bit set
+    nsINode* node = aNode->GetNextNode(aNode);
+    while (node) {
+      node->ClearDescendantOfCommonAncestorForRangeInSelection();
+      if (!node->IsCommonAncestorForRangeInSelection()) {
+        node = node->GetNextNode(aNode);
+      } else {
+        // We found an ancestor of an overlapping range, skip its descendants.
+        node = node->GetNextNonChildNode(aNode);
+      }
+    }
+  }
+}
+
+void
+nsIRange::RegisterCommonAncestor(nsINode* aNode)
+{
+  NS_PRECONDITION(aNode, "bad arg");
+  NS_ASSERTION(IsInSelection(), "registering range not in selection");
+
+  MarkDescendants(aNode);
+
+  RangeHashTable* ranges =
+    static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
+  if (!ranges) {
+    ranges = new RangeHashTable;
+    ranges->Init();
+    aNode->SetProperty(nsGkAtoms::range, ranges, RangeHashTableDtor);
+  }
+  ranges->PutEntry(this);
+  aNode->SetCommonAncestorForRangeInSelection();
+}
+
+void
+nsIRange::UnregisterCommonAncestor(nsINode* aNode)
+{
+  NS_PRECONDITION(aNode, "bad arg");
+  NS_ASSERTION(aNode->IsCommonAncestorForRangeInSelection(), "wrong node");
+  RangeHashTable* ranges =
+    static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
+  NS_ASSERTION(ranges->GetEntry(this), "unknown range");
+
+  if (ranges->Count() == 1) {
+    aNode->ClearCommonAncestorForRangeInSelection();
+    aNode->DeleteProperty(nsGkAtoms::range);
+    UnmarkDescendants(aNode);
+  } else {
+    ranges->RemoveEntry(this);
+  }
+}
+
 /******************************************************
  * nsIMutationObserver implementation
  ******************************************************/
 
 void
 nsRange::CharacterDataChanged(nsIDocument* aDocument,
                               nsIContent* aContent,
                               CharacterDataChangeInfo* aInfo)
@@ -288,16 +442,25 @@ nsRange::CharacterDataChanged(nsIDocumen
                    "only a split can start before the end");
       NS_ASSERTION(static_cast<PRUint32>(mStartOffset) <= aInfo->mChangeEnd + 1,
                    "mStartOffset is beyond the end of this node");
       newStartOffset = static_cast<PRUint32>(mStartOffset) - aInfo->mChangeStart;
       newStartNode = aInfo->mDetails->mNextSibling;
       if (NS_UNLIKELY(aContent == mRoot)) {
         newRoot = IsValidBoundary(newStartNode);
       }
+
+      bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
+      if (isCommonAncestor) {
+        UnregisterCommonAncestor(mStartParent);
+        RegisterCommonAncestor(newStartNode);
+      }
+      if (mStartParent->IsDescendantOfCommonAncestorForRangeInSelection()) {
+        newStartNode->SetDescendantOfCommonAncestorForRangeInSelection();
+      }
     } else {
       // If boundary is inside changed text, position it before change
       // else adjust start offset for the change in length.
       mStartOffset = static_cast<PRUint32>(mStartOffset) <= aInfo->mChangeEnd ?
         aInfo->mChangeStart :
         mStartOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
           aInfo->mReplaceLength;
     }
@@ -312,16 +475,26 @@ nsRange::CharacterDataChanged(nsIDocumen
       // splitText(), aInfo->mDetails->mNextSibling is the new text node
       NS_ASSERTION(aInfo->mDetails->mType ==
                    CharacterDataChangeInfo::Details::eSplit,
                    "only a split can start before the end");
       NS_ASSERTION(static_cast<PRUint32>(mEndOffset) <= aInfo->mChangeEnd + 1,
                    "mEndOffset is beyond the end of this node");
       newEndOffset = static_cast<PRUint32>(mEndOffset) - aInfo->mChangeStart;
       newEndNode = aInfo->mDetails->mNextSibling;
+
+      bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
+      if (isCommonAncestor && !newStartNode) {
+        // The split occurs inside the range.
+        UnregisterCommonAncestor(mStartParent);
+        RegisterCommonAncestor(mStartParent->GetParent());
+        newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
+      } else if (mEndParent->IsDescendantOfCommonAncestorForRangeInSelection()) {
+        newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
+      }
     } else {
       mEndOffset = static_cast<PRUint32>(mEndOffset) <= aInfo->mChangeEnd ?
         aInfo->mChangeStart :
         mEndOffset + aInfo->mChangeStart - aInfo->mChangeEnd +
           aInfo->mReplaceLength;
     }
   }
 
@@ -350,21 +523,39 @@ nsRange::CharacterDataChanged(nsIDocumen
       newStartNode = mStartParent;
       newStartOffset = mStartOffset;
     }
     if (!newEndNode) {
       newEndNode = mEndParent;
       newEndOffset = mEndOffset;
     }
     DoSetRange(newStartNode, newStartOffset, newEndNode, newEndOffset,
-               newRoot ? newRoot : mRoot.get()
-#ifdef DEBUG
-               , !newEndNode->GetParent() || !newStartNode->GetParent()
-#endif
-               );
+               newRoot ? newRoot : mRoot.get(),
+               !newEndNode->GetParent() || !newStartNode->GetParent());
+  }
+}
+
+void
+nsRange::ContentAppended(nsIDocument* aDocument,
+                         nsIContent*  aContainer,
+                         nsIContent*  aFirstNewContent,
+                         PRInt32      aNewIndexInContainer)
+{
+  NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
+
+  nsINode* container = NODE_FROM(aContainer, aDocument);
+  if (container->IsSelectionDescendant() && IsInSelection()) {
+    nsINode* child = aFirstNewContent;
+    while (child) {
+      if (!child->IsDescendantOfCommonAncestorForRangeInSelection()) {
+        MarkDescendants(child);
+        child->SetDescendantOfCommonAncestorForRangeInSelection();
+      }
+      child = child->GetNextSibling();
+    }
   }
 }
 
 void
 nsRange::ContentInserted(nsIDocument* aDocument,
                          nsIContent* aContainer,
                          nsIContent* aChild,
                          PRInt32 aIndexInContainer)
@@ -375,50 +566,68 @@ nsRange::ContentInserted(nsIDocument* aD
 
   // Adjust position if a sibling was inserted.
   if (container == mStartParent && aIndexInContainer < mStartOffset) {
     ++mStartOffset;
   }
   if (container == mEndParent && aIndexInContainer < mEndOffset) {
     ++mEndOffset;
   }
+  if (container->IsSelectionDescendant() &&
+      !aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
+    MarkDescendants(aChild);
+    aChild->SetDescendantOfCommonAncestorForRangeInSelection();
+  }
 }
 
 void
 nsRange::ContentRemoved(nsIDocument* aDocument,
                         nsIContent* aContainer,
                         nsIContent* aChild,
                         PRInt32 aIndexInContainer,
                         nsIContent* aPreviousSibling)
 {
   NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
 
   nsINode* container = NODE_FROM(aContainer, aDocument);
+  bool gravitateStart = false;
+  bool gravitateEnd = false;
 
   // Adjust position if a sibling was removed...
   if (container == mStartParent) {
     if (aIndexInContainer < mStartOffset) {
       --mStartOffset;
     }
   }
   // ...or gravitate if an ancestor was removed.
   else if (nsContentUtils::ContentIsDescendantOf(mStartParent, aChild)) {
-    mStartParent = container;
-    mStartOffset = aIndexInContainer;
+    gravitateStart = true;
   }
 
   // Do same thing for end boundry.
   if (container == mEndParent) {
     if (aIndexInContainer < mEndOffset) {
       --mEndOffset;
     }
   }
   else if (nsContentUtils::ContentIsDescendantOf(mEndParent, aChild)) {
-    mEndParent = container;
-    mEndOffset = aIndexInContainer;
+    gravitateEnd = true;
+  }
+
+  if (gravitateStart || gravitateEnd) {
+    DoSetRange(gravitateStart ? container : mStartParent.get(),
+               gravitateStart ? aIndexInContainer : mStartOffset,
+               gravitateEnd ? container : mEndParent.get(),
+               gravitateEnd ? aIndexInContainer : mEndOffset,
+               mRoot);
+  }
+  if (container->IsSelectionDescendant() &&
+      aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
+    aChild->ClearDescendantOfCommonAncestorForRangeInSelection();
+    UnmarkDescendants(aChild);
   }
 }
 
 void
 nsRange::ParentChainChanged(nsIContent *aContent)
 {
   NS_ASSERTION(mRoot == aContent, "Wrong ParentChainChanged notification?");
   nsINode* newRoot = IsValidBoundary(mStartParent);
@@ -502,21 +711,17 @@ static PRUint32 GetNodeLength(nsINode *a
 // It's important that all setting of the range start/end points 
 // go through this function, which will do all the right voodoo
 // for content notification of range ownership.  
 // Calling DoSetRange with either parent argument null will collapse
 // the range to have both endpoints point to the other node
 void
 nsRange::DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
                     nsINode* aEndN, PRInt32 aEndOffset,
-                    nsINode* aRoot
-#ifdef DEBUG
-                    , bool aNotInsertedYet
-#endif
-                    )
+                    nsINode* aRoot, bool aNotInsertedYet)
 {
   NS_PRECONDITION((aStartN && aEndN && aRoot) ||
                   (!aStartN && !aEndN && !aRoot),
                   "Set all or none");
   NS_PRECONDITION(!aRoot || aNotInsertedYet ||
                   (nsContentUtils::ContentIsDescendantOf(aStartN, aRoot) &&
                    nsContentUtils::ContentIsDescendantOf(aEndN, aRoot) &&
                    aRoot == IsValidBoundary(aStartN) &&
@@ -540,22 +745,39 @@ nsRange::DoSetRange(nsINode* aStartN, PR
   if (mRoot != aRoot) {
     if (mRoot) {
       mRoot->RemoveMutationObserver(this);
     }
     if (aRoot) {
       aRoot->AddMutationObserver(this);
     }
   }
- 
+  bool checkCommonAncestor = (mStartParent != aStartN || mEndParent != aEndN) &&
+                             IsInSelection() && !aNotInsertedYet;
+  nsINode* oldCommonAncestor = checkCommonAncestor ? GetCommonAncestor() : nsnull;
   mStartParent = aStartN;
   mStartOffset = aStartOffset;
   mEndParent = aEndN;
   mEndOffset = aEndOffset;
   mIsPositioned = !!mStartParent;
+  if (checkCommonAncestor) {
+    nsINode* newCommonAncestor = GetCommonAncestor();
+    if (newCommonAncestor != oldCommonAncestor) {
+      if (oldCommonAncestor) {
+        UnregisterCommonAncestor(oldCommonAncestor);
+      }
+      if (newCommonAncestor) {
+        RegisterCommonAncestor(newCommonAncestor);
+      } else {
+        NS_ASSERTION(mIsDetached, "unexpected disconnected nodes");
+        mInSelection = false;
+      }
+    }
+  }
+
   // This needs to be the last thing this function does.  See comment
   // in ParentChainChanged.
   mRoot = aRoot;
 }
 
 static PRInt32
 IndexOf(nsIDOMNode* aChildNode)
 {
@@ -659,17 +881,17 @@ nsRange::GetCommonAncestorContainer(nsID
   nsINode* container = nsContentUtils::GetCommonAncestor(mStartParent, mEndParent);
   if (container) {
     return CallQueryInterface(container, aCommonParent);
   }
 
   return NS_ERROR_NOT_INITIALIZED;
 }
 
-nsINode* nsRange::IsValidBoundary(nsINode* aNode)
+nsINode* nsIRange::IsValidBoundary(nsINode* aNode)
 {
   if (!aNode) {
     return nsnull;
   }
 
   if (aNode->IsNodeOfType(nsINode::eCONTENT)) {
     nsIContent* content = static_cast<nsIContent*>(aNode);
     if (content->Tag() == nsGkAtoms::documentTypeNodeName) {
--- a/content/base/src/nsRange.h
+++ b/content/base/src/nsRange.h
@@ -72,19 +72,17 @@ public:
 
 // -------------------------------------------------------------------------------
 
 class nsRange : public nsIRange,
                 public nsIDOMNSRange,
                 public nsStubMutationObserver
 {
 public:
-  nsRange()
-  {
-  }
+  nsRange(){}
   virtual ~nsRange();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsRange, nsIRange)
 
   // nsIDOMRange interface
   NS_DECL_NSIDOMRANGE
 
@@ -111,24 +109,23 @@ public:
 
   NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult);
 
   // nsIMutationObserver methods
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
   NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
+  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
 
 private:
   // no copy's or assigns
   nsRange(const nsRange&);
   nsRange& operator=(const nsRange&);
 
-  nsINode* IsValidBoundary(nsINode* aNode);
- 
   /**
    * Cut or delete the range's contents.
    *
    * @param aFragment nsIDOMDocumentFragment containing the nodes.
    *                  May be null to indicate the caller doesn't want a fragment.
    */
   nsresult CutContents(nsIDOMDocumentFragment** frag);
 
@@ -152,26 +149,27 @@ public:
  *****************************************************************************/
   static nsresult CompareNodeToRange(nsINode* aNode, nsIDOMRange* aRange,
                                      bool *outNodeBefore,
                                      bool *outNodeAfter);
   static nsresult CompareNodeToRange(nsINode* aNode, nsIRange* aRange,
                                      bool *outNodeBefore,
                                      bool *outNodeAfter);
 
+  static bool IsNodeSelected(nsINode* aNode, PRUint32 aStartOffset,
+                             PRUint32 aEndOffset);
+
 protected:
+  // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
+  // and suppress re-registering a range common ancestor node since
+  // the new text node of a splitText hasn't been inserted yet.
+  // CharacterDataChanged does the re-registering when needed.
   void DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
                   nsINode* aEndN, PRInt32 aEndOffset,
-                  nsINode* aRoot
-#ifdef DEBUG
-                  // CharacterDataChanged use this to disable an assertion since
-                  // the new text node of a splitText hasn't been inserted yet.
-                  , bool aNotInsertedYet = false
-#endif
-                  );
+                  nsINode* aRoot, bool aNotInsertedYet = false);
 };
 
 // Make a new nsIDOMRange object
 nsresult NS_NewRange(nsIDOMRange** aInstancePtrResult);
 
 // Make a new nsIRangeUtils object
 nsresult NS_NewRangeUtils(nsIRangeUtils** aInstancePtrResult);
 
--- a/content/base/src/nsTextNode.cpp
+++ b/content/base/src/nsTextNode.cpp
@@ -41,16 +41,19 @@
 
 #include "nsTextNode.h"
 #include "nsContentUtils.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIAttribute.h"
 #include "nsIDocument.h"
 #include "nsThreadUtils.h"
+#ifdef DEBUG
+#include "nsIRange.h"
+#endif
 
 using namespace mozilla::dom;
 
 /**
  * class used to implement attr() generated content
  */
 class nsAttributeTextNode : public nsTextNode,
                             public nsStubMutationObserver
@@ -219,16 +222,22 @@ nsTextNode::AppendTextForNormalize(const
 void
 nsTextNode::List(FILE* out, PRInt32 aIndent) const
 {
   PRInt32 index;
   for (index = aIndent; --index >= 0; ) fputs("  ", out);
 
   fprintf(out, "Text@%p", static_cast<const void*>(this));
   fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
+  if (IsCommonAncestorForRangeInSelection()) {
+    typedef nsTHashtable<nsPtrHashKey<nsIRange> > RangeHashTable;
+    RangeHashTable* ranges =
+      static_cast<RangeHashTable*>(GetProperty(nsGkAtoms::range));
+    fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
+  }
   fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
   fprintf(out, " refcount=%d<", mRefCnt.get());
 
   nsAutoString tmp;
   ToCString(tmp, 0, mText.GetLength());
   fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
 
   fputs(">\n", out);
--- a/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellWordUtil.cpp
@@ -964,17 +964,16 @@ WordSplitState::FindSpecialWord()
   // plug in new protocols. We also don't want to waste time here checking
   // against a lot of obscure protocols.
   if (firstColon > mDOMWordOffset) {
     nsString protocol(Substring(mDOMWordText, mDOMWordOffset,
                       firstColon - mDOMWordOffset));
     if (protocol.EqualsIgnoreCase("http") ||
         protocol.EqualsIgnoreCase("https") ||
         protocol.EqualsIgnoreCase("news") ||
-        protocol.EqualsIgnoreCase("ftp") ||
         protocol.EqualsIgnoreCase("file") ||
         protocol.EqualsIgnoreCase("javascript") ||
         protocol.EqualsIgnoreCase("ftp")) {
       return mDOMWordText.Length() - mDOMWordOffset;
     }
   }
 
   // not anything special
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2847,21 +2847,16 @@ MOZ_ARG_DISABLE_BOOL(methodjit,
 MOZ_ARG_DISABLE_BOOL(monoic,
 [  --disable-monoic      Disable use of MICs by JIT compiler],
   ENABLE_MONOIC= )
 
 MOZ_ARG_DISABLE_BOOL(polyic,
 [  --disable-polyic      Disable use of PICs by JIT compiler],
   ENABLE_POLYIC= )
 
-MOZ_ARG_ENABLE_BOOL(tracejit,
-[  --enable-tracejit     Deprecated, does nothing],
-  ENABLE_TRACEJIT=,
-  ENABLE_TRACEJIT= )
-
 MOZ_ARG_ENABLE_BOOL(methodjit-spew,
 [  --enable-methodjit-spew      Enable method JIT spew support],
   ENABLE_METHODJIT_SPEW=1,
   ENABLE_METHODJIT_SPEW= )
 
 AC_SUBST(ENABLE_METHODJIT)
 
 if test "$ENABLE_METHODJIT"; then
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -212,18 +212,18 @@ public:
   /**
    * Calling this setter makes us include all out-of-flow descendant
    * frames in the display list, wherever they may be positioned (even
    * outside the dirty rects).
    */
   void SetIncludeAllOutOfFlows() { mIncludeAllOutOfFlows = true; }
   bool GetIncludeAllOutOfFlows() const { return mIncludeAllOutOfFlows; }
   /**
-   * Calling this setter makes us exclude all leaf frames that does
-   * not have the NS_FRAME_SELECTED_CONTENT bit.
+   * Calling this setter makes us exclude all leaf frames that aren't
+   * selected.
    */
   void SetSelectedFramesOnly() { mSelectedFramesOnly = true; }
   bool GetSelectedFramesOnly() { return mSelectedFramesOnly; }
   /**
    * Calling this setter makes us compute accurate visible regions at the cost
    * of performance if regions get very complex.
    */
   void SetAccurateVisibleRegions() { mAccurateVisibleRegions = true; }
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -86,16 +86,17 @@
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSPseudoElements.h"
 #include "nsIHTMLContentSink.h" 
 #include "nsCSSFrameConstructor.h"
 
 #include "nsFrameTraversal.h"
 #include "nsStyleChangeList.h"
 #include "nsIDOMRange.h"
+#include "nsRange.h"
 #include "nsITableLayout.h"    //selection necessity
 #include "nsITableCellLayout.h"//  "
 #include "nsITextControlFrame.h"
 #include "nsINameSpaceManager.h"
 #include "nsIPercentHeightObserver.h"
 #include "nsStyleStructInlines.h"
 
 #ifdef IBMBIDI
@@ -439,18 +440,17 @@ nsFrame::Init(nsIContent*      aContent,
     NS_ADDREF(aContent);
   }
 
   if (aPrevInFlow) {
     // Make sure the general flags bits are the same
     nsFrameState state = aPrevInFlow->GetStateBits();
 
     // Make bits that are currently off (see constructor) the same:
-    mState |= state & (NS_FRAME_SELECTED_CONTENT |
-                       NS_FRAME_INDEPENDENT_SELECTION |
+    mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
                        NS_FRAME_IS_SPECIAL |
                        NS_FRAME_MAY_BE_TRANSFORMED);
   }
   if (mParent) {
     nsFrameState state = mParent->GetStateBits();
 
     // Make bits that are currently off (see constructor) the same:
     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
@@ -563,18 +563,17 @@ nsFrame::DestroyFrom(nsIFrame* aDestruct
          nextSib->Properties().Get(nsIFrame::IBSplitSpecialPrevSibling()),
          "IB sibling chain is inconsistent");
       nextSib->Properties().Delete(nsIFrame::IBSplitSpecialPrevSibling());
     }
   }
 
   shell->NotifyDestroyingFrame(this);
 
-  if ((mState & NS_FRAME_EXTERNAL_REFERENCE) ||
-      (mState & NS_FRAME_SELECTED_CONTENT)) {
+  if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
     shell->ClearFrameRefs(this);
   }
 
   if (view) {
     // Break association between view and frame
     view->SetFrame(nsnull);
 
     // Destroy the view
@@ -1199,20 +1198,17 @@ void nsDisplaySelectionOverlay::Paint(ns
 * Refreshes each content's frame
 *********************************************************/
 
 nsresult
 nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder*   aBuilder,
                                  nsDisplayList*          aList,
                                  PRUint16                aContentType)
 {
-//check frame selection state
-  if ((GetStateBits() & NS_FRAME_SELECTED_CONTENT) != NS_FRAME_SELECTED_CONTENT)
-    return NS_OK;
-  if (!IsVisibleForPainting(aBuilder))
+  if (!IsSelected() || !IsVisibleForPainting(aBuilder))
     return NS_OK;
     
   nsPresContext* presContext = PresContext();
   nsIPresShell *shell = presContext->PresShell();
   if (!shell)
     return NS_OK;
 
   PRInt16 displaySelection = shell->GetSelectionFlags();
@@ -1917,17 +1913,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
   }
 
   // Mark the display list items for absolutely positioned children
   child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
 
   if (childType != nsGkAtoms::placeholderFrame &&
       aBuilder->GetSelectedFramesOnly() &&
       child->IsLeaf() &&
-      !(child->GetStateBits() & NS_FRAME_SELECTED_CONTENT)) {
+      !aChild->IsSelected()) {
     return NS_OK;
   }
 
   if (aBuilder->GetIncludeAllOutOfFlows() &&
       (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
     dirty = child->GetVisualOverflowRect();
   } else if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
     // No need to descend into child to catch placeholders for visible
@@ -2488,19 +2484,17 @@ nsFrame::HandlePress(nsPresContext* aPre
   fc->SetDelayedCaretData(0);
 
   // Check if any part of this frame is selected, and if the
   // user clicked inside the selected region. If so, we delay
   // starting a new selection since the user may be trying to
   // drag the selected region to some other app.
 
   SelectionDetails *details = 0;
-  bool isSelected = ((GetStateBits() & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT);
-
-  if (isSelected)
+  if (GetContent()->IsSelectionDescendant())
   {
     bool inSelection = false;
     details = frameselection->LookUpSelection(offsets.content, 0,
         offsets.EndOffset(), false);
 
     //
     // If there are any details, check to see if the user clicked
     // within any selected region of the frame.
@@ -5194,18 +5188,19 @@ nsIFrame::IsVisibleOrCollapsedForPaintin
     return false;
   nsISelection* sel = aBuilder->GetBoundingSelection();
   return !sel || IsVisibleInSelection(sel);
 }
 
 bool
 nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
 {
-  if ((mState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT)
-    return true;
+  if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
+    return false;
+  }
   
   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
   bool vis;
   nsresult rv = aSelection->ContainsNode(node, true, &vis);
   return NS_FAILED(rv) || vis;
 }
 
 /* virtual */ bool
@@ -5251,21 +5246,21 @@ nsIFrame::GetFrameSelection()
 {
   nsFrameSelection* fs =
     const_cast<nsFrameSelection*>(GetConstFrameSelection());
   NS_IF_ADDREF(fs);
   return fs;
 }
 
 const nsFrameSelection*
-nsIFrame::GetConstFrameSelection()
-{
-  nsIFrame *frame = this;
+nsIFrame::GetConstFrameSelection() const
+{
+  nsIFrame* frame = const_cast<nsIFrame*>(this);
   while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
-    nsITextControlFrame *tcf = do_QueryFrame(frame);
+    nsITextControlFrame* tcf = do_QueryFrame(frame);
     if (tcf) {
       return tcf->GetOwnedFrameSelection();
     }
     frame = frame->GetParent();
   }
 
   return PresContext()->PresShell()->ConstFrameSelection();
 }
@@ -5333,49 +5328,23 @@ nsFrame::DumpBaseRegressionData(nsPresCo
     }
     aIndent--;
     IndentBy(out, aIndent);
     fprintf(out, "</child-list>\n");
   }
 }
 #endif
 
-void
-nsIFrame::SetSelected(bool aSelected, SelectionType aType)
-{
-  NS_ASSERTION(!GetPrevContinuation(),
-               "Should only be called on first in flow");
-  if (aType != nsISelectionController::SELECTION_NORMAL)
-    return;
-
-  // check whether style allows selection
-  bool selectable;
-  IsSelectable(&selectable, nsnull);
-  if (!selectable)
-    return;
-
-  for (nsIFrame* f = this; f; f = f->GetNextContinuation()) {
-    if (aSelected) {
-      AddStateBits(NS_FRAME_SELECTED_CONTENT);
-    } else {
-      RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
-    }
-
-    // Repaint this frame subtree's entire area
-    InvalidateFrameSubtree();
-  }
-}
-
-NS_IMETHODIMP
-nsFrame::GetSelected(bool *aSelected) const
-{
-  if (!aSelected )
-    return NS_ERROR_NULL_POINTER;
-  *aSelected = !!(mState & NS_FRAME_SELECTED_CONTENT);
-  return NS_OK;
+bool
+nsIFrame::IsFrameSelected() const
+{
+  NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
+               "use the public IsSelected() instead");
+  return nsRange::IsNodeSelected(GetContent(), 0,
+                                 GetContent()->GetChildCount());
 }
 
 NS_IMETHODIMP
 nsFrame::GetPointFromOffset(PRInt32 inOffset, nsPoint* outPoint)
 {
   NS_PRECONDITION(outPoint != nsnull, "Null parameter");
   nsRect contentRect = GetContentRect() - GetPosition();
   nsPoint pt = contentRect.TopLeft();
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -227,17 +227,16 @@ public:
   NS_IMETHOD  SetNextContinuation(nsIFrame*);
   virtual nsIFrame* GetPrevInFlowVirtual() const;
   NS_IMETHOD  SetPrevInFlow(nsIFrame*);
   virtual nsIFrame* GetNextInFlowVirtual() const;
   NS_IMETHOD  SetNextInFlow(nsIFrame*);
   NS_IMETHOD  GetOffsetFromView(nsPoint& aOffset, nsIView** aView) const;
   virtual nsIAtom* GetType() const;
 
-  NS_IMETHOD  GetSelected(bool *aSelected) const;
   NS_IMETHOD  IsSelectable(bool* aIsSelectable, PRUint8* aSelectStyle) const;
 
   NS_IMETHOD  GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon);
 
   virtual bool PeekOffsetNoAmount(bool aForward, PRInt32* aOffset);
   virtual bool PeekOffsetCharacter(bool aForward, PRInt32* aOffset,
                                      bool aRespectClusters = true);
   virtual bool PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -591,27 +591,26 @@ public:
    * Dragging or extending selection will never allow for a subset
    * (or the whole) of the maintained selection to become unselected.
    * Primary use: double click selecting then dragging on second click
    * @param aAmount the initial amount of text selected (word, line or paragraph).
    *                For "line", use eSelectBeginLine.
    */
   nsresult MaintainSelection(nsSelectionAmount aAmount = eSelectNoAmount);
 
-
   nsFrameSelection();
 
   void StartBatchChanges();
   void EndBatchChanges();
   /*unsafe*/
   nsresult DeleteFromDocument();
 
   nsIPresShell *GetShell()const  { return mShell; }
 
-  void DisconnectFromPresShell() { StopAutoScrollTimer(); mShell = nsnull; }
+  void DisconnectFromPresShell();
 private:
   nsresult TakeFocus(nsIContent *aNewFocus,
                      PRUint32 aContentOffset,
                      PRUint32 aContentEndOffset,
                      HINT aHint,
                      bool aContinueSelection,
                      bool aMultipleSelection);
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1469,19 +1469,16 @@ nsGfxScrollFrameInner::nsGfxScrollFrameI
   , mHorizontalOverflow(false)
   , mVerticalOverflow(false)
   , mPostedReflowCallback(false)
   , mMayHaveDirtyFixedChildren(false)
   , mUpdateScrollbarAttributes(false)
   , mCollapsedResizer(false)
   , mShouldBuildLayer(false)
 {
-  // lookup if we're allowed to overlap the content from the look&feel object
-  mScrollbarsCanOverlapContent =
-    LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollbarsCanOverlapContent) != 0;
   mScrollingActive = IsAlwaysActive();
 }
 
 nsGfxScrollFrameInner::~nsGfxScrollFrameInner()
 {
   if (mActivityExpirationState.IsTracked()) {
     gScrollFrameActivityTracker->RemoveObject(this);
   }
@@ -1874,42 +1871,45 @@ AppendToTop(nsDisplayListBuilder* aBuild
   if (aOwnLayer) {
     aDest->AppendNewToTop(
         new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource));
   } else {
     aDest->AppendToTop(aSource);
   }  
 }
 
-nsresult
-nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder*          aBuilder,
-                                           const nsRect&                  aDirtyRect,
-                                           const nsDisplayListSet&        aLists,
-                                           const nsDisplayListCollection& aDest,
-                                           bool&                        aCreateLayer)
+void
+nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
+                                           const nsRect&           aDirtyRect,
+                                           const nsDisplayListSet& aLists,
+                                           bool&                   aCreateLayer,
+                                           bool                    aPositioned)
 {
-  nsresult rv = NS_OK;
-  bool hasResizer = HasResizer();
   for (nsIFrame* kid = mOuter->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
-    if (kid != mScrolledFrame) {
-      if (kid == mResizerBox && hasResizer) {
-        // skip the resizer as this will be drawn later on top of the scrolled content
-        continue;
-      }
-      rv = mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aDest,
-                                            nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
-      NS_ENSURE_SUCCESS(rv, rv);
-      // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into the
-      // PositionedDescendants list.
-      ::AppendToTop(aBuilder, aLists.BorderBackground(),
-                    aDest.PositionedDescendants(), kid,
-                    aCreateLayer);
-    }
+    if (kid == mScrolledFrame ||
+        (kid->GetStyleDisplay()->IsPositioned() != aPositioned))
+      continue;
+
+    nsDisplayListCollection partList;
+    mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, partList,
+                                     nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
+
+    // Don't append textarea resizers to the positioned descendants because
+    // we don't want them to float on top of overlapping elements.
+    bool appendToPositioned = aPositioned && !(kid == mResizerBox && !mIsRoot);
+
+    nsDisplayList* dest = appendToPositioned ?
+      aLists.PositionedDescendants() : aLists.BorderBackground();
+
+    // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into
+    // partList.PositionedDescendants().
+    ::AppendToTop(aBuilder, dest,
+                  partList.PositionedDescendants(), kid,
+                  aCreateLayer);
   }
-  return rv;
 }
 
 bool
 nsGfxScrollFrameInner::ShouldBuildLayer() const
 {
   return mShouldBuildLayer;
 }
 
@@ -1979,25 +1979,25 @@ nsGfxScrollFrameInner::BuildDisplayList(
   // they're not scrolled with the rest of the document. But when both
   // scrollbars are visible, the layer's visible rectangle would be the size
   // of the viewport, so most layer implementations would create a layer buffer
   // that's much larger than necessary. Creating independent layers for each
   // scrollbar works around the problem.
   bool createLayersForScrollbars = mIsRoot &&
     mOuter->PresContext()->IsRootContentDocument();
 
-  nsDisplayListCollection scrollParts;
-  if (!mScrollbarsCanOverlapContent) {
-    // Now display the scrollbars and scrollcorner. These parts are drawn
-    // in the border-background layer, on top of our own background and
-    // borders and underneath borders and backgrounds of later elements
-    // in the tree.
-    AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
-                        scrollParts, createLayersForScrollbars);
-  }
+  // Now display the scrollbars and scrollcorner. These parts are drawn
+  // in the border-background layer, on top of our own background and
+  // borders and underneath borders and backgrounds of later elements
+  // in the tree.
+  // Note that this does not apply for overlay scrollbars; those are drawn
+  // in the positioned-elements layer on top of everything else by the call
+  // to AppendScrollPartsTo(..., true) further down.
+  AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
+                      false);
 
   // Overflow clipping can never clip frames outside our subtree, so there
   // is no need to worry about whether we are a moving frame that might clip
   // non-moving frames.
   nsRect dirtyRect;
   // Not all our descendants will be clipped by overflow clipping, but all
   // the ones that aren't clipped will be out of flow frames that have already
   // had dirty rects saved for them by their parent frames calling
@@ -2057,35 +2057,19 @@ nsGfxScrollFrameInner::BuildDisplayList(
   // frame below the viewport. If so, we want it to be clipped. We also want
   // to end up on our BorderBackground list.
   // If we are the viewport scrollframe, then clip all our descendants (to ensure
   // that fixed-pos elements get clipped by us).
   rv = mOuter->OverflowClip(aBuilder, set, aLists, clip, radii,
                             true, mIsRoot);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (mScrollbarsCanOverlapContent) {
-    AppendScrollPartsTo(aBuilder, aDirtyRect, aLists,
-                       scrollParts, createLayersForScrollbars);
-  }
-
-  if (HasResizer()) {
-    rv = mOuter->BuildDisplayListForChild(aBuilder, mResizerBox, aDirtyRect, scrollParts,
-                                          nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
-    NS_ENSURE_SUCCESS(rv, rv);
-    // DISPLAY_CHILD_FORCE_STACKING_CONTEXT puts everything into the
-    // PositionedDescendants list.
-    // The resizer is positioned and has maximum z-index; we put it in
-    // PositionedDescendants() for the root frame to ensure that it appears
-    // above all content, bug 631337.
-    ::AppendToTop(aBuilder,
-                  mIsRoot ? aLists.PositionedDescendants() : aLists.Content(),
-                  scrollParts.PositionedDescendants(), mResizerBox,
-                  createLayersForScrollbars);
-  }
+  // Now display overlay scrollbars and the resizer, if we have one.
+  AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
+                      true);
 
   return NS_OK;
 }
 
 static void HandleScrollPref(nsIScrollable *aScrollable, PRInt32 aOrientation,
                              PRUint8& aValue)
 {
   PRInt32 pref;
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -93,21 +93,21 @@ public:
   void Destroy();
 
   bool ShouldBuildLayer() const;
 
   nsresult BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                             const nsRect&           aDirtyRect,
                             const nsDisplayListSet& aLists);
 
-  nsresult AppendScrollPartsTo(nsDisplayListBuilder*          aBuilder,
-                               const nsRect&                  aDirtyRect,
-                               const nsDisplayListSet&        aLists,
-                               const nsDisplayListCollection& aDest,
-                               bool&                        aCreateLayer);
+  void AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
+                           const nsRect&           aDirtyRect,
+                           const nsDisplayListSet& aLists,
+                           bool&                   aCreateLayer,
+                           bool                    aPositioned);
 
   bool GetBorderRadii(nscoord aRadii[8]) const;
 
   // nsIReflowCallback
   virtual bool ReflowFinished();
   virtual void ReflowCallbackCanceled();
 
   // This gets called when the 'curpos' attribute on one of the scrollbars changes
@@ -319,19 +319,16 @@ public:
   bool mPostedReflowCallback:1;
   bool mMayHaveDirtyFixedChildren:1;
   // If true, need to actually update our scrollbar attributes in the
   // reflow callback.
   bool mUpdateScrollbarAttributes:1;
   // If true, we should be prepared to scroll using this scrollframe
   // by placing descendant content into its own layer(s)
   bool mScrollingActive:1;
-  // If true, scrollbars are stacked on the top of the display list and can
-  // float above the content as a result
-  bool mScrollbarsCanOverlapContent:1;
   // If true, the resizer is collapsed and not displayed
   bool mCollapsedResizer:1;
 
   // If true, the layer should always be active because we always build a layer.
   // Used for asynchronous scrolling.
   bool mShouldBuildLayer:1;
 };
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -194,18 +194,18 @@ typedef PRUint64 nsFrameState;
 // page and b) invisible: no borders, zero height, ignored in margin
 // collapsing, etc. See nsContainerFrame.h
 #define NS_FRAME_IS_OVERFLOW_CONTAINER              NS_FRAME_STATE_BIT(7)
 
 // If this bit is set, then the frame has been moved out of the flow,
 // e.g., it is absolutely positioned or floated
 #define NS_FRAME_OUT_OF_FLOW                        NS_FRAME_STATE_BIT(8)
 
-// If this bit is set, then the frame reflects content that may be selected
-#define NS_FRAME_SELECTED_CONTENT                   NS_FRAME_STATE_BIT(9)
+// This bit is available for re-use.
+//#define NS_FRAME_SELECTED_CONTENT                   NS_FRAME_STATE_BIT(9)
 
 // If this bit is set, then the frame is dirty and needs to be reflowed.
 // This bit is set when the frame is first created.
 // This bit is cleared by DidReflow after the required call to Reflow has
 // finished.
 // Do not set this bit yourself if you plan to pass the frame to
 // nsIPresShell::FrameNeedsReflow.  Pass the right arguments instead.
 #define NS_FRAME_IS_DIRTY                           NS_FRAME_STATE_BIT(10)
@@ -256,16 +256,17 @@ typedef PRUint64 nsFrameState;
 #define NS_FRAME_HAS_CHILD_WITH_VIEW                NS_FRAME_STATE_BIT(18)
 
 // If this bit is set, then reflow may be dispatched from the current
 // frame instead of the root frame.
 #define NS_FRAME_REFLOW_ROOT                        NS_FRAME_STATE_BIT(19)
 
 // Bits 20-31 and 60-63 of the frame state are reserved for implementations.
 #define NS_FRAME_IMPL_RESERVED                      nsFrameState(0xF0000000FFF00000)
+#define NS_FRAME_RESERVED                           ~NS_FRAME_IMPL_RESERVED
 
 // This bit is set on floats whose parent does not contain their
 // placeholder.  This can happen for two reasons:  (1) the float was
 // split, and this piece is the continuation, or (2) the entire float
 // didn't fit on the page.
 #define NS_FRAME_IS_PUSHED_FLOAT                    NS_FRAME_STATE_BIT(32)
 
 // This bit acts as a loop flag for recursive paint server drawing.
@@ -292,19 +293,16 @@ typedef PRUint64 nsFrameState;
 
 // Frame is or is a descendant of something with a fixed height, and
 // has no closer ancestor that is overflow:auto or overflow:scroll.
 #define NS_FRAME_IN_CONSTRAINED_HEIGHT              NS_FRAME_STATE_BIT(39)
 
 // This is only set during painting
 #define NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO    NS_FRAME_STATE_BIT(40)
 
-// Bits 0-19 and bits 32-59 of the frame state are reserved by this API.
-#define NS_FRAME_RESERVED                           ~NS_FRAME_IMPL_RESERVED
-
 // Box layout bits
 #define NS_STATE_IS_HORIZONTAL                      NS_FRAME_STATE_BIT(22)
 #define NS_STATE_IS_DIRECTION_NORMAL                NS_FRAME_STATE_BIT(31)
 
 // Helper macros
 #define NS_SUBTREE_DIRTY(_frame)  \
   (((_frame)->GetStateBits() &      \
     (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0)
@@ -575,16 +573,22 @@ public:
    * content for its content node.
    * If the frame is a placeholder, it also ensures the out-of-flow frame's
    * removal and destruction.
    */
   void Destroy() { DestroyFrom(this); }
 
 protected:
   /**
+   * Return true if the frame is part of a Selection.
+   * Helper method to implement the public IsSelected() API.
+   */
+  virtual bool IsFrameSelected() const;
+
+  /**
    * Implements Destroy(). Do not call this directly except from within a
    * DestroyFrom() implementation.
    *
    * @note This will always be called, so it is not necessary to override
    *       Destroy() in subclasses of nsFrame, just DestroyFrom().
    *
    * @param  aDestructRoot is the root of the subtree being destroyed
    */
@@ -2300,35 +2304,23 @@ public:
   bool ClearOverflowRects();
 
   /**
    * Determine whether borders should not be painted on certain sides of the
    * frame.
    */
   virtual PRIntn GetSkipSides() const { return 0; }
 
-  /** Selection related calls
+  /**
+   * @returns true if this frame is selected.
    */
-  /** 
-   *  Called to set the selection status of the frame.
-   *  
-   *  This must be called on the primary frame, but all continuations
-   *  will be affected the same way.
-   *
-   *  This sets or clears NS_FRAME_SELECTED_CONTENT for each frame in the
-   *  continuation chain, if the frames are currently selectable.
-   *  The frames are unconditionally invalidated, if this selection type
-   *  is supported at all.
-   *  @param aSelected is it selected?
-   *  @param aType the selection type of the selection that you are setting on the frame
-   */
-  virtual void SetSelected(bool          aSelected,
-                           SelectionType aType);
-
-  NS_IMETHOD  GetSelected(bool *aSelected) const = 0;
+  bool IsSelected() const {
+    return (GetContent() && GetContent()->IsSelectionDescendant()) ?
+      IsFrameSelected() : false;
+  }
 
   /**
    *  called to discover where this frame, or a parent frame has user-select style
    *  applied, which affects that way that it is selected.
    *    
    *  @param aIsSelectable out param. Set to true if the frame can be selected
    *                       (i.e. is not affected by user-select: none)
    *  @param aSelectStyle  out param. Returns the type of selection style found
@@ -2347,20 +2339,17 @@ public:
    *  Call to get nsFrameSelection for this frame.
    */
   already_AddRefed<nsFrameSelection> GetFrameSelection();
 
   /**
    * GetConstFrameSelection returns an object which methods are safe to use for
    * example in nsIFrame code.
    */
-  const nsFrameSelection* GetConstFrameSelection();
-
-  /** EndSelection related calls
-   */
+  const nsFrameSelection* GetConstFrameSelection() const;
 
   /**
    *  called to find the previous/next character, word, or line  returns the actual 
    *  nsIFrame and the frame offset.  THIS DOES NOT CHANGE SELECTION STATE
    *  uses frame's begin selection state to start. if no selection on this frame will 
    *  return NS_ERROR_FAILURE
    *  @param aPOS is defined in nsFrameSelection
    */
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -262,17 +262,16 @@ public:
 
   // Note: StartAutoScrollTimer might destroy arbitrary frames etc.
   nsresult     StartAutoScrollTimer(nsIFrame *aFrame,
                                     nsPoint& aPoint,
                                     PRUint32 aDelay);
 
   nsresult     StopAutoScrollTimer();
 
-
 private:
   friend class nsAutoScrollTimer;
 
   // Note: DoAutoScroll might destroy arbitrary frames etc.
   nsresult DoAutoScroll(nsIFrame *aFrame, nsPoint& aPoint);
 
 public:
   SelectionType GetType(){return mType;}
@@ -1697,18 +1696,18 @@ nsFrameSelection::HandleDrag(nsIFrame *a
   if (!newFrame)
     return;
 
   nsIFrame::ContentOffsets offsets =
       newFrame->GetContentOffsetsFromPoint(newPoint);
   if (!offsets.content)
     return;
 
-  if ((newFrame->GetStateBits() & NS_FRAME_SELECTED_CONTENT) &&
-       AdjustForMaintainedSelection(offsets.content, offsets.offset))
+  if (newFrame->IsSelected() &&
+      AdjustForMaintainedSelection(offsets.content, offsets.offset))
     return;
 
   // Adjust offsets according to maintained amount
   if (mMaintainRange && 
       mMaintainedAmount != eSelectNoAmount) {    
     
     nsINode* rangenode = mMaintainRange->GetStartParent();
     PRInt32 rangeOffset = mMaintainRange->StartOffset();
@@ -1906,17 +1905,16 @@ printf(" * TakeFocus - moving into new c
 
   // Don't notify selection listeners if batching is on:
   if (GetBatching())
     return NS_OK;
   return NotifySelectionListeners(nsISelectionController::SELECTION_NORMAL);
 }
 
 
-
 SelectionDetails*
 nsFrameSelection::LookUpSelection(nsIContent *aContent,
                                   PRInt32 aContentOffset,
                                   PRInt32 aContentLength,
                                   bool aSlowCheck) const
 {
   if (!aContent || !mShell)
     return nsnull;
@@ -2473,18 +2471,17 @@ printf("HandleTableSelection: Mouse down
           GetFirstSelectedContent(GetFirstCellRange());
         if (previousCellNode)
         {
           // We have at least 1 other selected cell
 
           // Check if new cell is already selected
           nsIFrame  *cellFrame = childContent->GetPrimaryFrame();
           if (!cellFrame) return NS_ERROR_NULL_POINTER;
-          result = cellFrame->GetSelected(&isSelected);
-          if (NS_FAILED(result)) return result;
+          isSelected = cellFrame->IsSelected();
         }
         else
         {
           // No cells selected -- remove non-cell selection
           mDomSelections[index]->RemoveAllRanges();
         }
         mDragSelectingCells = true;    // Signal to start drag-cell-selection
         mSelectingTableCellMode = aTarget;
@@ -3372,16 +3369,26 @@ nsMouseEvent*
 nsFrameSelection::GetDelayedCaretData()
 {
   if (mDelayedMouseEventValid)
     return &mDelayedMouseEvent;
   
   return nsnull;
 }
 
+void
+nsFrameSelection::DisconnectFromPresShell()
+{
+  StopAutoScrollTimer();
+  for (PRInt32 i = 0; i < nsISelectionController::NUM_SELECTIONTYPES; i++) {
+    mDomSelections[i]->Clear(nsnull);
+  }
+  mShell = nsnull;
+}
+
 //END nsISelection interface implementations
 
 #if 0
 #pragma mark -
 #endif
 
 // nsTypedSelection implementation
 
@@ -3401,16 +3408,21 @@ nsTypedSelection::nsTypedSelection(nsFra
   , mType(nsISelectionController::SELECTION_NORMAL)
 {
 }
 
 nsTypedSelection::~nsTypedSelection()
 {
   setAnchorFocusRange(-1);
 
+  PRUint32 count = mRanges.Length();
+  for (PRUint32 i = 0; i < count; ++i) {
+    mRanges[i].mRange->SetInSelection(false);
+  }
+
   if (mAutoScrollTimer) {
     mAutoScrollTimer->Stop();
     mAutoScrollTimer = nsnull;
   }
 
   mScrollEvent.Revoke();
 
   if (mCachedOffsetForFrame) {
@@ -3725,16 +3737,18 @@ nsTypedSelection::AddItem(nsIRange *aIte
     return NS_ERROR_UNEXPECTED;
   if (aOutIndex)
     *aOutIndex = -1;
 
   // a common case is that we have no ranges yet
   if (mRanges.Length() == 0) {
     if (!mRanges.AppendElement(RangeData(aItem)))
       return NS_ERROR_OUT_OF_MEMORY;
+    aItem->SetInSelection(true);
+
     if (aOutIndex)
       *aOutIndex = 0;
     return NS_OK;
   }
 
   PRInt32 startIndex, endIndex;
   GetIndicesForInterval(aItem->GetStartParent(), aItem->StartOffset(),
                         aItem->GetEndParent(), aItem->EndOffset(),
@@ -3762,16 +3776,17 @@ nsTypedSelection::AddItem(nsIRange *aIte
       *aOutIndex = startIndex;
     return NS_OK;
   }
 
   if (startIndex == endIndex) {
     // The new range doesn't overlap any existing ranges
     if (!mRanges.InsertElementAt(startIndex, RangeData(aItem)))
       return NS_ERROR_OUT_OF_MEMORY;
+    aItem->SetInSelection(true);
     if (aOutIndex)
       *aOutIndex = startIndex;
     return NS_OK;
   }
 
   // We now know that at least 1 existing range overlaps with the range that
   // we are trying to add. In fact, the only ranges of interest are those at
   // the two end points, startIndex and endIndex - 1 (which may point to the
@@ -3783,16 +3798,19 @@ nsTypedSelection::AddItem(nsIRange *aIte
     return NS_ERROR_OUT_OF_MEMORY;
 
   if (endIndex - 1 != startIndex) {
     if (!overlaps.InsertElementAt(1, mRanges[endIndex - 1]))
       return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // Remove all the overlapping ranges
+  for (PRInt32 i = startIndex; i < endIndex; ++i) {
+    mRanges[i].mRange->SetInSelection(false);
+  }
   mRanges.RemoveElementsAt(startIndex, endIndex - startIndex);
 
   nsTArray<RangeData> temp;
   for (PRInt32 i = overlaps.Length() - 1; i >= 0; i--) {
     nsresult rv = SubtractRange(&overlaps[i], aItem, &temp);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
@@ -3806,16 +3824,20 @@ nsTypedSelection::AddItem(nsIRange *aIte
 
   if (!temp.InsertElementAt(insertionPoint, RangeData(aItem)))
     return NS_ERROR_OUT_OF_MEMORY;
 
   // Merge the leftovers back in to mRanges
   if (!mRanges.InsertElementsAt(startIndex, temp))
     return NS_ERROR_OUT_OF_MEMORY;
 
+  for (PRUint32 i = 0; i < temp.Length(); ++i) {
+    temp[i].mRange->SetInSelection(true);
+  }
+
   *aOutIndex = startIndex + insertionPoint;
   return NS_OK;
 }
 
 nsresult
 nsTypedSelection::RemoveItem(nsIRange *aItem)
 {
   if (!aItem)
@@ -3832,16 +3854,17 @@ nsTypedSelection::RemoveItem(nsIRange *a
       idx = (PRInt32)i;
       break;
     }
   }
   if (idx < 0)
     return NS_ERROR_INVALID_ARG;
 
   mRanges.RemoveElementAt(idx);
+  aItem->SetInSelection(false);
   return NS_OK;
 }
 
 nsresult
 nsTypedSelection::RemoveCollapsedRanges()
 {
   PRUint32 i = 0;
   while (i < mRanges.Length()) {
@@ -3855,18 +3878,19 @@ nsTypedSelection::RemoveCollapsedRanges(
   return NS_OK;
 }
 
 nsresult
 nsTypedSelection::Clear(nsPresContext* aPresContext)
 {
   setAnchorFocusRange(-1);
 
-  for (PRInt32 i = 0; i < (PRInt32)mRanges.Length(); i ++) {
-    selectFrames(aPresContext, mRanges[i].mRange, 0);
+  for (PRUint32 i = 0; i < mRanges.Length(); ++i) {
+    mRanges[i].mRange->SetInSelection(false);
+    selectFrames(aPresContext, mRanges[i].mRange, false);
   }
   mRanges.Clear();
 
   // Reset direction so for more dependable table selection range handling
   SetDirection(eDirNext);
 
   // If this was an ATTENTION selection, change it back to normal now
   if (mFrameSelection &&
@@ -4269,104 +4293,91 @@ nsTypedSelection::GetPrimaryFrameForFocu
 }
 
 //select all content children of aContent
 nsresult
 nsTypedSelection::SelectAllFramesForContent(nsIContentIterator *aInnerIter,
                                   nsIContent *aContent,
                                   bool aSelected)
 {
-  if (!mFrameSelection)
-    return NS_OK; // nothing to do
-  nsIPresShell* shell = mFrameSelection->GetShell();
-  if (!shell)
-    return NS_OK;
-  nsresult result;
-  if (!aInnerIter)
-    return NS_ERROR_NULL_POINTER;
-  result = aInnerIter->Init(aContent);
+  nsresult result = aInnerIter->Init(aContent);
   nsIFrame *frame;
   if (NS_SUCCEEDED(result))
   {
     // First select frame of content passed in
     frame = aContent->GetPrimaryFrame();
-    if (frame)
-    {
-      frame->SetSelected(aSelected, mType);
-      if (mFrameSelection->GetTableCellSelection())
-      {
-        nsITableCellLayout *tcl = do_QueryFrame(frame);
-        if (tcl)
-        {
-          return NS_OK;
-        }
-      }
+    if (frame && frame->GetType() == nsGkAtoms::textFrame) {
+      nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
+      textFrame->SetSelectedRange(0, aContent->GetText()->GetLength(), aSelected, mType);
     }
     // Now iterated through the child frames and set them
-    while (!aInnerIter->IsDone())
-    {
+    while (!aInnerIter->IsDone()) {
       nsCOMPtr<nsIContent> innercontent =
         do_QueryInterface(aInnerIter->GetCurrentNode());
 
       frame = innercontent->GetPrimaryFrame();
-      if (frame)
-      {
-        frame->SetSelected(aSelected, mType);
+      if (frame) {
+        if (frame->GetType() == nsGkAtoms::textFrame) {
+          nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
+          textFrame->SetSelectedRange(0, innercontent->GetText()->GetLength(), aSelected, mType);
+        } else {
+          frame->InvalidateFrameSubtree();  // frame continuations?
+        }
       }
 
       aInnerIter->Next();
     }
 
     return NS_OK;
   }
 
   return NS_ERROR_FAILURE;
 }
 
-
-
 //the idea of this helper method is to select, deselect "top to bottom" traversing through the frames
 nsresult
 nsTypedSelection::selectFrames(nsPresContext* aPresContext, nsIRange *aRange, bool aFlags)
 {
-  if (!mFrameSelection || !aPresContext)
+  if (!mFrameSelection || !aPresContext || !aPresContext->GetPresShell())
     return NS_OK; // nothing to do
-  nsIPresShell *presShell = aPresContext->GetPresShell();
-  if (!presShell)
+
+  if (mFrameSelection->GetTableCellSelection()) {
+    nsINode* node = aRange->GetCommonAncestor();
+    nsCOMPtr<nsIContent> content = do_QueryInterface(node);
+    nsIFrame* frame = content ? content->GetPrimaryFrame()
+                              : aPresContext->FrameManager()->GetRootFrame();
+    if (frame) {
+      frame->InvalidateFrameSubtree();
+    }
     return NS_OK;
-
-  nsCOMPtr<nsIDOMRange> domRange = do_QueryInterface(aRange);
-  if (!domRange || !aPresContext) 
-    return NS_ERROR_NULL_POINTER;
+  }
 
   nsresult result;
   nsCOMPtr<nsIContentIterator> iter = do_CreateInstance(
                                               kCSubtreeIteratorCID,
                                               &result);
   if (NS_FAILED(result))
     return result;
 
   nsCOMPtr<nsIContentIterator> inneriter = do_CreateInstance(
                                               kCContentIteratorCID,
                                               &result);
 
-  if ((NS_SUCCEEDED(result)) && iter && inneriter)
-  {
+  if ((NS_SUCCEEDED(result)) && iter) {
     result = iter->Init(aRange);
 
     // loop through the content iterator for each content node
     // for each text node, call SetSelected on it:
     nsCOMPtr<nsIContent> content = do_QueryInterface(aRange->GetStartParent());
 
     // we must call first one explicitly
     if (!content)
       return NS_ERROR_UNEXPECTED;
 
-    if (content->IsNodeOfType(nsINode::eTEXT))
-    {
+    if (content->IsNodeOfType(nsINode::eTEXT)) {
       nsIFrame* frame = content->GetPrimaryFrame();
       // The frame could be an SVG text frame, in which case we'll ignore
       // it.
       if (frame && frame->GetType() == nsGkAtoms::textFrame)
       {
         nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
         PRUint32 startOffset = aRange->StartOffset();
         PRUint32 endOffset;
@@ -4375,23 +4386,19 @@ nsTypedSelection::selectFrames(nsPresCon
         } else {
           endOffset = content->GetText()->GetLength();
         }
         textFrame->SetSelectedRange(startOffset, endOffset, aFlags, mType);
       }
     }
 
     iter->First();
-
-    while (!iter->IsDone())
-    {
+    while (!iter->IsDone()) {
       content = do_QueryInterface(iter->GetCurrentNode());
-
       SelectAllFramesForContent(inneriter, content, aFlags);
-
       iter->Next();
     }
 
     //we must now do the last one  if it is not the same as the first
     if (aRange->GetEndParent() != aRange->GetStartParent())
     {
       content = do_QueryInterface(aRange->GetEndParent(), &result);
       if (NS_FAILED(result) || !content)
@@ -4408,16 +4415,17 @@ nsTypedSelection::selectFrames(nsPresCon
           textFrame->SetSelectedRange(0, aRange->EndOffset(), aFlags, mType);
         }
       }
     }
   }
   return result;
 }
 
+
 // nsTypedSelection::LookUpSelection
 //
 //    This function is called when a node wants to know where the selection is
 //    over itself.
 //
 //    Usually, this is called when we already know there is a selection over
 //    the node in question, and we only need to find the boundaries of it on
 //    that node. This is when slowCheck is false--a strict test is not needed.
@@ -4780,23 +4788,17 @@ nsTypedSelection::AddRange(nsIRange* aRa
   setAnchorFocusRange(rangeIndex);
   
   // Make sure the caret appears on the next line, if at a newline
   if (mType == nsISelectionController::SELECTION_NORMAL)
     SetInterlinePosition(true);
 
   nsRefPtr<nsPresContext>  presContext;
   GetPresContext(getter_AddRefs(presContext));
-
-  // Ensure all frames are properly constructed for selectFrames, bug 602331.
-  nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nsnull;
-  if (presShell) {
-    presShell->FlushPendingNotifications(Flush_Frames);
-  }
-  selectFrames(presContext, aRange, true);        
+  selectFrames(presContext, aRange, true);
 
   if (!mFrameSelection)
     return NS_OK;//nothing to do
 
   return mFrameSelection->NotifySelectionListeners(GetType());
 }
 
 // nsTypedSelection::RemoveRange
@@ -4921,37 +4923,31 @@ nsTypedSelection::Collapse(nsINode* aPar
   result = range->SetEnd(aParentNode, aOffset);
   if (NS_FAILED(result))
     return result;
   result = range->SetStart(aParentNode, aOffset);
   if (NS_FAILED(result))
     return result;
 
 #ifdef DEBUG_SELECTION
-  if (aParentNode)
-  {
-    nsCOMPtr<nsIContent>content;
-    content = do_QueryInterface(aParentNode);
-    if (!content)
-      return NS_ERROR_FAILURE;
-
-    printf ("Sel. Collapse to %p %s %d\n", content.get(),
-            nsAtomCString(content->Tag()).get(), aOffset);
-  }
-  else {
-    printf ("Sel. Collapse set to null parent.\n");
+  if (aParentNode) {
+    nsCOMPtr<nsIContent> content = do_QueryInterface(aParentNode);
+    nsCOMPtr<nsIDocument> doc = do_QueryInterface(aParentNode);
+    printf ("Sel. Collapse to %p %s %d\n", aParentNode,
+            content ? nsAtomCString(content->Tag()).get()
+                    : (doc ? "DOCUMENT" : "???"),
+            aOffset);
   }
 #endif
 
-
   result = AddItem(range);
+  if (NS_FAILED(result))
+    return result;
   setAnchorFocusRange(0);
   selectFrames(presContext, range, true);
-  if (NS_FAILED(result))
-    return result;
   return mFrameSelection->NotifySelectionListeners(GetType());
 }
 
 /*
  * Sets the whole selection to be one point
  * at the start of the current selection
  */
 NS_IMETHODIMP
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -160,21 +160,17 @@ public:
    * This is called only on the primary text frame. It indicates that
    * the selection state of the given character range has changed.
    * Text in the range is unconditionally invalidated
    * (nsTypedSelection::Repaint depends on this).
    * @param aSelected true if the selection has been added to the range,
    * false otherwise
    * @param aType the type of selection added or removed
    */
-  virtual void SetSelected(bool          aSelected,
-                           SelectionType aType);
-  void SetSelectedRange(PRUint32 aStart,
-                        PRUint32 aEnd,
-                        bool aSelected,
+  void SetSelectedRange(PRUint32 aStart, PRUint32 aEnd, bool aSelected,
                         SelectionType aType);
 
   virtual bool PeekOffsetNoAmount(bool aForward, PRInt32* aOffset);
   virtual bool PeekOffsetCharacter(bool aForward, PRInt32* aOffset,
                                      bool aRespectClusters = true);
   virtual bool PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect,
                                 PRInt32* aOffset, PeekWordState* aState);
 
@@ -471,16 +467,22 @@ protected:
   // This does *not* indicate the length of text currently mapped by the frame;
   // instead it's a hint saying that this frame *wants* to map this much text
   // so if we create a new continuation, this is where that continuation should
   // start.
   PRInt32     mContentLengthHint;
   nscoord     mAscent;
   gfxTextRun* mTextRun;
 
+  /**
+   * Return true if the frame is part of a Selection.
+   * Helper method to implement the public IsSelected() API.
+   */
+  virtual bool IsFrameSelected() const;
+
   // The caller of this method must call DestroySelectionDetails() on the
   // return value, if that return value is not null.  Calling
   // DestroySelectionDetails() on a null value is still OK, just not necessary.
   SelectionDetails* GetSelectionDetails();
 
   void UnionAdditionalOverflow(nsPresContext* aPresContext,
                                const nsHTMLReflowState& aBlockReflowState,
                                PropertyProvider& aProvider,
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -87,16 +87,17 @@
 #include "nsIUGenCategory.h"
 #include "nsUnicharUtilCIID.h"
 
 #include "nsTextFragment.h"
 #include "nsGkAtoms.h"
 #include "nsFrameSelection.h"
 #include "nsISelection.h"
 #include "nsIDOMRange.h"
+#include "nsRange.h"
 #include "nsCSSRendering.h"
 #include "nsContentUtils.h"
 #include "nsLineBreaker.h"
 #include "nsIWordBreaker.h"
 #include "nsGenericDOMDataNode.h"
 
 #include "nsILineIterator.h"
 
@@ -3684,16 +3685,17 @@ nsTextFrame::Init(nsIContent*      aCont
   // might be invalid if the content was modified while there was no frame
   aContent->DeleteProperty(nsGkAtoms::newline);
   if (PresContext()->BidiEnabled()) {
     aContent->DeleteProperty(nsGkAtoms::flowlength);
   }
 
   // Since our content has a frame now, this flag is no longer needed.
   aContent->UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE);
+
   // We're not a continuing frame.
   // mContentOffset = 0; not necessary since we get zeroed out at init
   return nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 void
 nsTextFrame::ClearFrameOffsetCache()
 {
@@ -4309,16 +4311,19 @@ GetGeneratedContentOwner(nsIFrame* aFram
   }
   return aFrame;
 }
 
 SelectionDetails*
 nsTextFrame::GetSelectionDetails()
 {
   const nsFrameSelection* frameSelection = GetConstFrameSelection();
+  if (frameSelection->GetTableCellSelection()) {
+    return nsnull;
+  }
   if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) {
     SelectionDetails* details =
       frameSelection->LookUpSelection(mContent, GetContentOffset(),
                                       GetContentLength(), false);
     SelectionDetails* sd;
     for (sd = details; sd; sd = sd->mNext) {
       sd->mStart += mContentOffset;
       sd->mEnd += mContentOffset;
@@ -4570,17 +4575,17 @@ nsTextFrame::UnionAdditionalOverflow(nsP
       }
 
       aVisualOverflowRect->UnionRect(*aVisualOverflowRect,
                                      nsRect(0, top, width, bottom - top));
     }
   }
   // When this frame is not selected, the text-decoration area must be in
   // frame bounds.
-  if (!(GetStateBits() & NS_FRAME_SELECTED_CONTENT) ||
+  if (!IsSelected() ||
       !CombineSelectionUnderlineRect(aPresContext, *aVisualOverflowRect))
     return;
   AddStateBits(TEXT_SELECTION_UNDERLINE_OVERFLOWED);
 }
 
 static gfxFloat
 ComputeDescentLimitForSelectionUnderline(nsPresContext* aPresContext,
                                          nsTextFrame* aFrame,
@@ -5020,23 +5025,17 @@ nsTextFrame::PaintTextWithSelectionColor
         }
       }
     }
     sdptr = sdptr->mNext;
   }
   *aAllTypes = allTypes;
 
   if (!allTypes) {
-    // Nothing is selected in the given text range.
-    if (aContentLength == aProvider.GetOriginalLength()) {
-      // It's the full text range so we can remove the FRAME_SELECTED_CONTENT
-      // bit to avoid going through this slow path until something is selected
-      // in this frame again.
-      RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
-    }
+    // Nothing is selected in the given text range. XXX can this still occur?
     return false;
   }
 
   const gfxFloat startXOffset = aTextBaselinePt.x - aFramePt.x;
   gfxFloat xOffset, hyphenWidth;
   PRUint32 offset, length; // in transformed string
   SelectionType type;
   nsTextRangeStyle rangeStyle;
@@ -5174,33 +5173,28 @@ bool
 nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
     const gfxPoint& aFramePt,
     const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect,
     PropertyProvider& aProvider,
     PRUint32 aContentOffset, PRUint32 aContentLength,
     nsTextPaintStyle& aTextPaintStyle,
     const nsCharClipDisplayItem::ClipEdges& aClipEdges)
 {
+  NS_ASSERTION(GetContent()->IsSelectionDescendant(), "wrong paint path");
+
   SelectionDetails* details = GetSelectionDetails();
   if (!details) {
-    if (aContentLength == aProvider.GetOriginalLength()) {
-      // It's the full text range so we can remove the FRAME_SELECTED_CONTENT
-      // bit to avoid going through this slow path until something is selected
-      // in this frame again.
-      RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
-    }
     return false;
   }
 
   SelectionType allTypes;
   if (!PaintTextWithSelectionColors(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
                                     aProvider, aContentOffset, aContentLength,
                                     aTextPaintStyle, details, &allTypes,
-                                    aClipEdges))
-  {
+                                    aClipEdges)) {
     DestroySelectionDetails(details);
     return false;
   }
   PRInt32 i;
   // Iterate through just the selection types that paint decorations and
   // paint decorations for any that actually occur in this frame. Paint
   // higher-numbered selection types below lower-numered ones on the
   // general principal that lower-numbered selections are higher priority.
@@ -5407,25 +5401,26 @@ nsTextFrame::PaintText(nsRenderingContex
   textBaselinePt.x += rtl ? -snappedRightEdge : snappedLeftEdge;
   nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedLeftEdge,
                                              snappedRightEdge);
   nsTextPaintStyle textPaintStyle(this);
 
   gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
                     aDirtyRect.width, aDirtyRect.height);
   // Fork off to the (slower) paint-with-selection path if necessary.
-  if (nsLayoutUtils::GetNonGeneratedAncestor(this)->GetStateBits() & NS_FRAME_SELECTED_CONTENT) {
+  if (IsSelected()) {
     gfxSkipCharsIterator tmp(provider.GetStart());
     PRInt32 contentOffset = tmp.ConvertSkippedToOriginal(startOffset);
     PRInt32 contentLength =
       tmp.ConvertSkippedToOriginal(startOffset + maxLength) - contentOffset;
     if (PaintTextWithSelection(ctx, framePt, textBaselinePt, dirtyRect,
                                provider, contentOffset, contentLength,
-                               textPaintStyle, clipEdges))
+                               textPaintStyle, clipEdges)) {
       return;
+    }
   }
 
   nscolor foregroundColor = textPaintStyle.GetTextColor();
   const nsStyleText* textStyle = GetStyleText();
   if (textStyle->mTextShadow) {
     // Text shadow happens with the last value being painted at the back,
     // ie. it is painted first.
     for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
@@ -5605,18 +5600,17 @@ nsTextFrame::GetSelectionStatus(PRInt16*
 
   return selectionValue;
 }
 
 bool
 nsTextFrame::IsVisibleInSelection(nsISelection* aSelection)
 {
   // Check the quick way first
-  bool isSelected = (mState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
-  if (!isSelected)
+  if (!GetContent()->IsSelectionDescendant())
     return false;
     
   SelectionDetails* details = GetSelectionDetails();
   bool found = false;
     
   // where are the selection points "really"
   SelectionDetails *sdptr = details;
   while (sdptr) {
@@ -5796,69 +5790,52 @@ nsTextFrame::CombineSelectionUnderlineRe
         style, descentLimit);
     aRect.UnionRect(aRect, decorationArea);
   }
   DestroySelectionDetails(details);
 
   return !aRect.IsEmpty() && !givenRect.Contains(aRect);
 }
 
-void
-nsTextFrame::SetSelected(bool          aSelected,
-                         SelectionType aType)
-{
-  SetSelectedRange(0, mContent->GetText()->GetLength(), aSelected, aType);
+bool
+nsTextFrame::IsFrameSelected() const
+{
+  NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
+               "use the public IsSelected() instead");
+  return nsRange::IsNodeSelected(GetContent(), GetContentOffset(),
+                                 GetContentEnd());
 }
 
 void
-nsTextFrame::SetSelectedRange(PRUint32 aStart,
-                              PRUint32 aEnd,
-                              bool aSelected,
+nsTextFrame::SetSelectedRange(PRUint32 aStart, PRUint32 aEnd, bool aSelected,
                               SelectionType aType)
 {
   NS_ASSERTION(!GetPrevContinuation(), "Should only be called for primary frame");
   DEBUG_VERIFY_NOT_DIRTY(mState);
 
   // Selection is collapsed, which can't affect text frame rendering
   if (aStart == aEnd)
     return;
 
   if (aType == nsISelectionController::SELECTION_NORMAL) {
     // check whether style allows selection
     bool selectable;
     IsSelectable(&selectable, nsnull);
-    if (!selectable)
+    if (!selectable) {
       return;
-  }
-
-  bool anySelected = false;
+    }
+  }
 
   nsTextFrame* f = this;
   while (f && f->GetContentEnd() <= PRInt32(aStart)) {
-    if (f->GetStateBits() & NS_FRAME_SELECTED_CONTENT) {
-      anySelected = true;
-    }
     f = static_cast<nsTextFrame*>(f->GetNextContinuation());
   }
 
   nsPresContext* presContext = PresContext();
   while (f && f->GetContentOffset() < PRInt32(aEnd)) {
-    if (aSelected) {
-      f->AddStateBits(NS_FRAME_SELECTED_CONTENT);
-      anySelected = true;
-    } else { // we need to see if any other selection is available.
-      SelectionDetails *details = f->GetSelectionDetails();
-      if (details) {
-        anySelected = true;
-        DestroySelectionDetails(details);
-      } else {
-        f->RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
-      }
-    }
-
     // We may need to reflow to recompute the overflow area for
     // spellchecking or IME underline if their underline is thicker than
     // the normal decoration line.
     if (aType & SelectionTypesWithDecorations) {
       bool didHaveOverflowingSelection =
         (f->GetStateBits() & TEXT_SELECTION_UNDERLINE_OVERFLOWED) != 0;
       nsRect r(nsPoint(0, 0), GetSize());
       bool willHaveOverflowingSelection =
@@ -5869,32 +5846,16 @@ nsTextFrame::SetSelectedRange(PRUint32 a
                                                    NS_FRAME_IS_DIRTY);
       }
     }
     // Selection might change anything. Invalidate the overflow area.
     f->InvalidateOverflowRect();
 
     f = static_cast<nsTextFrame*>(f->GetNextContinuation());
   }
-
-  // Scan remaining continuations to see if any are selected
-  while (f && !anySelected) {
-    if (f->GetStateBits() & NS_FRAME_SELECTED_CONTENT) {
-      anySelected = true;
-    }
-    f = static_cast<nsTextFrame*>(f->GetNextContinuation());
-  }
-
-  if (anySelected) {
-    mContent->SetFlags(NS_TEXT_IN_SELECTION);
-  } else {
-    // This is only legal because there is only one presentation for the
-    // content with a selection
-    mContent->UnsetFlags(NS_TEXT_IN_SELECTION);
-  }
 }
 
 NS_IMETHODIMP
 nsTextFrame::GetPointFromOffset(PRInt32 inOffset,
                                 nsPoint* outPoint)
 {
   if (!outPoint)
     return NS_ERROR_NULL_POINTER;
@@ -7618,26 +7579,16 @@ nsTextFrame::ReflowText(nsLineLayout& aL
     NS_ASSERTION(numJustifiableCharacters <= charsFit,
                  "Bad justifiable character count");
     aLineLayout.SetTextJustificationWeights(numJustifiableCharacters,
         charsFit - numJustifiableCharacters);
   }
 
   SetLength(contentLength, &aLineLayout, ALLOW_FRAME_CREATION_AND_DESTRUCTION);
 
-  if (mContent->HasFlag(NS_TEXT_IN_SELECTION)) {
-    SelectionDetails* details = GetSelectionDetails();
-    if (details) {
-      AddStateBits(NS_FRAME_SELECTED_CONTENT);
-      DestroySelectionDetails(details);
-    } else {
-      RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
-    }
-  }
-
   Invalidate(aMetrics.VisualOverflow());
 
 #ifdef NOISY_REFLOW
   ListTag(stdout);
   printf(": desiredSize=%d,%d(b=%d) status=%x\n",
          aMetrics.width, aMetrics.height, aMetrics.ascent,
          aStatus);
 #endif
@@ -7991,22 +7942,19 @@ nsTextFrame::List(FILE* out, PRInt32 aIn
     fprintf(out, " prev-continuation=%p", static_cast<void*>(prevContinuation));
   }
   if (nsnull != mNextContinuation) {
     fprintf(out, " next-continuation=%p", static_cast<void*>(mNextContinuation));
   }
 
   // Output the rect and state
   fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
-  if (0 != mState) {
-    if (mState & NS_FRAME_SELECTED_CONTENT) {
-      fprintf(out, " [state=%016llx] SELECTED", mState);
-    } else {
-      fprintf(out, " [state=%016llx]", mState);
-    }
+  fprintf(out, " [state=%016llx]", mState);
+  if (IsSelected()) {
+    fprintf(out, " SELECTED");
   }
   fprintf(out, " [content=%p]", static_cast<void*>(mContent));
   if (HasOverflowAreas()) {
     nsRect overflowArea = GetVisualOverflowRect();
     fprintf(out, " [vis-overflow=%d,%d,%d,%d]",
             overflowArea.x, overflowArea.y,
             overflowArea.width, overflowArea.height);
     overflowArea = GetScrollableOverflowRect();
--- a/layout/mathml/nsMathMLmoFrame.cpp
+++ b/layout/mathml/nsMathMLmoFrame.cpp
@@ -84,22 +84,17 @@ nsMathMLmoFrame::GetMathMLFrameType()
 
 // since a mouse click implies selection, we cannot just rely on the
 // frame's state bit in our child text frame. So we will first check
 // its selected state bit, and use this little helper to double check.
 bool
 nsMathMLmoFrame::IsFrameInSelection(nsIFrame* aFrame)
 {
   NS_ASSERTION(aFrame, "null arg");
-  if (!aFrame)
-    return false;
-
-  bool isSelected = false;
-  aFrame->GetSelected(&isSelected);
-  if (!isSelected)
+  if (!aFrame || !aFrame->IsSelected())
     return false;
 
   const nsFrameSelection* frameSelection = aFrame->GetConstFrameSelection();
   SelectionDetails* details =
     frameSelection->LookUpSelection(aFrame->GetContent(), 0, 1, true);
 
   if (!details)
     return false;
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -2541,25 +2541,17 @@ nsPrintEngine::FindSelectionBoundsWithLi
                                            nsRect&         aEndRect)
 {
   NS_ASSERTION(aPresContext, "Pointer is null!");
   NS_ASSERTION(aParentFrame, "Pointer is null!");
 
   aRect += aParentFrame->GetPosition();
   for (; !aChildFrames.AtEnd(); aChildFrames.Next()) {
     nsIFrame* child = aChildFrames.get();
-    // only leaf frames have this bit flipped
-    // then check the hard way
-    bool isSelected = (child->GetStateBits() & NS_FRAME_SELECTED_CONTENT)
-      == NS_FRAME_SELECTED_CONTENT;
-    if (isSelected) {
-      isSelected = child->IsVisibleForPainting();
-    }
-
-    if (isSelected) {
+    if (child->IsSelected() && child->IsVisibleForPainting()) {
       nsRect r = child->GetRect();
       if (aStartFrame == nsnull) {
         aStartFrame = child;
         aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
       } else {
         aEndFrame = child;
         aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height);
       }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/selection/dom-mutations-ref.html
@@ -0,0 +1,200 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=619273
+-->
+<head>
+  <title>Test for Bug 619273</title>
+<script type="application/javascript;version=1.7">
+/** Test DOM mutations inside selection **/
+function createDOM(doc) {
+  let s = doc.createElement('span');
+  s.appendChild(doc.createTextNode('|'))
+  let s2 = doc.createElement('span');
+  s2.appendChild(doc.createTextNode('z'))
+  s.appendChild(s2)
+  return s;
+}
+
+var tests_done = 0;
+var tests = [
+  function(win,doc,sel) {
+    doc.body.innerHTML = '.I<br>B<br>C|z'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(a, 1);
+    r.setEnd(a, 2);
+    sel.addRange(r);
+  },
+   function(win,doc,sel) {
+    doc.body.innerHTML = '.I<br>B<br>C|z'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(doc.firstChild, 0);
+    r.setEnd(a, 2);
+    sel.addRange(r);
+  },
+ function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>.B<br>C|z'
+    let a = doc.body.firstChild;
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>.B<br>C|z'
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(doc.body, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>.B<br>C|z'
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(doc, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>.C|z'
+    let a = doc.body.firstChild;
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 2);
+    sel.addRange(r);
+  },
+
+  function(win,doc,sel) {
+    doc.body.innerHTML = '|z|zI<br>B<br>C'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(a, 4);
+    r.setEnd(a, 5);
+    sel.addRange(r);
+  },
+   function(win,doc,sel) {
+    doc.body.innerHTML = '|z|zI<br>B<br>C'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(doc.firstChild, 0);
+    r.setEnd(a, 5);
+    sel.addRange(r);
+  },
+ function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>|z|zB<br>C'
+    let a = doc.body.firstChild;
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>|z|zB<br>C'
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(doc.body, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>|z|zB<br>C'
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(doc, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>|z|zC'
+    let a = doc.body.firstChild;
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 5);
+    sel.addRange(r);
+  },
+
+  function(win,doc,sel) {
+    doc.body.innerHTML = '<br>B<br>CI'
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = '<br>B<br>C'
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+  },
+
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I|z'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(a, 1);
+    r.setEnd(a, 2);
+    sel.addRange(r);
+  },
+
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'Iz|'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(a, 1);
+    r.setEnd(a, 2);
+    sel.addRange(r);
+
+    document.body.appendChild(document.createTextNode('I'));
+    document.body.appendChild(document.createTextNode(' '));
+    document.body.appendChild(createDOM(document));
+  },
+]
+
+function runTestInIframe(run,t) {
+  let f = document.createElement('iframe');
+  f.setAttribute('frameborder','0');
+  f.setAttribute('height','100');
+  f.setAttribute('width','200');
+  f.src = 'data:text/html,<body style="margin:0;padding:0;font-family:monospace">';
+  f.onload = function () {
+    try {
+      run(f.contentWindow, f.contentDocument, f.contentWindow.getSelection());
+    } finally { ++tests_done; }
+  }
+  return f;
+}
+
+var id;
+function checkFinished() {
+  if (window.frames.length == tests_done) {
+    clearInterval(id);
+    document.documentElement.className = "";
+  }
+}
+
+function runTest() {
+  for (let i=0; i < tests.length; ++i) {
+    let t = tests[i];
+    document.body.appendChild(runTestInIframe(t));
+  }
+  id = setInterval(checkFinished,500);
+}
+</script>
+</head>
+<body onload="runTest()"></body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/selection/dom-mutations.html
@@ -0,0 +1,250 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=619273
+-->
+<head>
+  <title>Test for Bug 619273</title>
+<script type="application/javascript;version=1.7">
+/** Test DOM mutations inside selection **/
+function createDOM(doc) {
+  let s = doc.createElement('span');
+  s.appendChild(doc.createTextNode('|'))
+  let s2 = doc.createElement('span');
+  s2.appendChild(doc.createTextNode('z'))
+  s.appendChild(s2)
+  return s;
+}
+
+var tests_done = 0;
+var tests = [
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(a, 1);
+    sel.addRange(r);
+    doc.body.insertBefore(doc.createTextNode('.'), a);
+    doc.body.appendChild(createDOM(doc));
+  },
+   function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(doc.firstChild, 0);
+    r.setEnd(a, 1);
+    sel.addRange(r);
+    doc.body.insertBefore(doc.createTextNode('.'), a);
+    doc.body.appendChild(createDOM(doc));
+  },
+ function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    doc.body.insertBefore(doc.createTextNode('.'), b);
+    doc.body.appendChild(createDOM(doc));
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(doc.body, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    doc.body.insertBefore(doc.createTextNode('.'), b);
+    doc.body.appendChild(createDOM(doc));
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(doc, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    doc.body.insertBefore(doc.createTextNode('.'), b);
+    doc.body.appendChild(createDOM(doc));
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    doc.body.insertBefore(doc.createTextNode('.'), c);
+    doc.body.appendChild(createDOM(doc));
+  },
+
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(a, 1);
+    sel.addRange(r);
+    let span = createDOM(doc);
+    doc.body.insertBefore(span, a);
+    span.appendChild(createDOM(doc));
+  },
+   function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(doc.firstChild, 0);
+    r.setEnd(a, 1);
+    sel.addRange(r);
+    let span = createDOM(doc);
+    doc.body.insertBefore(span, a);
+    span.appendChild(createDOM(doc));
+  },
+ function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    let span = createDOM(doc);
+    doc.body.insertBefore(span, b);
+    span.appendChild(createDOM(doc));
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(doc.body, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    let span = createDOM(doc);
+    doc.body.insertBefore(span, b);
+    span.appendChild(createDOM(doc));
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let b = doc.body.childNodes[2];
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(doc, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    let span = createDOM(doc);
+    doc.body.insertBefore(span, b);
+    span.appendChild(createDOM(doc));
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    let span = createDOM(doc);
+    doc.body.insertBefore(span, c);
+    span.appendChild(createDOM(doc));
+  },
+
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(a, 1);
+    sel.addRange(r);
+    doc.body.appendChild(a);
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(a, 1);
+    sel.addRange(r);
+    document.adoptNode(a);
+    document.body.appendChild(a);
+    document.body.appendChild(document.createTextNode(' '));
+  },
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I<br>B<br>C'
+    let a = doc.body.firstChild;
+    let c = doc.body.childNodes[4];
+    let r = doc.createRange();
+    r.setStart(a, 0);
+    r.setEnd(c, 1);
+    sel.addRange(r);
+    let span = createDOM(doc);
+    doc.body.insertBefore(span, c);
+    document.adoptNode(span);
+    document.body.appendChild(span);
+  },
+
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I'
+    let a = doc.body.firstChild;
+    let span = createDOM(doc);
+    let r = doc.createRange();
+    r.setStart(span, 0);
+    r.setEnd(span, 1);
+    sel.addRange(r);
+    doc.body.appendChild(span);
+  },
+
+  function(win,doc,sel) {
+    doc.body.innerHTML = 'I'
+    let a = doc.body.firstChild;
+    let span = createDOM(doc);
+    let r = doc.createRange();
+    r.setStart(span.firstChild, 0);
+    r.setEnd(span.firstChild, 1);
+    sel.addRange(r);
+    doc.body.appendChild(span);
+    doc.body.appendChild(span.firstChild);
+    r.setEnd(span.firstChild, 1);
+  },
+]
+
+function runTestInIframe(run,t) {
+  let f = document.createElement('iframe');
+  f.setAttribute('frameborder','0');
+  f.setAttribute('height','100');
+  f.setAttribute('width','200');
+  f.src = 'data:text/html,<body style="margin:0;padding:0;font-family:monospace">';
+  f.onload = function () {
+    try {
+      run(f.contentWindow, f.contentDocument, f.contentWindow.getSelection());
+    } finally { ++tests_done; }
+  }
+  return f;
+}
+
+var id;
+function checkFinished() {
+  if (window.frames.length == tests_done) {
+    clearInterval(id);
+    document.documentElement.className = "";
+  }
+}
+
+function runTest() {
+  for (let i=0; i < tests.length; ++i) {
+    let t = tests[i];
+    document.body.appendChild(runTestInIframe(t));
+  }
+  id = setInterval(checkFinished,500);
+}
+</script>
+</head>
+<body onload="runTest()"></body>
+</html>
--- a/layout/reftests/selection/reftest.list
+++ b/layout/reftests/selection/reftest.list
@@ -26,8 +26,9 @@
 == extend-4b.html extend-4-ref.html
 fails-if(Android) != pseudo-element-of-native-anonymous.html pseudo-element-of-native-anonymous-ref.html # bug 676641
 # These tests uses Highlight and HighlightText color keywords, they are not same as text selection color on Mac.
 fails-if(cocoaWidget) == non-themed-widget.html non-themed-widget-ref.html
 fails-if(cocoaWidget) == themed-widget.html themed-widget-ref.html
 == addrange-1.html addrange-ref.html
 == addrange-2.html addrange-ref.html
 == splitText-normalize.html splitText-normalize-ref.html
+== dom-mutations.html dom-mutations-ref.html
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp
+++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp
@@ -266,52 +266,16 @@ nsSVGGlyphFrame::DidSetStyleContext(nsSt
   nsSVGGlyphFrameBase::DidSetStyleContext(aOldStyleContext);
 
   if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     ClearTextRun();
     NotifyGlyphMetricsChange();
   }
 }
 
-void
-nsSVGGlyphFrame::SetSelected(bool          aSelected,
-                             SelectionType aType)
-{
-#if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
-  printf("nsSVGGlyphFrame(%p)::SetSelected()\n", this);
-#endif
-
-  if (aType != nsISelectionController::SELECTION_NORMAL)
-    return;
-
-  // check whether style allows selection
-  bool selectable;
-  IsSelectable(&selectable, nsnull);
-  if (!selectable)
-    return;
-
-  if (aSelected) {
-    AddStateBits(NS_FRAME_SELECTED_CONTENT);
-  } else {
-    RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
-  }
-
-  nsSVGUtils::UpdateGraphic(this);
-}
-
-NS_IMETHODIMP
-nsSVGGlyphFrame::GetSelected(bool *aSelected) const
-{
-  nsresult rv = nsSVGGlyphFrameBase::GetSelected(aSelected);
-#if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
-  printf("nsSVGGlyphFrame(%p)::GetSelected()=%d\n", this, *aSelected);
-#endif
-  return rv;
-}
-
 NS_IMETHODIMP
 nsSVGGlyphFrame::IsSelectable(bool* aIsSelectable,
                               PRUint8* aSelectStyle) const
 {
   nsresult rv = nsSVGGlyphFrameBase::IsSelectable(aIsSelectable, aSelectStyle);
 #if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
   printf("nsSVGGlyphFrame(%p)::IsSelectable()=(%d,%d)\n", this, *aIsSelectable, aSelectStyle);
 #endif
@@ -979,19 +943,17 @@ nsresult
 nsSVGGlyphFrame::GetHighlight(PRUint32 *charnum, PRUint32 *nchars,
                               nscolor *foreground, nscolor *background)
 {
   *foreground = NS_RGB(255,255,255);
   *background = NS_RGB(0,0,0); 
   *charnum=0;
   *nchars=0;
 
-  bool hasHighlight =
-    (mState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
-
+  bool hasHighlight = IsSelected();
   if (!hasHighlight) {
     NS_ERROR("nsSVGGlyphFrame::GetHighlight() called by renderer when there is no highlight");
     return NS_ERROR_FAILURE;
   }
 
   nsPresContext *presContext = PresContext();
 
   // The selection ranges are relative to the uncompressed text in
--- a/layout/svg/base/src/nsSVGGlyphFrame.h
+++ b/layout/svg/base/src/nsSVGGlyphFrame.h
@@ -130,19 +130,16 @@ public:
   bool EndsWithWhitespace() const;
   bool IsAllWhitespace() const;
 
   // nsIFrame interface:
   NS_IMETHOD  CharacterDataChanged(CharacterDataChangeInfo* aInfo);
 
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext);
 
-  virtual void SetSelected(bool          aSelected,
-                           SelectionType aType);
-  NS_IMETHOD  GetSelected(bool *aSelected) const;
   NS_IMETHOD  IsSelectable(bool* aIsSelectable, PRUint8* aSelectStyle) const;
 
   NS_IMETHOD Init(nsIContent*      aContent,
                   nsIFrame*        aParent,
                   nsIFrame*        aPrevInFlow);
 
   /**
    * Get the "type" of the frame
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -313,18 +313,17 @@ inline nscolor EnsureDifferentColors(nsc
     }
     return colorA;
 }
 
 void
 nsTableCellFrame::DecorateForSelection(nsRenderingContext& aRenderingContext,
                                        nsPoint aPt)
 {
-  NS_ASSERTION(GetStateBits() & NS_FRAME_SELECTED_CONTENT,
-               "Should only be called for selected cells");
+  NS_ASSERTION(IsSelected(), "Should only be called for selected cells");
   PRInt16 displaySelection;
   nsPresContext* presContext = PresContext();
   displaySelection = DisplaySelection(presContext);
   if (displaySelection) {
     nsRefPtr<nsFrameSelection> frameSelection =
       presContext->PresShell()->FrameSelection();
 
     if (frameSelection->GetTableCellSelection()) {
@@ -494,19 +493,17 @@ nsTableCellFrame::BuildDisplayList(nsDis
     if (!tableFrame->IsBorderCollapse() && HasBorder() &&
         emptyCellStyle == NS_STYLE_TABLE_EMPTY_CELLS_SHOW) {
       nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
           nsDisplayBorder(aBuilder, this));
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // and display the selection border if we need to
-    bool isSelected =
-      (GetStateBits() & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
-    if (isSelected) {
+    if (IsSelected()) {
       nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
           nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection,
                            "TableCellSelection",
                            nsDisplayItem::TYPE_TABLE_CELL_SELECTION));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -3662,17 +3662,17 @@ nsTableFrame::GetCellDataAt(PRInt32     
                             PRInt32        aColIndex,
                             nsIDOMElement* &aCell,   //out params
                             PRInt32&       aStartRowIndex,
                             PRInt32&       aStartColIndex,
                             PRInt32&       aRowSpan,
                             PRInt32&       aColSpan,
                             PRInt32&       aActualRowSpan,
                             PRInt32&       aActualColSpan,
-                            bool&        aIsSelected)
+                            bool&          aIsSelected)
 {
   // Initialize out params
   aCell = nsnull;
   aStartRowIndex = 0;
   aStartColIndex = 0;
   aRowSpan = 0;
   aColSpan = 0;
   aIsSelected = false;
@@ -3695,18 +3695,17 @@ nsTableFrame::GetCellDataAt(PRInt32     
   aColSpan = cellFrame->GetColSpan();
   aActualRowSpan = GetEffectiveRowSpan(*cellFrame);
   aActualColSpan = GetEffectiveColSpan(*cellFrame);
 
   // If these aren't at least 1, we have a cellmap error
   if (aActualRowSpan == 0 || aActualColSpan == 0)
     return NS_ERROR_FAILURE;
 
-  result = cellFrame->GetSelected(&aIsSelected);
-  if (NS_FAILED(result)) return result;
+  aIsSelected = cellFrame->IsSelected();
 
   // do this last, because it addrefs,
   // and we don't want the caller leaking it on error
   nsIContent* content = cellFrame->GetContent();
   if (!content) return NS_ERROR_FAILURE;
 
   return CallQueryInterface(content, &aCell);
 }
--- a/layout/tables/nsTableOuterFrame.cpp
+++ b/layout/tables/nsTableOuterFrame.cpp
@@ -366,24 +366,16 @@ nsTableOuterFrame::BuildDisplayListForIn
   while (kid) {
     nsresult rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
     NS_ENSURE_SUCCESS(rv, rv);
     kid = kid->GetNextSibling();
   }
   return NS_OK;
 }
 
-void
-nsTableOuterFrame::SetSelected(bool          aSelected,
-                               SelectionType aType)
-{
-  nsFrame::SetSelected(aSelected, aType);
-  InnerTableFrame()->SetSelected(aSelected, aType);
-}
-
 nsIFrame*
 nsTableOuterFrame::GetParentStyleContextFrame()
 {
   // The table outer frame and the (inner) table frame split the style
   // data by giving the table frame the style context associated with
   // the table content node and creating a style context for the outer
   // frame that is a *child* of the table frame's style context,
   // matching the ::-moz-table-outer pseudo-element.  html.css has a
--- a/layout/tables/nsTableOuterFrame.h
+++ b/layout/tables/nsTableOuterFrame.h
@@ -154,21 +154,16 @@ public:
    * @see nsGkAtoms::tableOuterFrame
    */
   virtual nsIAtom* GetType() const;
 
 #ifdef DEBUG
   NS_IMETHOD GetFrameName(nsAString& aResult) const;
 #endif
 
-  /** SetSelected needs to be overridden to talk to inner tableframe
-   */
-  void SetSelected(bool aSelected,
-                   SelectionType aType);
-
   virtual nsIFrame* GetParentStyleContextFrame();
 
   /*---------------- nsITableLayout methods ------------------------*/
 
   /** @see nsITableFrame::GetCellDataAt */
   NS_IMETHOD GetCellDataAt(PRInt32 aRowIndex, PRInt32 aColIndex, 
                            nsIDOMElement* &aCell,   //out params
                            PRInt32& aStartRowIndex, PRInt32& aStartColIndex, 
--- a/layout/tools/reftest/jar.mn
+++ b/layout/tools/reftest/jar.mn
@@ -1,12 +1,10 @@
 reftest.jar:
 % content reftest %content/
-*  content/quit.js (quit.js)
 *  content/reftest.js (reftest.js)
   content/reftest-content.js (reftest-content.js)
   content/reftest.xul (reftest.xul)
-  content/MozillaLogger.js (../../../testing/mochitest/tests/SimpleTest/MozillaLogger.js)
 #ifdef XPI_NAME
 %  component {32530271-8c1b-4b7d-a812-218e42c6bb23} components/reftest-cmdline.js
 %  contract @mozilla.org/commandlinehandler/general-startup;1?type=reftest {32530271-8c1b-4b7d-a812-218e42c6bb23}
 %  category command-line-handler m-reftest @mozilla.org/commandlinehandler/general-startup;1?type=reftest
 #endif
deleted file mode 100644
--- a/layout/tools/reftest/quit.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is The Original Code is Mozilla Automated Testing Code
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2005
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s): Bob Clary <bob@bclary.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/*
-  From mozilla/toolkit/content
-  These files did not have a license
-*/
-
-function canQuitApplication()
-{
-  var os = Components.classes["@mozilla.org/observer-service;1"]
-    .getService(Components.interfaces.nsIObserverService);
-  if (!os) 
-  {
-    return true;
-  }
-  
-  try 
-  {
-    var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
-      .createInstance(Components.interfaces.nsISupportsPRBool);
-    os.notifyObservers(cancelQuit, "quit-application-requested", null);
-    
-    // Something aborted the quit process. 
-    if (cancelQuit.data)
-    {
-      return false;
-    }
-  }
-  catch (ex) 
-  {
-  }
-  return true;
-}
-
-function goQuitApplication()
-{
-  if (!canQuitApplication())
-  {
-    return false;
-  }
-
-  const kAppStartup = '@mozilla.org/toolkit/app-startup;1';
-  const kAppShell   = '@mozilla.org/appshell/appShellService;1';
-  var   appService;
-  var   forceQuit;
-
-  if (kAppStartup in Components.classes)
-  {
-    appService = Components.classes[kAppStartup].
-      getService(Components.interfaces.nsIAppStartup);
-    forceQuit  = Components.interfaces.nsIAppStartup.eForceQuit;
-  }
-  else if (kAppShell in Components.classes)
-  {
-    appService = Components.classes[kAppShell].
-      getService(Components.interfaces.nsIAppShellService);
-    forceQuit = Components.interfaces.nsIAppShellService.eForceQuit;
-  }
-  else
-  {
-    throw 'goQuitApplication: no AppStartup/appShell';
-  }
-
-  try
-  {
-    appService.quit(forceQuit);
-  }
-  catch(ex)
-  {
-    throw('goQuitApplication: ' + ex);
-  }
-
-  return true;
-}
-
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -57,16 +57,18 @@ const NS_NETWORK_PROTOCOL_CONTRACTID_PRE
           "@mozilla.org/network/protocol;1?name=";
 const NS_XREAPPINFO_CONTRACTID =
           "@mozilla.org/xre/app-info;1";
 const NS_DIRECTORY_SERVICE_CONTRACTID =
           "@mozilla.org/file/directory_service;1";
 const NS_OBSERVER_SERVICE_CONTRACTID =
           "@mozilla.org/observer-service;1";
 
+Components.utils.import("resource://gre/modules/FileUtils.jsm");        
+
 var gLoadTimeout = 0;
 var gTimeoutHook = null;
 var gRemote = false;
 var gIgnoreWindowSize = false;
 var gTotalChunks = 0;
 var gThisChunk = 0;
 var gContainingWindow = null;
 
@@ -256,85 +258,89 @@ function OnRefTestLoad()
     // us.
     RegisterMessageListenersAndLoadContentScript();
 }
 
 function InitAndStartRefTests()
 {
     /* These prefs are optional, so we don't need to spit an error to the log */
     try {
-      var prefs = Components.classes["@mozilla.org/preferences-service;1"].
-                  getService(Components.interfaces.nsIPrefBranch2);
+        var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+                    getService(Components.interfaces.nsIPrefBranch2);
     } catch(e) {
-      gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n");
+        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n");
     }
     
     /* set the gLoadTimeout */
     try {
-      gLoadTimeout = prefs.getIntPref("reftest.timeout");
+        gLoadTimeout = prefs.getIntPref("reftest.timeout");
     } catch(e) { 
-      gLoadTimeout = 5 * 60 * 1000; //5 minutes as per bug 479518
+        gLoadTimeout = 5 * 60 * 1000; //5 minutes as per bug 479518
     }
     
     /* Get the logfile for android tests */
     try {
-      logFile = prefs.getCharPref("reftest.logFile");
-      if (logFile) {
-        try {
-          var mfl = new MozillaFileLogger(logFile);
-          // Set to mirror to stdout as well as the file
-          gDumpLog = function (msg) {dump(msg); mfl.log(msg);};
+        logFile = prefs.getCharPref("reftest.logFile");
+        if (logFile) {
+            try {
+                var f = FileUtils.File(logFile);
+                var mfl = FileUtils.openFileOutputStream(f, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE);  
+                // Set to mirror to stdout as well as the file
+                gDumpLog = function (msg) {
+                    dump(msg); 
+                    mfl.write(msg, msg.length);
+                };
+            }
+            catch(e) {
+                // If there is a problem, just use stdout
+                gDumpLog = dump;
+            }
         }
-        catch(e) {
-          // If there is a problem, just use stdout
-          gDumpLog = dump;
-        }
-      }
     } catch(e) {}
     
     try {
-      gRemote = prefs.getBoolPref("reftest.remote");
+        gRemote = prefs.getBoolPref("reftest.remote");
     } catch(e) { 
-      gRemote = false;
+        gRemote = false;
     }
 
     try {
-      gIgnoreWindowSize = prefs.getBoolPref("reftest.ignoreWindowSize");
+        gIgnoreWindowSize = prefs.getBoolPref("reftest.ignoreWindowSize");
     } catch(e) {
-      gIgnoreWindowSize = false;
+        gIgnoreWindowSize = false;
     }
 
     /* Support for running a chunk (subset) of tests.  In separate try as this is optional */
     try {
-      gTotalChunks = prefs.getIntPref("reftest.totalChunks");
-      gThisChunk = prefs.getIntPref("reftest.thisChunk");
+        gTotalChunks = prefs.getIntPref("reftest.totalChunks");
+        gThisChunk = prefs.getIntPref("reftest.thisChunk");
     }
     catch(e) {
-      gTotalChunks = 0;
-      gThisChunk = 0;
+        gTotalChunks = 0;
+        gThisChunk = 0;
     }
 
     try {
         gWindowUtils = gContainingWindow.QueryInterface(CI.nsIInterfaceRequestor).getInterface(CI.nsIDOMWindowUtils);
         if (gWindowUtils && !gWindowUtils.compareCanvases)
             gWindowUtils = null;
     } catch (e) {
         gWindowUtils = null;
     }
 
     gIOService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService);
     gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
 
     RegisterProcessCrashObservers();
 
     if (gRemote) {
-      gServer = null;
+        gServer = null;
     } else {
-      gServer = CC["@mozilla.org/server/jshttp;1"].
-                    createInstance(CI.nsIHttpServer);
+        gServer = CC["@mozilla.org/server/jshttp;1"].
+                      createInstance(CI.nsIHttpServer);
     }
     try {
         if (gServer)
             StartHTTPServer();
     } catch (ex) {
         //gBrowser.loadURI('data:text/plain,' + ex);
         ++gTestResults.Exception;
         gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
@@ -400,17 +406,16 @@ function StartTests()
         ++gTestResults.Exception;
         gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + ex + "\n");
         DoneTests();
     }
 }
 
 function OnRefTestUnload()
 {
-    MozillaFileLogger.close();
 }
 
 // Read all available data from an input stream and return it
 // as a string.
 function getStreamContent(inputStream)
 {
   var streamBuf = "";
   var sis = CC["@mozilla.org/scriptableinputstream;1"].
@@ -988,17 +993,18 @@ function DoneTests()
              gTestResults.Random + " random, " +
              gTestResults.Skip + " skipped, " +
              gTestResults.Slow + " slow)\n");
 
     gDumpLog("REFTEST INFO | Total canvas count = " + gRecycledCanvases.length + "\n");
 
     gDumpLog("REFTEST TEST-START | Shutdown\n");
     function onStopped() {
-        goQuitApplication();
+        let appStartup = CC["@mozilla.org/toolkit/app-startup;1"].getService(CI.nsIAppStartup);
+        appStartup.quit(CI.nsIAppStartup.eForceQuit);
     }
     if (gServer)
         gServer.stop(onStopped);
     else
         onStopped();
 }
 
 function UpdateCanvasCache(url, canvas)
--- a/layout/tools/reftest/reftest.xul
+++ b/layout/tools/reftest/reftest.xul
@@ -44,13 +44,11 @@
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         id="reftest-window"
         hidechrome="true"
         onload="OnRefTestLoad();"
         onunload="OnRefTestUnload();"
         style="background:white; overflow:hidden"
         >
-    <script type="application/ecmascript" src="quit.js" />
     <script type="application/ecmascript" src="reftest.js" />
-    <script type="application/ecmascript" src="MozillaLogger.js" />
     <!-- The reftest browser element is dynamically created, here -->
 </window>
--- a/mobile/android/base/AutoCompletePopup.java
+++ b/mobile/android/base/AutoCompletePopup.java
@@ -63,16 +63,18 @@ public class AutoCompletePopup extends L
 
     private int mWidth;
     private int mHeight;
 
     private Animation mAnimation; 
 
     private static final String LOGTAG = "AutoCompletePopup";
 
+    private static int sMinWidth = 0;
+
     public AutoCompletePopup(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
 
         mAnimation = AnimationUtils.loadAnimation(context, R.anim.grow_fade_in);
         mAnimation.setDuration(75);
 
         setFocusable(false);
@@ -127,17 +129,28 @@ public class AutoCompletePopup extends L
         int listLeft = left < 0 ? 0 : left;
         int listTop = top + height;
 
         FloatSize viewport = GeckoApp.mAppContext.getLayerController().getViewportSize();
 
         // If the textbox is smaller than the screen-width,
         // shrink the list's width
         if ((left + width) < viewport.width) 
-            listWidth = left + width;
+            listWidth = left < 0 ? left + width : width;
+
+        // Late initializing variable to allow DisplayMetrics not to be null and avoid NPE
+        if (sMinWidth == 0)
+            sMinWidth = 100 * GeckoAppShell.getDpi();
+
+        if (listWidth < sMinWidth) {
+            listWidth = sMinWidth;
+
+            if ((listLeft + listWidth) > viewport.width)
+                listLeft = (int)viewport.width - listWidth;
+        }
 
         // If the list is extending outside of the viewport
         // try moving above
         if (((listTop + listHeight) > viewport.height) && (listHeight <= top))
             listTop = (top - listHeight);
 
         mLayout = new RelativeLayout.LayoutParams(listWidth, listHeight);
         mLayout.setMargins(listLeft, listTop, 0, 0);
--- a/mobile/android/base/AwesomeBar.java
+++ b/mobile/android/base/AwesomeBar.java
@@ -37,33 +37,48 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 package org.mozilla.gecko;
 
 import android.app.Activity;
 import android.app.ActionBar;
 import android.content.Intent;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Configuration;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.KeyEvent;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.EditorInfo;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ImageButton;
 import android.widget.RelativeLayout;
+import android.widget.ListView;
+
+import org.mozilla.gecko.db.BrowserDB.URLColumns;
+import org.mozilla.gecko.db.BrowserDB;
 
 import org.json.JSONArray;
 import org.json.JSONObject;
 
 public class AwesomeBar extends Activity implements GeckoEventListener {
     private static final String LOGTAG = "GeckoAwesomeBar";
 
     static final String URL_KEY = "url";
@@ -196,16 +211,20 @@ public class AwesomeBar extends Activity
             public void onFocusChange(View v, boolean hasFocus) {
                 if (!hasFocus) {
                     InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                     imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                 }
             }
         });
 
+        registerForContextMenu(mAwesomeTabs.findViewById(R.id.all_pages_list));
+        registerForContextMenu(mAwesomeTabs.findViewById(R.id.bookmarks_list));
+        registerForContextMenu(mAwesomeTabs.findViewById(R.id.history_list));
+
         GeckoAppShell.registerGeckoEventListener("SearchEngines:Data", this);
         GeckoAppShell.sendEventToGecko(new GeckoEvent("SearchEngines:Get", null));
     }
 
     public void handleMessage(String event, JSONObject message) {
         try {
             if (event.equals("SearchEngines:Data")) {
                 mAwesomeTabs.setSearchEngines(message.getJSONArray("searchEngines"));
@@ -350,16 +369,81 @@ public class AwesomeBar extends Activity
 
     @Override
     public void onDestroy() {
         super.onDestroy();
         mAwesomeTabs.destroy();
         GeckoAppShell.unregisterGeckoEventListener("SearchEngines:Data", this);
     }
 
+    private Cursor mContextMenuCursor = null;
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
+        super.onCreateContextMenu(menu, view, menuInfo);
+
+        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+        ListView list = (ListView) view;
+        Object selecteditem = list.getItemAtPosition(info.position);
+
+        if (!(selecteditem instanceof Cursor)) {
+            mContextMenuCursor = null;
+            return;
+        }
+
+        mContextMenuCursor = (Cursor) selecteditem;
+
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.awesomebar_contextmenu, menu);
+
+        String title = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.TITLE));
+        menu.setHeaderTitle(title);
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        if (mContextMenuCursor == null)
+            return false;
+
+        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+
+        switch (item.getItemId()) {
+            case R.id.open_new_tab: {
+                String url = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.URL));
+                GeckoApp.mAppContext.loadUrl(url, AwesomeBar.Type.ADD);
+                break;
+            }
+            case R.id.add_to_launcher: {
+                String url = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.URL));
+                byte[] b = (byte[]) mContextMenuCursor.getBlob(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.FAVICON));
+                String title = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.TITLE));
+    
+                Bitmap bitmap = null;
+                if (b != null)
+                    bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
+    
+                GeckoAppShell.createShortcut(title, url, bitmap, "");
+                break;
+            }
+            case R.id.share: {
+                String url = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.URL));
+                String title = mContextMenuCursor.getString(mContextMenuCursor.getColumnIndexOrThrow(URLColumns.TITLE));
+                GeckoAppShell.openUriExternal(url, "text/plain", "", "",
+                                              Intent.ACTION_SEND, title);
+                break;
+            }
+            default: {
+                mContextMenuCursor = null;
+                return super.onContextItemSelected(item);
+            }
+        }
+        mContextMenuCursor = null;
+        return true;
+    }
+
     public static class AwesomeBarEditText extends EditText {
         OnKeyPreImeListener mOnKeyPreImeListener;
 
         public interface OnKeyPreImeListener {
             public boolean onKeyPreIme(View v, int keyCode, KeyEvent event);
         }
 
         public AwesomeBarEditText(Context context, AttributeSet attrs) {
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -33,16 +33,17 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 package org.mozilla.gecko;
 
+import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient;
 import org.mozilla.gecko.gfx.LayerController;
 import org.mozilla.gecko.gfx.LayerView;
 
 import java.io.*;
 import java.lang.reflect.*;
 import java.nio.*;
 import java.nio.channels.*;
@@ -604,38 +605,107 @@ public class GeckoAppShell
     }
     static void scheduleRestart() {
         Log.i(LOGTAG, "scheduling restart");
         gRestartScheduled = true;
     }
 
     // "Installs" an application by creating a shortcut
     static void createShortcut(String aTitle, String aURI, String aIconData, String aType) {
-        Log.w(LOGTAG, "createShortcut for " + aURI + " [" + aTitle + "] > " + aType);
-
-        // the intent to be launched by the shortcut
-        Intent shortcutIntent = new Intent();
-        if (aType.equalsIgnoreCase("webapp")) {
-            shortcutIntent.setAction("org.mozilla.gecko.WEBAPP");
-            shortcutIntent.putExtra("args", "--webapp=" + aURI);
-        } else {
-            shortcutIntent.setAction("org.mozilla.gecko.BOOKMARK");
-            shortcutIntent.putExtra("args", "--url=" + aURI);
-        }
-        shortcutIntent.setClassName(GeckoApp.mAppContext,
-                                    GeckoApp.mAppContext.getPackageName() + ".App");
-
-        Intent intent = new Intent();
-        intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
-        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
         byte[] raw = Base64.decode(aIconData.substring(22), Base64.DEFAULT);
         Bitmap bitmap = BitmapFactory.decodeByteArray(raw, 0, raw.length);
-        intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
-        intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
-        GeckoApp.mAppContext.sendBroadcast(intent);
+        createShortcut(aTitle, aURI, bitmap, aType);
+    }
+
+    public static void createShortcut(final String aTitle, final String aURI, final Bitmap aIcon, final String aType) {
+        getHandler().post(new Runnable() {
+            public void run() {
+                Log.w(LOGTAG, "createShortcut for " + aURI + " [" + aTitle + "] > " + aType);
+        
+                // the intent to be launched by the shortcut
+                Intent shortcutIntent = new Intent();
+                if (aType.equalsIgnoreCase("webapp")) {
+                    shortcutIntent.setAction("org.mozilla.gecko.WEBAPP");
+                    shortcutIntent.putExtra("args", aURI);
+                } else {
+                    shortcutIntent.setAction("org.mozilla.gecko.BOOKMARK");
+                    shortcutIntent.putExtra("args", aURI);
+                }
+                shortcutIntent.setClassName(GeckoApp.mAppContext,
+                                            GeckoApp.mAppContext.getPackageName() + ".App");
+        
+                Intent intent = new Intent();
+                intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
+                if (aTitle != null)
+                    intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
+                else
+                    intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aURI);
+                intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getLauncherIcon(aIcon));
+                intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
+                GeckoApp.mAppContext.sendBroadcast(intent);
+            }
+        });
+    }
+
+    static private Bitmap getLauncherIcon(Bitmap aSource) {
+        // The background images are 72px, but Android will resize as needed.
+        // Bigger is better than too small.
+        final int kIconSize = 72;
+        final int kOverlaySize = 32;
+        final int kOffset = 6;
+        final int kRadius = 5;
+
+        Bitmap bitmap = Bitmap.createBitmap(kIconSize, kIconSize, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+
+        // draw a base color
+        Paint paint = new Paint();
+        
+        if (aSource == null) {
+            float[] hsv = new float[3];
+            hsv[0] = 32.0f;
+            hsv[1] = 1.0f;
+            hsv[2] = 1.0f;
+            paint.setColor(Color.HSVToColor(hsv));
+            canvas.drawRoundRect(new RectF(kOffset, kOffset, kIconSize - kOffset, kIconSize - kOffset), kRadius, kRadius, paint);
+        } else {
+            int color = BitmapUtils.getDominantColor(aSource);
+            paint.setColor(color);
+            canvas.drawRoundRect(new RectF(kOffset, kOffset, kIconSize - kOffset, kIconSize - kOffset), kRadius, kRadius, paint);
+            paint.setColor(Color.argb(100, 255, 255, 255));
+            canvas.drawRoundRect(new RectF(kOffset, kOffset, kIconSize - kOffset, kIconSize - kOffset), kRadius, kRadius, paint);
+        }
+
+        // draw the overlay
+        Bitmap overlay = BitmapFactory.decodeResource(GeckoApp.mAppContext.getResources(), R.drawable.home_bg);
+        canvas.drawBitmap(overlay, null, new Rect(0,0,kIconSize, kIconSize), null);
+
+        // draw the bitmap
+        if (aSource == null)
+            aSource = BitmapFactory.decodeResource(GeckoApp.mAppContext.getResources(), R.drawable.home_star);
+
+        if (aSource.getWidth() < kOverlaySize || aSource.getHeight() < kOverlaySize) {
+            canvas.drawBitmap(aSource,
+                              null,
+                              new Rect(kIconSize/2 - kOverlaySize/2,
+                                       kIconSize/2 - kOverlaySize/2,
+                                       kIconSize/2 + kOverlaySize/2,
+                                       kIconSize/2 + kOverlaySize/2),
+                              null);
+        } else {
+            canvas.drawBitmap(aSource,
+                              null,
+                              new Rect(kIconSize/2 - aSource.getWidth()/2,
+                                       kIconSize/2 - aSource.getHeight()/2,
+                                       kIconSize/2 + aSource.getWidth()/2,
+                                       kIconSize/2 + aSource.getHeight()/2),
+                              null);
+        }
+
+        return bitmap;
     }
 
     static String[] getHandlersForMimeType(String aMimeType, String aAction) {
         Intent intent = getIntentForActionString(aAction);
         if (aMimeType != null && aMimeType.length() > 0)
             intent.setType(aMimeType);
         return getHandlersForIntent(intent);
     }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -78,16 +78,17 @@ JAVAFILES = \
   GlobalHistory.java \
   LinkPreference.java \
   ProfileMigrator.java \
   PromptService.java \
   SurfaceLockInfo.java \
   Tab.java \
   Tabs.java \
   TabsTray.java \
+  gfx/BitmapUtils.java \
   gfx/BufferedCairoImage.java \
   gfx/CairoGLInfo.java \
   gfx/CairoImage.java \
   gfx/CairoUtils.java \
   gfx/FloatSize.java \
   gfx/GeckoSoftwareLayerClient.java \
   gfx/InputConnectionHandler.java \
   gfx/IntSize.java \
@@ -267,16 +268,18 @@ RES_DRAWABLE_MDPI_V8 = \
   res/drawable-mdpi-v8/doorhanger_shadow_bg.9.png \
   res/drawable-mdpi-v8/doorhanger_popup_bg.9.png \
   res/drawable-mdpi-v8/site_security_identified.png \
   res/drawable-mdpi-v8/site_security_verified.png \
   res/drawable-mdpi-v8/urlbar_stop.png \
   $(NULL)
 
 RES_DRAWABLE_HDPI_V8 = \
+  res/drawable-hdpi-v8/home_bg.png \
+  res/drawable-hdpi-v8/home_star.png \
   res/drawable-hdpi-v8/abouthome_icon.png \
   res/drawable-hdpi-v8/abouthome_logo.png \
   res/drawable-hdpi-v8/abouthome_separator.9.png \
   res/drawable-hdpi-v8/abouthome_topsite_placeholder.png \
   res/drawable-hdpi-v8/abouthome_topsite_shadow.9.png \
   res/drawable-hdpi-v8/ic_awesomebar_go.png \
   res/drawable-hdpi-v8/ic_awesomebar_search.png \
   res/drawable-hdpi-v8/ic_menu_bookmark_add.png \
@@ -420,16 +423,20 @@ RES_DRAWABLE_LAND_XHDPI_V14 = \
   res/drawable-land-xhdpi-v14/urlbar_stop.png \
   res/drawable-land-xhdpi-v14/site_security_identified.png \
   res/drawable-land-xhdpi-v14/site_security_verified.png \
   $(NULL)
 
 RES_COLOR = \
   res/color/awesomebar_tab_text.xml
 
+RES_MENU = \
+  res/menu/awesomebar_contextmenu.xml \
+  $(NULL)
+
 AB_rCD = $(shell echo $(AB_CD) | sed -e s/-/-r/)
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
 ifdef MOZ_CRASHREPORTER
 PROCESSEDJAVAFILES += CrashReporter.java
 MOZ_ANDROID_DRAWABLES += mobile/android/base/resources/drawable/crash_reporter.png
 RES_LAYOUT += res/layout/crash_reporter.xml
@@ -590,17 +597,21 @@ RES_DRAWABLE = $(addprefix res/drawable/
 $(RES_DRAWABLE_LAND_XHDPI_V14): $(subst res/,$(srcdir)/resources/,$(RES_DRAWABLE_LAND_XHDPI_V14))
 	$(NSINSTALL) -D res/drawable-land-xhdpi-v14
 	$(NSINSTALL) $(srcdir)/resources/drawable-land-xhdpi-v14/* res/drawable-land-xhdpi-v14/
 
 $(RES_COLOR): $(subst res/,$(srcdir)/resources/,$(RES_COLOR))
 	$(NSINSTALL) -D res/color
 	$(NSINSTALL) $^  res/color
 
-R.java: $(MOZ_APP_ICON) $(RES_LAYOUT) $(RES_LAYOUT_V11) $(RES_DRAWABLE) $(RES_VALUES) $(RES_VALUES_V11) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_NODPI) $(RES_DRAWABLE_MDPI_V8) $(RES_DRAWABLE_HDPI_V8) $(RES_DRAWABLE_MDPI_V9) $(RES_DRAWABLE_HDPI_V9) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_DRAWABLE_LAND_MDPI_V14) $(RES_DRAWABLE_LAND_HDPI_V14) $(RES_DRAWABLE_LAND_XHDPI_V14) $(RES_COLOR) res/drawable/icon.png res/drawable-hdpi/icon.png res/values/strings.xml AndroidManifest.xml
+$(RES_MENU): $(subst res/,$(srcdir)/resources/,$(RES_MENU))
+	$(NSINSTALL) -D res/menu
+	$(NSINSTALL) $^  res/menu
+
+R.java: $(MOZ_APP_ICON) $(RES_LAYOUT) $(RES_LAYOUT_V11) $(RES_DRAWABLE) $(RES_VALUES) $(RES_VALUES_V11) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_NODPI) $(RES_DRAWABLE_MDPI_V8) $(RES_DRAWABLE_HDPI_V8) $(RES_DRAWABLE_MDPI_V9) $(RES_DRAWABLE_HDPI_V9) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_DRAWABLE_LAND_MDPI_V14) $(RES_DRAWABLE_LAND_HDPI_V14) $(RES_DRAWABLE_LAND_XHDPI_V14) $(RES_COLOR) $(RES_MENU) res/drawable/icon.png res/drawable-hdpi/icon.png res/values/strings.xml AndroidManifest.xml
 	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -J . --custom-package org.mozilla.gecko
 
-gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png $(RES_LAYOUT) $(RES_LAYOUT_V11) $(RES_DRAWABLE) $(RES_VALUES) $(RES_VALUES_V11) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_NODPI) $(RES_DRAWABLE_MDPI_V8) $(RES_DRAWABLE_HDPI_V8) $(RES_DRAWABLE_MDPI_V9) $(RES_DRAWABLE_HDPI_V9) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_DRAWABLE_LAND_MDPI_V14) $(RES_DRAWABLE_LAND_HDPI_V14) $(RES_DRAWABLE_LAND_XHDPI_V14) $(RES_COLOR) res/values/strings.xml FORCE
+gecko.ap_: AndroidManifest.xml res/drawable/icon.png res/drawable-hdpi/icon.png $(RES_LAYOUT) $(RES_LAYOUT_V11) $(RES_DRAWABLE) $(RES_VALUES) $(RES_VALUES_V11) $(RES_XML) $(RES_ANIM) $(RES_DRAWABLE_NODPI) $(RES_DRAWABLE_MDPI_V8) $(RES_DRAWABLE_HDPI_V8) $(RES_DRAWABLE_MDPI_V9) $(RES_DRAWABLE_HDPI_V9) $(RES_DRAWABLE_MDPI_V11) $(RES_DRAWABLE_HDPI_V11) $(RES_DRAWABLE_XHDPI_V11) $(RES_DRAWABLE_LAND_MDPI_V14) $(RES_DRAWABLE_LAND_HDPI_V14) $(RES_DRAWABLE_LAND_XHDPI_V14) $(RES_COLOR) $(RES_MENU) res/values/strings.xml FORCE
 	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
 
 libs:: classes.dex package-name.txt
 	$(INSTALL) classes.dex $(FINAL_TARGET)
 	$(INSTALL) package-name.txt $(FINAL_TARGET)
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/gfx/BitmapUtils.java
@@ -0,0 +1,90 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Wes Johnston <wjohnston@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko.gfx;
+
+import android.graphics.Color;
+import android.graphics.Bitmap;
+import java.lang.Math;
+import android.util.Log;
+
+public final class BitmapUtils {
+    public static int getDominantColor(Bitmap source) {
+      int[] colors = new int[37];
+      int[] sat = new int[11];
+      int[] val = new int[11];
+      int maxH = 0;
+      int maxS = 0;
+      int maxV = 0;
+      if (source == null)
+        return Color.argb(255,255,255,255);
+
+      for (int row = 0; row < source.getHeight(); row++) {
+        for (int col = 0; col < source.getWidth(); col++) {
+          int c = source.getPixel(col, row);
+          if (Color.alpha(c) < 128)
+            continue;
+
+          float[] hsv = new float[3];
+          Color.colorToHSV(c, hsv);
+
+          // arbitrarily chosen values for "white" and "black"
+          if (hsv[1] > 0.35f && hsv[2] > 0.35f) {
+            int h = Math.round(hsv[0] / 10.0f);
+            int s = Math.round(hsv[1] * 10.0f);
+            int v = Math.round(hsv[2] * 10.0f);
+            colors[h]++;
+            sat[s]++;
+            val[v]++;
+            // we only care about the most unique non white or black hue, but also
+            // store its saturation and value params to match the color better
+            if (colors[h] > colors[maxH]) {
+              maxH = h;
+              maxS = s;
+              maxV = v;
+            }
+          }
+        }
+      }
+      float[] hsv = new float[3];
+      hsv[0] = maxH*10.0f;
+      hsv[1] = (float)maxS/10.0f;
+      hsv[2] = (float)maxV/10.0f;
+      return Color.HSVToColor(hsv);
+    }
+}
+
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -76,12 +76,16 @@
 
 <!ENTITY addons "Add-ons">
 
 <!ENTITY share "Share">
 <!ENTITY save_as_pdf "Save as PDF">
 <!ENTITY agent_request_desktop "Request Desktop Site">
 <!ENTITY agent_request_mobile "Request Mobile Site">
 
+<!ENTITY contextmenu_open_new_tab "Open in New Tab">
+<!ENTITY contextmenu_add_to_launcher "Add to Home Screen">
+<!ENTITY contextmenu_share "Share">
+
 <!ENTITY site_settings_title        "Clear Site Settings">
 <!ENTITY site_settings_cancel       "Cancel">
 <!ENTITY site_settings_clear        "Clear">
 <!ENTITY site_settings_no_settings  "There are no settings to clear.">
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8020939e00c853025012a2b2ae0353fe74d54b3a
GIT binary patch
literal 2169
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ef4ecf728019a8df5b8edf9049c6c9f35f54d8f0
GIT binary patch
literal 4040
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
--- a/mobile/android/base/resources/drawable/awesomebar_tab_focus.xml
+++ b/mobile/android/base/resources/drawable/awesomebar_tab_focus.xml
@@ -1,17 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@android:color/transparent"/>
-            <size android:height="48dip"/>
-        </shape>
-    </item>
-
     <item android:top="46dip">
         <shape android:shape="rectangle">
             <solid android:color="#000000"/>
         </shape>
     </item>
 
 </layer-list>
--- a/mobile/android/base/resources/drawable/awesomebar_tab_focus_selected.xml
+++ b/mobile/android/base/resources/drawable/awesomebar_tab_focus_selected.xml
@@ -1,17 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@android:color/transparent"/>
-            <size android:height="48dip"/>
-        </shape>
-    </item>
-
     <item android:top="36dip">
         <shape android:shape="rectangle">
             <solid android:color="#111111"/>
         </shape>
     </item>
 
 </layer-list>
--- a/mobile/android/base/resources/drawable/awesomebar_tab_press.xml
+++ b/mobile/android/base/resources/drawable/awesomebar_tab_press.xml
@@ -1,17 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@android:color/transparent"/>
-            <size android:height="48dip"/>
-        </shape>
-    </item>
-
     <item android:top="46dip">
         <shape android:shape="rectangle">
             <solid android:color="#111111"/>
         </shape>
     </item>
 
 </layer-list>
--- a/mobile/android/base/resources/drawable/awesomebar_tab_press_selected.xml
+++ b/mobile/android/base/resources/drawable/awesomebar_tab_press_selected.xml
@@ -1,17 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@android:color/transparent"/>
-            <size android:height="48dip"/>
-        </shape>
-    </item>
-
     <item android:top="36dip">
         <shape android:shape="rectangle">
             <solid android:color="#111111"/>
         </shape>
     </item>
 
 </layer-list>
--- a/mobile/android/base/resources/drawable/awesomebar_tab_selected.xml
+++ b/mobile/android/base/resources/drawable/awesomebar_tab_selected.xml
@@ -1,17 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@android:color/transparent"/>
-            <size android:height="48dip"/>
-        </shape>
-    </item>
-
     <item android:top="36dip">
         <shape android:shape="rectangle">
             <solid android:color="#000000"/>
         </shape>
     </item>
 
 </layer-list>
--- a/mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml
+++ b/mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml
@@ -1,17 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="@android:color/transparent"/>
-            <size android:height="48dip"/>
-        </shape>
-    </item>
-
     <item android:top="46dip">
         <shape android:shape="rectangle">
             <solid android:color="#000000"/>
         </shape>
     </item>
 
 </layer-list>
--- a/mobile/android/base/resources/layout-v11/awesomebar_search_actionbar.xml
+++ b/mobile/android/base/resources/layout-v11/awesomebar_search_actionbar.xml
@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:background="@color/awesomebar_background">
+                android:background="@drawable/tabs_tray_bg_repeat">
 
     <view class="org.mozilla.gecko.AwesomeBar$AwesomeBarEditText"
           android:id="@+id/awesomebar_text"
           style="@style/AddressBar.Button"
           android:layout_width="fill_parent"
           android:layout_alignParentBottom="true"
           android:layout_centerVertical="true"
           android:paddingLeft="15dip"
--- a/mobile/android/base/resources/layout/awesomebar_search.xml
+++ b/mobile/android/base/resources/layout/awesomebar_search.xml
@@ -1,15 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:id="@+id/awesome_screen"
               style="@style/Screen">
 
     <RelativeLayout style="@style/AddressBar"
-                    android:background="@color/awesomebar_background">
+                    android:background="@drawable/tabs_tray_bg_repeat">
 
         <view class="org.mozilla.gecko.AwesomeBar$AwesomeBarEditText"
               android:id="@+id/awesomebar_text"
               style="@style/AddressBar.Button"
               android:layout_width="fill_parent"
               android:layout_alignParentBottom="true"
               android:layout_centerVertical="true"
               android:paddingLeft="15dip"
--- a/mobile/android/base/resources/layout/awesomebar_tabs.xml
+++ b/mobile/android/base/resources/layout/awesomebar_tabs.xml
@@ -2,18 +2,18 @@
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <LinearLayout android:orientation="vertical"
                   android:layout_width="fill_parent"
                   android:layout_height="fill_parent">
 
         <TabWidget android:id="@android:id/tabs"
                    android:layout_width="fill_parent"
-                   android:layout_height="wrap_content"
-                   android:background="@color/awesomebar_background"/>
+                   android:layout_height="48dip"
+                   android:background="@drawable/tabs_tray_bg_repeat"/>
 
         <FrameLayout android:id="@android:id/tabcontent"
                      android:layout_width="fill_parent"
                      android:layout_height="fill_parent">
 
             <ListView android:id="@+id/all_pages_list"
                       style="@style/AwesomeBarList"/>
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/menu/awesomebar_contextmenu.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:id="@+id/open_new_tab"
+          android:title="@string/contextmenu_open_new_tab"/>
+
+    <item android:id="@+id/share"
+          android:title="@string/contextmenu_share"/>
+
+    <item android:id="@+id/add_to_launcher"
+          android:title="@string/contextmenu_add_to_launcher"/>
+
+</menu>
--- a/mobile/android/base/resources/values/colors.xml
+++ b/mobile/android/base/resources/values/colors.xml
@@ -1,9 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
   <color name="splash_background">#000000</color>
   <color name="splash_msgfont">#ffffff</color>
   <color name="splash_urlfont">#000000</color>
   <color name="splash_content">#ffffff</color>
-  <color name="awesomebar_background">#000000</color>
 </resources>
 
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -82,9 +82,13 @@
   <string name="forward">&forward;</string>
   <string name="new_tab">&new_tab;</string>
   <string name="addons">&addons;</string>
 
   <string name="site_settings_title">&site_settings_title;</string>
   <string name="site_settings_cancel">&site_settings_cancel;</string>
   <string name="site_settings_clear">&site_settings_clear;</string>
   <string name="site_settings_no_settings">&site_settings_no_settings;</string>
+
+  <string name="contextmenu_open_new_tab">&contextmenu_open_new_tab;</string>
+  <string name="contextmenu_add_to_launcher">&contextmenu_add_to_launcher;</string>
+  <string name="contextmenu_share">&contextmenu_share;</string>
 </resources>
--- a/mobile/xul/app/mobile.js
+++ b/mobile/xul/app/mobile.js
@@ -78,18 +78,16 @@ pref("browser.viewport.desktopWidth", 98
 #ifndef MOZ_PLATFORM_MAEMO
 // On desktop builds, simulate an MDPI tablet by default.
 pref("layout.css.dpi", 160);
 #else
 // Maemo X11 lies about its dpi
 pref("layout.css.dpi", 240);
 #endif
 #endif
-/* allow scrollbars to float above chrome ui */
-pref("ui.scrollbarsCanOverlapContent", 1);
 
 /* use long press to display a context menu */
 pref("ui.click_hold_context_menus", true);
 
 /* cache prefs */
 pref("browser.cache.disk.enable", true);
 pref("browser.cache.disk.capacity", 10240); // kilobytes
 pref("browser.cache.disk.smart_size.enabled", false);
--- a/widget/public/LookAndFeel.h
+++ b/widget/public/LookAndFeel.h
@@ -214,18 +214,16 @@ public:
     // show the caret when text is selected?
     eIntID_ShowCaretDuringSelection,
     // select textfields when focused via tab/accesskey?
     eIntID_SelectTextfieldsOnKeyFocus,
     // delay before submenus open
     eIntID_SubmenuDelay,
     // can popups overlap menu/task bar?
     eIntID_MenusCanOverlapOSBar,
-    // can scrollbars float above content?
-    eIntID_ScrollbarsCanOverlapContent,
     // skip navigating to disabled menu item?
     eIntID_SkipNavigatingDisabledMenuItem,
     // begin a drag if the mouse is moved further than the threshold while the
     // button is down
     eIntID_DragThresholdX,
     eIntID_DragThresholdY,
     // Accessibility theme being used?
     eIntID_UseAccessibilityTheme,
--- a/widget/src/xpwidgets/nsXPLookAndFeel.cpp
+++ b/widget/src/xpwidgets/nsXPLookAndFeel.cpp
@@ -72,19 +72,16 @@ nsLookAndFeelIntPref nsXPLookAndFeel::sI
     eIntID_DragThresholdX,
     false, 0 },
   { "ui.dragThresholdY",
     eIntID_DragThresholdY,
     false, 0 },
   { "ui.useAccessibilityTheme",
     eIntID_UseAccessibilityTheme,
     false, 0 },
-  { "ui.scrollbarsCanOverlapContent",
-    eIntID_ScrollbarsCanOverlapContent,
-    false, 0 },
   { "ui.menusCanOverlapOSBar",
     eIntID_MenusCanOverlapOSBar,
     false, 0 },
   { "ui.skipNavigatingDisabledMenuItem",
     eIntID_SkipNavigatingDisabledMenuItem,
     false, 0 },
   { "ui.treeOpenDelay",
     eIntID_TreeOpenDelay,