# Responsive Design Mode Architecture

## Context

You have a single browser tab that has visited several pages, and now has a
history that looks like, in oldest to newest order:

1. https://newsblur.com
2. https://mozilla.org (← current page)
3. https://convolv.es

## Opening RDM During Current Firefox Session

When opening RDM, the browser tab's history must preserved.  Additionally, we
strive to preserve the exact state of the currently displayed page (effectively
any in-page state, which is important for single page apps where data can be
lost if they are reloaded).

This seems a bit convoluted, but one advantage of this technique is that it
preserves tab state since the same tab is reused.  This helps to maintain any
extra state that may be set on tab by add-ons or others.

1. Create a temporary, hidden tab to load the tool UI.
2. Mark the tool tab browser's docshell as active so the viewport frame is
   created eagerly and will be ready to swap.
3. Create the initial viewport inside the tool UI.
4. Swap tab content from the regular browser tab to the browser within the
   viewport in the tool UI, preserving all state via
   `gBrowser._swapBrowserDocShells`.
5. Force the original browser tab to be non-remote since the tool UI must be
   loaded in the parent process, and we're about to swap the tool UI into
   this tab.
6. Swap the tool UI (with viewport showing the content) into the original
   browser tab and close the temporary tab used to load the tool via
   `swapBrowsersAndCloseOther`.
7. Start a tunnel from the tool tab's browser to the viewport browser
   so that some browser UI functions, like navigation, are connected to
   the content in the viewport, instead of the tool page.

## Closing RDM During Current Firefox Session

To close RDM, we follow a similar process to the one from opening RDM so we can
restore the content back to a normal tab.

1. Stop the tunnel between outer and inner browsers.
2. Create a temporary, hidden tab to hold the content.
3. Mark the content tab browser's docshell as active so the frame is created
   eagerly and will be ready to swap.
4. Swap tab content from the browser within the viewport in the tool UI to the
   regular browser tab, preserving all state via
   `gBrowser._swapBrowserDocShells`.
5. Force the original browser tab to be remote since web content is loaded in
   the child process, and we're about to swap the content into this tab.
6. Swap the content into the original browser tab and close the temporary tab
   used to hold the content via `swapBrowsersAndCloseOther`.

## Session Restore

When restarting Firefox and restoring a user's browsing session, we must
correctly restore the tab history.  If the RDM tool was opened when the session
was captured, then it would be acceptable to either:

* A: Restore the tab content without any RDM tool displayed **OR**
* B: Restore the RDM tool the tab content inside, just as before the restart

We currently follow path A (no RDM after session restore), which seems more in
line with how the rest of DevTools currently functions after restore.  To do so,
we watch for `beforeunload` events on the tab at shutdown and quickly exit RDM
so that session restore records only the original page content during its final
write at shutdown.