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 83782 a8506ab2c654
parent 83765 c7101dec8deb (current diff)
parent 83781 eeb4b35a1ea8 (diff)
child 83783 00dc96a6c12b
push idunknown
push userunknown
push dateunknown
milestone11.0a1
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,