Bug 545812 - DOM/content changes required for DOM full-screen API. r=jst
authorChris Pearce <chris@pearce.org.nz>
Mon, 05 Sep 2011 08:39:05 +1200
changeset 76532 f212867dce42ff6aa6d63c76570d5eb4a3c9f5f8
parent 76531 81ebc148aad38f3bf5a1712927c97a6d6692767b
child 76533 8794e3692ee86a90940c4a376801324f8abc7deb
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersjst
bugs545812
milestone9.0a1
Bug 545812 - DOM/content changes required for DOM full-screen API. r=jst
content/base/public/nsContentUtils.h
content/base/public/nsIDocument.h
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
dom/base/nsGlobalWindow.cpp
dom/interfaces/core/nsIDOMDocument.idl
dom/interfaces/html/nsIDOMNSHTMLElement.idl
modules/libpref/src/init/all.js
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1695,16 +1695,21 @@ public:
   /**
    * Determine whether a content node is focused or not,
    *
    * @param aContent the content node to check
    * @return true if the content node is focused, false otherwise.
    */
   static PRBool IsFocusedContent(const nsIContent *aContent);
 
+  /**
+   * Returns PR_TRUE if the DOM full-screen API is enabled.
+   */
+  static PRBool IsFullScreenApiEnabled();
+
   static void GetShiftText(nsAString& text);
   static void GetControlText(nsAString& text);
   static void GetMetaText(nsAString& text);
   static void GetAltText(nsAString& text);
   static void GetModifierSeparatorText(nsAString& text);
 
   /**
    * Returns if aContent has a tabbable subdocument.
@@ -1859,16 +1864,17 @@ private:
   static nsTArray< nsCOMPtr<nsIRunnable> >* sBlockedScriptRunners;
   static PRUint32 sRunnersCountAtFirstBlocker;
   static PRUint32 sScriptBlockerCountWhereRunnersPrevented;
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
   static PRBool sIsHandlingKeyBoardEvent;
   static PRBool sAllowXULXBL_for_file;
+  static PRBool sIsFullScreenApiEnabled;
 
   static nsHtml5Parser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   static nsString* sShiftText;
   static nsString* sControlText;
   static nsString* sMetaText;
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -122,18 +122,18 @@ class Loader;
 namespace dom {
 class Link;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 
 #define NS_IDOCUMENT_IID      \
-{ 0x455e4d79, 0x756b, 0x4f73,  \
- { 0x95, 0xea, 0x3f, 0xf6, 0x0c, 0x6a, 0x8c, 0xa6 } }
+{ 0x15d92ce2, 0x472a, 0x4ea7,  \
+ { 0xaf, 0x29, 0x47, 0x7b, 0xac, 0x98, 0xa0, 0x43 } }
 
 // Flag for AddStyleSheet().
 #define NS_STYLESHEET_FROM_CATALOG                (1 << 0)
 
 // Document states
 
 // RTL locale: specific to the XUL localedir attribute
 #define NS_DOCUMENT_STATE_RTL_LOCALE              NS_DEFINE_EVENT_STATE_MACRO(0)
@@ -737,16 +737,47 @@ public:
   /**
    * Add/Remove an element to the document's id and name hashes
    */
   virtual void AddToIdTable(Element* aElement, nsIAtom* aId) = 0;
   virtual void RemoveFromIdTable(Element* aElement, nsIAtom* aId) = 0;
   virtual void AddToNameTable(Element* aElement, nsIAtom* aName) = 0;
   virtual void RemoveFromNameTable(Element* aElement, nsIAtom* aName) = 0;
 
+  /**
+   * Resets the current full-screen element to nsnull.
+   */
+  virtual void ResetFullScreenElement() = 0;
+
+  /**
+   * Returns the element which either is the full-screen element, or
+   * contains the full-screen element if a child of this document contains
+   * the fullscreen element.
+   */
+  virtual Element* GetFullScreenElement() = 0;
+
+  /**
+   * Requests that the document make aElement the full-screen element,
+   * and move into full-screen mode.
+   */
+  virtual void RequestFullScreen(Element* aElement) = 0;
+
+  /**
+   * Updates the full-screen status on this document, setting the full-screen
+   * mode to aIsFullScreen. This doesn't affect the window's full-screen mode,
+   * this updates the document's internal state which determines whether the
+   * document reports as being in full-screen mode.
+   */
+  virtual void UpdateFullScreenStatus(PRBool aIsFullScreen) = 0;
+
+  /**
+   * Returns PR_TRUE if this document is in full-screen mode.
+   */
+  virtual PRBool IsFullScreenDoc() = 0;
+
   //----------------------------------------------------------------------
 
   // Document notification API's
 
   /**
    * Add a new observer of document change notifications. Whenever
    * content is changed, appended, inserted or removed the observers are
    * informed.  An observer that is already observing the document must
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -256,16 +256,17 @@ PRBool nsContentUtils::sAllowXULXBL_for_
 
 nsString* nsContentUtils::sShiftText = nsnull;
 nsString* nsContentUtils::sControlText = nsnull;
 nsString* nsContentUtils::sMetaText = nsnull;
 nsString* nsContentUtils::sAltText = nsnull;
 nsString* nsContentUtils::sModifierSeparator = nsnull;
 
 PRBool nsContentUtils::sInitialized = PR_FALSE;
+PRBool nsContentUtils::sIsFullScreenApiEnabled = PR_FALSE;
 
 nsHtml5Parser* nsContentUtils::sHTMLFragmentParser = nsnull;
 nsIParser* nsContentUtils::sXMLFragmentParser = nsnull;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nsnull;
 
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
@@ -379,16 +380,19 @@ nsContentUtils::Init()
     }
   }
 
   sBlockedScriptRunners = new nsTArray< nsCOMPtr<nsIRunnable> >;
 
   Preferences::AddBoolVarCache(&sAllowXULXBL_for_file,
                                "dom.allow_XUL_XBL_for_file");
 
+  Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled,
+                               "full-screen-api.enabled");
+
   sInitialized = PR_TRUE;
 
   return NS_OK;
 }
 
 void
 nsContentUtils::GetShiftText(nsAString& text)
 {
@@ -5691,8 +5695,14 @@ nsContentUtils::IsPatternMatching(nsAStr
   JSBool res;
 
   res = JS_ExecuteRegExpNoStatics(ctx, re, reinterpret_cast<jschar*>
                                     (aValue.BeginWriting()),
                                   aValue.Length(), &idx, JS_TRUE, &rval);
 
   return res == JS_FALSE || rval != JSVAL_NULL;
 }
+
+PRBool
+nsContentUtils::IsFullScreenApiEnabled()
+{
+  return sIsFullScreenApiEnabled;
+}
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1539,16 +1539,17 @@ nsDOMImplementation::CreateHTMLDocument(
 // ==================================================================
 
   // NOTE! nsDocument::operator new() zeroes out all members, so don't
   // bother initializing members to 0.
 
 nsDocument::nsDocument(const char* aContentType)
   : nsIDocument()
   , mAnimatingImages(PR_TRUE)
+  , mIsFullScreen(PR_FALSE)
 {
   SetContentTypeInternal(nsDependentCString(aContentType));
   
 #ifdef PR_LOGGING
   if (!gDocumentLeakPRLog)
     gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak");
 
   if (gDocumentLeakPRLog)
@@ -1866,16 +1867,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLayoutHistoryState)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnloadBlocker)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstBaseNodeWithHref)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMImplementation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mImageMaps,
                                                        nsIDOMNodeList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOriginalDocument)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCachedEncoder)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFullScreenElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStateObjectCached)
 
   // Traverse all our nsCOMArrays.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mStyleSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCatalogSheets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPreloadingImages)
 
   for (PRUint32 i = 0; i < tmp->mAnimationFrameListeners.Length(); ++i) {
@@ -1922,16 +1924,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mXPathEvaluatorTearoff)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootElement)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDisplayDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstBaseNodeWithHref)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDOMImplementation)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImageMaps)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOriginalDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedEncoder)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFullScreenElement)
 
   tmp->mParentDocument = nsnull;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPreloadingImages)
 
   
   if (tmp->mBoxObjectTable) {
    tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nsnull);
@@ -8454,16 +8457,183 @@ nsIDocument::SizeOf() const
   for (nsIContent* node = GetFirstChild(); node;
        node = node->GetNextNode(this)) {
     size += node->SizeOf();
   }
 
   return size;
 }
 
+// Returns the root document in a document hierarchy.
+static nsIDocument*
+GetRootDocument(nsIDocument* aDoc)
+{
+  if (!aDoc) {
+    return nsnull;
+  }
+  nsCOMPtr<nsIPresShell> shell = aDoc->GetShell();
+  if (!shell) {
+    return nsnull;
+  }
+  nsPresContext* ctx = shell->GetPresContext();
+  if (!ctx) {
+    return nsnull;
+  }
+  nsRootPresContext* rpc = ctx->GetRootPresContext();
+  if (!rpc) {
+    return nsnull;
+  }
+  return rpc->Document();
+}
+
+void
+nsDocument::UpdateFullScreenStatus(PRBool aIsFullScreen)
+{
+  mIsFullScreen = aIsFullScreen;
+  if (!mIsFullScreen) {
+    // Full-screen is being turned off. Reset the full-screen element, to
+    // save us from having to traverse the document hierarchy again in
+    // MozCancelFullScreen().
+    ResetFullScreenElement();
+  }
+}
+
+static PRBool
+UpdateFullScreenStatus(nsIDocument* aDocument, void* aData)
+{
+  aDocument->UpdateFullScreenStatus(*static_cast<PRBool*>(aData));
+  aDocument->EnumerateSubDocuments(UpdateFullScreenStatus, aData);
+  return PR_TRUE;
+}
+
+static void
+UpdateFullScreenStatusInDocTree(nsIDocument* aDoc, PRBool aIsFullScreen)
+{
+  nsIDocument* root = GetRootDocument(aDoc);
+  if (root) {
+    UpdateFullScreenStatus(root, static_cast<void*>(&aIsFullScreen));
+  }
+}
+
+void
+nsDocument::ResetFullScreenElement()
+{
+  mFullScreenElement = nsnull;
+}
+
+static PRBool
+ResetFullScreenElement(nsIDocument* aDocument, void* aData)
+{
+  aDocument->ResetFullScreenElement();
+  aDocument->EnumerateSubDocuments(ResetFullScreenElement, aData);
+  return PR_TRUE;
+}
+
+static void
+ResetFullScreenElementInDocTree(nsIDocument* aDoc)
+{
+  nsIDocument* root = GetRootDocument(aDoc);
+  if (root) {
+    ResetFullScreenElement(root, nsnull);
+  }
+}
+
+NS_IMETHODIMP
+nsDocument::MozCancelFullScreen()
+{
+  if (!nsContentUtils::IsFullScreenApiEnabled() ||
+      !IsFullScreenDoc() ||
+      !GetWindow()) {
+    return NS_OK;
+  }
+
+  // Disable full-screen mode in all documents in this hierarchy.
+  UpdateFullScreenStatusInDocTree(this, PR_FALSE);
+
+  // Move the window out of full-screen mode.
+  GetWindow()->SetFullScreen(PR_FALSE);
+
+  return NS_OK;
+}
+
+PRBool
+nsDocument::IsFullScreenDoc()
+{
+  return nsContentUtils::IsFullScreenApiEnabled() && mIsFullScreen;
+}
+
+void
+nsDocument::RequestFullScreen(Element* aElement)
+{
+  if (!aElement || !nsContentUtils::IsFullScreenApiEnabled() || !GetWindow()) {
+    return;
+  }
+
+  // Reset the full-screen elements of every document in this document
+  // hierarchy.
+  ResetFullScreenElementInDocTree(this);
+  
+  if (aElement->IsInDoc()) {
+    // Propagate up the document hierarchy, setting the full-screen element as
+    // the element's container in ancestor documents. Note we don't propagate
+    // down the document hierarchy, the full-screen element (or its container)
+    // is not visible there.
+    mFullScreenElement = aElement;
+    nsIDocument* child = this;
+    nsIDocument* parent;
+    while (parent = child->GetParentDocument()) {
+      nsIContent* content = parent->FindContentForSubDocument(child);
+      nsCOMPtr<Element> element(do_QueryInterface(content));
+      static_cast<nsDocument*>(parent)->mFullScreenElement = element;
+      child = parent;
+    }
+  }
+
+  // Set all documents in hierarchy to full-screen mode.
+  UpdateFullScreenStatusInDocTree(this, PR_TRUE);
+
+  // Make the window full-screen. Note we must make the state changes above
+  // before making the window full-screen, as then the document reports as
+  // being in full-screen mode when the Chrome "fullscreen" event fires,
+  // enabling browser.js to distinguish between browser and dom full-screen
+  // modes.
+  GetWindow()->SetFullScreen(PR_TRUE);
+}
+
+NS_IMETHODIMP
+nsDocument::GetMozFullScreenElement(nsIDOMHTMLElement **aFullScreenElement)
+{
+  NS_ENSURE_ARG_POINTER(aFullScreenElement);
+  if (!nsContentUtils::IsFullScreenApiEnabled() || !IsFullScreenDoc()) {
+    *aFullScreenElement = nsnull;
+    return NS_OK;
+  }
+  nsCOMPtr<nsIDOMHTMLElement> e(do_QueryInterface(GetFullScreenElement()));
+  NS_IF_ADDREF(*aFullScreenElement = e);
+  return NS_OK;
+}
+
+Element*
+nsDocument::GetFullScreenElement()
+{
+  if (!nsContentUtils::IsFullScreenApiEnabled() ||
+      (mFullScreenElement && !mFullScreenElement->IsInDoc())) {
+    return nsnull;
+  }
+  return mFullScreenElement;
+}
+
+NS_IMETHODIMP
+nsDocument::GetMozFullScreen(PRBool *aFullScreen)
+{
+  NS_ENSURE_ARG_POINTER(aFullScreen);
+  *aFullScreen = nsContentUtils::IsFullScreenApiEnabled() && IsFullScreenDoc();
+  return NS_OK;
+}
+
 PRInt64
 nsDocument::SizeOf() const
 {
   PRInt64 size = MemoryReporter::GetBasicSize<nsDocument, nsIDocument>(this);
   size += mAttrStyleSheet ? mAttrStyleSheet->DOMSizeOf() : 0;
   return size;
 }
 
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -936,16 +936,22 @@ public:
 
   virtual nsresult GetStateObject(nsIVariant** aResult);
 
   virtual nsDOMNavigationTiming* GetNavigationTiming() const;
   virtual nsresult SetNavigationTiming(nsDOMNavigationTiming* aTiming);
 
   virtual Element* FindImageMap(const nsAString& aNormalizedMapName);
 
+  virtual void ResetFullScreenElement();
+  virtual Element* GetFullScreenElement();
+  virtual void RequestFullScreen(Element* aElement);
+  virtual void UpdateFullScreenStatus(PRBool aIsFullScreen);
+  virtual PRBool IsFullScreenDoc();
+
 protected:
   friend class nsNodeUtils;
 
   /**
    * Check that aId is not empty and log a message to the console
    * service if it is.
    * @returns PR_TRUE if aId looks correct, PR_FALSE otherwise.
    */
@@ -1073,16 +1079,19 @@ protected:
    */
   nsTHashtable<nsIdentifierMapEntry> mIdentifierMap;
 
   nsClassHashtable<nsStringHashKey, nsRadioGroupStruct> mRadioGroups;
 
   // Recorded time of change to 'loading' state.
   mozilla::TimeStamp mLoadingTimeStamp;
 
+  // The current full-screen element of this document.
+  nsCOMPtr<Element> mFullScreenElement;
+
   // True if the document has been detached from its content viewer.
   PRPackedBool mIsGoingAway:1;
   // True if the document is being destroyed.
   PRPackedBool mInDestructor:1;
 
   // True if this document has ever had an HTML or SVG <title> element
   // bound to it
   PRPackedBool mMayHaveTitleElement:1;
@@ -1105,16 +1114,19 @@ protected:
   PRPackedBool mLoadedAsInteractiveData:1;
 
   // Whether we're currently holding a lock on all of our images.
   PRPackedBool mLockingImages:1;
 
   // Whether we currently require our images to animate
   PRPackedBool mAnimatingImages:1;
 
+  // Whether we are currently in full-screen mode, as per the DOM API.
+  PRPackedBool mIsFullScreen:1;
+
   PRUint8 mXMLDeclarationBits;
 
   PRUint8 mDefaultElementType;
 
   nsInterfaceHashtable<nsVoidPtrHashKey, nsPIBoxObject> *mBoxObjectTable;
 
   // The channel that got passed to StartDocumentLoad(), if any
   nsCOMPtr<nsIChannel> mChannel;
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -3374,16 +3374,39 @@ nsGenericHTMLElement::Blur()
 nsresult
 nsGenericHTMLElement::Focus()
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
   return fm ? fm->SetFocus(elem, 0) : NS_OK;
 }
 
+nsresult nsGenericHTMLElement::MozRequestFullScreen()
+{
+  if (!nsContentUtils::IsFullScreenApiEnabled()) {
+    return NS_OK;
+  }
+
+  nsIDocument* doc = GetOwnerDoc();
+  NS_ENSURE_STATE(doc);
+  doc->RequestFullScreen(this);
+#ifdef DEBUG
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(doc->GetWindow());
+  NS_ENSURE_STATE(window);
+  PRBool fullscreen;
+  window->GetFullScreen(&fullscreen);
+  NS_ASSERTION(fullscreen, "Windows should report fullscreen");
+  nsCOMPtr<nsIDOMDocument> domDocument(do_QueryInterface(doc));
+  domDocument->GetMozFullScreen(&fullscreen);
+  NS_ASSERTION(fullscreen, "Document should report fullscreen");
+  NS_ASSERTION(doc->IsFullScreenDoc(), "Should be in full screen state!");
+#endif
+  return NS_OK;
+}
+
 nsresult nsGenericHTMLElement::Click()
 {
   if (HasFlag(NODE_HANDLING_CLICK))
     return NS_OK;
 
   // Strong in case the event kills it
   nsCOMPtr<nsIDocument> doc = GetCurrentDoc();
 
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -134,16 +134,17 @@ public:
   nsresult GetOffsetWidth(PRInt32* aOffsetWidth);
   nsresult GetOffsetHeight(PRInt32* aOffsetHeight);
   nsresult GetOffsetParent(nsIDOMElement** aOffsetParent);
   virtual nsresult GetInnerHTML(nsAString& aInnerHTML);
   virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
   virtual nsresult InsertAdjacentHTML(const nsAString& aPosition,
                                       const nsAString& aText);
   nsresult ScrollIntoView(PRBool aTop, PRUint8 optional_argc);
+  nsresult MozRequestFullScreen();
   // Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetHidden(),
   // SetHidden(), GetSpellcheck(), SetSpellcheck(), and GetDraggable() such that
   // classes that inherit interfaces with those methods properly override them.
   NS_IMETHOD Focus();
   NS_IMETHOD Blur();
   NS_IMETHOD Click();
   NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex);
   NS_IMETHOD SetTabIndex(PRInt32 aTabIndex);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4401,19 +4401,21 @@ NS_IMETHODIMP
 nsGlobalWindow::SetFullScreen(PRBool aFullScreen)
 {
   FORWARD_TO_OUTER(SetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
 
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
   PRBool rootWinFullScreen;
   GetFullScreen(&rootWinFullScreen);
-  // Only chrome can change our fullScreen mode.
-  if (aFullScreen == rootWinFullScreen || 
-      !nsContentUtils::IsCallerTrustedForWrite()) {
+  // Only chrome can change our fullScreen mode, unless the DOM full-screen
+  // API is enabled.
+  if ((aFullScreen == rootWinFullScreen || 
+      !nsContentUtils::IsCallerTrustedForWrite()) &&
+      !nsContentUtils::IsFullScreenApiEnabled()) {
     return NS_OK;
   }
 
   // SetFullScreen needs to be called on the root window, so get that
   // via the DocShell tree, and if we are not already the root,
   // call SetFullScreen on that window instead.
   nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
@@ -4453,16 +4455,24 @@ nsGlobalWindow::SetFullScreen(PRBool aFu
   // Set this before so if widget sends an event indicating its
   // gone full screen, the state trap above works.
   mFullScreen = aFullScreen;
 
   nsCOMPtr<nsIWidget> widget = GetMainWidget();
   if (widget)
     widget->MakeFullScreen(aFullScreen);
 
+  if (!mFullScreen && mDocument) {
+    // Notify the document that we've left full-screen mode. This is so that
+    // if we're in full-screen mode and the user exits full-screen mode with
+    // the browser full-screen mode toggle keyboard-shortcut, we detect that
+    // and leave DOM API full-screen mode too.
+    mDocument->MozCancelFullScreen();
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetFullScreen(PRBool* aFullScreen)
 {
   FORWARD_TO_OUTER(GetFullScreen, (aFullScreen), NS_ERROR_NOT_INITIALIZED);
 
--- a/dom/interfaces/core/nsIDOMDocument.idl
+++ b/dom/interfaces/core/nsIDOMDocument.idl
@@ -58,17 +58,17 @@ interface nsIDOMCaretPosition;
  * cannot exist outside the context of a Document, the nsIDOMDocument 
  * interface also contains the factory methods needed to create these 
  * objects.
  *
  * For more information on this interface please see 
  * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
  */
 
-[scriptable, uuid(d19897dc-948a-42e7-8ac6-d8a0bd141b85)]
+[scriptable, uuid(903493d3-72b6-4416-b930-fbfc17ef1d87)]
 interface nsIDOMDocument : nsIDOMNode
 {
   readonly attribute nsIDOMDocumentType         doctype;
   readonly attribute nsIDOMDOMImplementation    implementation;
   readonly attribute nsIDOMElement              documentElement;
   nsIDOMElement                 createElement(in DOMString tagName)
                                   raises(DOMException);
   nsIDOMDocumentFragment        createDocumentFragment();
@@ -366,9 +366,33 @@ interface nsIDOMDocument : nsIDOMNode
    * unregister the image element ID |aImageElementId|.
    *
    * @see <https://developer.mozilla.org/en/DOM/document.mozSetImageElement>
    */
   void mozSetImageElement(in DOMString aImageElementId,
                           in nsIDOMElement aImageElement);
 
   nsIDOMCaretPosition caretPositionFromPoint(in float x, in float y);
+  
+  /**
+   * Element which is currently the full-screen element as per the DOM
+   * full-screen api.
+   *
+   * @see <https://wiki.mozilla.org/index.php?title=Gecko:FullScreenAPI>
+   */
+  readonly attribute nsIDOMHTMLElement mozFullScreenElement;
+
+  /**
+   * Causes the document to leave DOM full-screen mode, if it's in
+   * full-screen mode, as per the DOM full-screen api.
+   *
+   * @see <https://wiki.mozilla.org/index.php?title=Gecko:FullScreenAPI>
+   */
+  void mozCancelFullScreen();   
+  
+  /**
+   * Denotes whether this document is in DOM full-screen mode, as per the DOM
+   * full-screen api.
+   *
+   * @see <https://wiki.mozilla.org/index.php?title=Gecko:FullScreenAPI>
+   */
+  readonly attribute boolean mozFullScreen;  
 };
--- a/dom/interfaces/html/nsIDOMNSHTMLElement.idl
+++ b/dom/interfaces/html/nsIDOMNSHTMLElement.idl
@@ -36,17 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
 interface nsIDOMDOMStringMap;
 interface nsIDOMHTMLMenuElement;
 
-[scriptable, uuid(0c3b4b63-30b2-4c93-906d-f983ee9af584)]
+[scriptable, uuid(38305156-007a-4b68-8592-b1c3625c6f6c)]
 interface nsIDOMNSHTMLElement : nsISupports
 {
   readonly attribute long             offsetTop;
   readonly attribute long             offsetLeft;
   readonly attribute long             offsetWidth;
   readonly attribute long             offsetHeight;
   readonly attribute nsIDOMElement    offsetParent;
            attribute DOMString        innerHTML;
@@ -71,9 +71,17 @@ interface nsIDOMNSHTMLElement : nsISuppo
                           raises(DOMException);
 
   [optional_argc] void scrollIntoView([optional] in boolean top);
 
   readonly attribute nsIDOMHTMLMenuElement contextMenu;
            attribute boolean         spellcheck;
 
   readonly attribute nsIDOMDOMStringMap dataset;
+  
+  /**
+   * Requests that this element be made the full-screen element, as per the DOM
+   * full-screen api.
+   *
+   * @see <https://wiki.mozilla.org/index.php?title=Gecko:FullScreenAPI>
+   */
+           void                       mozRequestFullScreen();  
 };
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3341,11 +3341,14 @@ pref("network.buffer.cache.size",  32768
 // Desktop Notification
 pref("notification.feature.enabled", false);
 
 // Alert sliding effect
 pref("alerts.slideIncrement", 1);
 pref("alerts.slideIncrementTime", 10);
 pref("alerts.totalOpenTime", 4000);
 pref("alerts.disableSlidingEffect", false);
+
+// DOM full-screen API.
+pref("full-screen-api.enabled", false);
  
 //3D Transforms
 pref("layout.3d-transforms.enabled", false);