diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -12,7 +12,7 @@
     'core.pkg.css' => '86f155f9',
     'core.pkg.js' => '705aec2c',
     'differential.pkg.css' => '607c84be',
-    'differential.pkg.js' => 'd73a942b',
+    'differential.pkg.js' => '99e2cb01',
     'diffusion.pkg.css' => '42c75c37',
     'diffusion.pkg.js' => 'a98c0bf7',
     'maniphest.pkg.css' => '35995d6d',
@@ -377,9 +377,9 @@
     'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be',
     'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9',
     'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8',
-    'rsrc/js/application/diff/DiffChangeset.js' => '7ccc4153',
-    'rsrc/js/application/diff/DiffChangesetList.js' => '2e636e0a',
-    'rsrc/js/application/diff/DiffInline.js' => 'a4a14a94',
+    'rsrc/js/application/diff/DiffChangeset.js' => '5a4e4a3b',
+    'rsrc/js/application/diff/DiffChangesetList.js' => '4769cfe7',
+    'rsrc/js/application/diff/DiffInline.js' => '16e97ebc',
     'rsrc/js/application/diff/behavior-preview-link.js' => 'f51e9c17',
     'rsrc/js/application/differential/behavior-diff-radios.js' => '925fe8cd',
     'rsrc/js/application/differential/behavior-populate.js' => 'dfa1d313',
@@ -774,9 +774,9 @@
     'phabricator-darklog' => '3b869402',
     'phabricator-darkmessage' => '26cd4b73',
     'phabricator-dashboard-css' => '5a205b9d',
-    'phabricator-diff-changeset' => '7ccc4153',
-    'phabricator-diff-changeset-list' => '2e636e0a',
-    'phabricator-diff-inline' => 'a4a14a94',
+    'phabricator-diff-changeset' => '5a4e4a3b',
+    'phabricator-diff-changeset-list' => '4769cfe7',
+    'phabricator-diff-inline' => '16e97ebc',
     'phabricator-drag-and-drop-file-upload' => '4370900d',
     'phabricator-draggable-list' => '0169e425',
     'phabricator-fatal-config-template-css' => '20babf50',
@@ -1029,6 +1029,9 @@
       'javelin-stratcom',
       'javelin-util',
     ),
+    '16e97ebc' => array(
+      'javelin-dom',
+    ),
     '1b6acc2a' => array(
       'javelin-magical-init',
       'javelin-util',
@@ -1169,10 +1172,6 @@
       'javelin-util',
       'javelin-stratcom',
     ),
-    '2e636e0a' => array(
-      'javelin-install',
-      'phuix-button-view',
-    ),
     '2f1db1ed' => array(
       'javelin-util',
     ),
@@ -1308,6 +1307,10 @@
       'javelin-util',
       'phabricator-busy',
     ),
+    '4769cfe7' => array(
+      'javelin-install',
+      'phuix-button-view',
+    ),
     '47a0728b' => array(
       'javelin-behavior',
       'javelin-dom',
@@ -1441,6 +1444,17 @@
       'javelin-util',
       'javelin-magical-init',
     ),
+    '5a4e4a3b' => array(
+      'javelin-dom',
+      'javelin-util',
+      'javelin-stratcom',
+      'javelin-install',
+      'javelin-workflow',
+      'javelin-router',
+      'javelin-behavior-device',
+      'javelin-vector',
+      'phabricator-diff-inline',
+    ),
     '5a6f6a06' => array(
       'javelin-behavior',
       'javelin-quicksand',
@@ -1612,17 +1626,6 @@
       'javelin-install',
       'javelin-dom',
     ),
-    '7ccc4153' => array(
-      'javelin-dom',
-      'javelin-util',
-      'javelin-stratcom',
-      'javelin-install',
-      'javelin-workflow',
-      'javelin-router',
-      'javelin-behavior-device',
-      'javelin-vector',
-      'phabricator-diff-inline',
-    ),
     '80bff3af' => array(
       'javelin-install',
       'javelin-typeahead-source',
@@ -1828,9 +1831,6 @@
       'javelin-stratcom',
       'javelin-vector',
     ),
-    'a4a14a94' => array(
-      'javelin-dom',
-    ),
     'a4aa75c4' => array(
       'phui-button-css',
       'phui-button-simple-css',
diff --git a/src/applications/differential/controller/DifferentialChangesetViewController.php b/src/applications/differential/controller/DifferentialChangesetViewController.php
--- a/src/applications/differential/controller/DifferentialChangesetViewController.php
+++ b/src/applications/differential/controller/DifferentialChangesetViewController.php
@@ -205,8 +205,6 @@
       ->setRightSideCommentMapping($right_source, $right_new)
       ->setLeftSideCommentMapping($left_source, $left_new);
 
-    $parser->readParametersFromRequest($request);
-
     if ($left && $right) {
       $parser->setOriginals($left, $right);
     }
@@ -274,7 +272,7 @@
     if ($request->isAjax()) {
       // NOTE: We must render the changeset before we render coverage
       // information, since it builds some caches.
-      $rendered_changeset = $parser->renderChangeset();
+      $response = $parser->newChangesetResponse();
 
       $mcov = $parser->renderModifiedCoverage();
 
@@ -282,10 +280,9 @@
         'differential-mcoverage-'.md5($changeset->getFilename()) => $mcov,
       );
 
-      return id(new PhabricatorChangesetResponse())
-        ->setRenderedChangeset($rendered_changeset)
-        ->setCoverage($coverage_data)
-        ->setUndoTemplates($parser->getRenderer()->renderUndoTemplates());
+      $response->setCoverage($coverage_data);
+
+      return $response;
     }
 
     $detail = id(new DifferentialChangesetListView())
diff --git a/src/applications/differential/parser/DifferentialChangesetParser.php b/src/applications/differential/parser/DifferentialChangesetParser.php
--- a/src/applications/differential/parser/DifferentialChangesetParser.php
+++ b/src/applications/differential/parser/DifferentialChangesetParser.php
@@ -44,7 +44,6 @@
   private $highlightErrors;
   private $disableCache;
   private $renderer;
-  private $characterEncoding;
   private $highlightingDisabled;
   private $showEditAndReplyLinks = true;
   private $canMarkDone;
@@ -58,7 +57,6 @@
 
   private $highlightEngine;
   private $viewer;
-  private $documentEngineKey;
 
   private $viewState;
 
@@ -95,24 +93,12 @@
     return $this->viewState;
   }
 
-  public function setCharacterEncoding($character_encoding) {
-    $this->characterEncoding = $character_encoding;
-    return $this;
-  }
-
-  public function getCharacterEncoding() {
-    return $this->characterEncoding;
-  }
-
   public function setRenderer(DifferentialChangesetRenderer $renderer) {
     $this->renderer = $renderer;
     return $this;
   }
 
   public function getRenderer() {
-    if (!$this->renderer) {
-      return new DifferentialChangesetTwoUpRenderer();
-    }
     return $this->renderer;
   }
 
@@ -161,53 +147,34 @@
     return $this->viewer;
   }
 
-  public function setDocumentEngineKey($document_engine_key) {
-    $this->documentEngineKey = $document_engine_key;
-    return $this;
-  }
-
-  public function getDocumentEngineKey() {
-    return $this->documentEngineKey;
-  }
-
-  public static function getDefaultRendererForViewer(PhabricatorUser $viewer) {
-    $is_unified = $viewer->compareUserSetting(
-      PhabricatorUnifiedDiffsSetting::SETTINGKEY,
-      PhabricatorUnifiedDiffsSetting::VALUE_ALWAYS_UNIFIED);
-
-    if ($is_unified) {
-      return '1up';
-    }
-
-    return null;
-  }
-
-  public function readParametersFromRequest(AphrontRequest $request) {
-    $this->setCharacterEncoding($request->getStr('encoding'));
-    $this->setDocumentEngineKey($request->getStr('engine'));
+  private function newRenderer() {
+    $viewer = $this->getViewer();
+    $viewstate = $this->getViewstate();
 
-    $renderer = null;
+    $renderer_key = $viewstate->getRendererKey();
 
-    // If the viewer prefers unified diffs, always set the renderer to unified.
-    // Otherwise, we leave it unspecified and the client will choose a
-    // renderer based on the screen size.
+    if ($renderer_key === null) {
+      $is_unified = $viewer->compareUserSetting(
+        PhabricatorUnifiedDiffsSetting::SETTINGKEY,
+        PhabricatorUnifiedDiffsSetting::VALUE_ALWAYS_UNIFIED);
 
-    if ($request->getStr('renderer')) {
-      $renderer = $request->getStr('renderer');
-    } else {
-      $renderer = self::getDefaultRendererForViewer($request->getViewer());
+      if ($is_unified) {
+        $renderer_key = '1up';
+      } else {
+        $renderer_key = $viewstate->getDefaultDeviceRendererKey();
+      }
     }
 
-    switch ($renderer) {
+    switch ($renderer_key) {
       case '1up':
-        $this->setRenderer(new DifferentialChangesetOneUpRenderer());
+        $renderer = new DifferentialChangesetOneUpRenderer();
         break;
       default:
-        $this->setRenderer(new DifferentialChangesetTwoUpRenderer());
+        $renderer = new DifferentialChangesetTwoUpRenderer();
         break;
     }
 
-    return $this;
+    return $renderer;
   }
 
   const CACHE_VERSION = 14;
@@ -633,7 +600,8 @@
       $skip_cache = true;
     }
 
-    if ($this->characterEncoding) {
+    $character_encoding = $viewstate->getCharacterEncoding();
+    if ($character_encoding !== null) {
       $skip_cache = true;
     }
 
@@ -782,6 +750,12 @@
     $range_len    = null,
     $mask_force   = array()) {
 
+    $renderer = $this->getRenderer();
+    if (!$renderer) {
+      $renderer = $this->newRenderer();
+      $this->setRenderer($renderer);
+    }
+
     // "Top level" renders are initial requests for the whole file, versus
     // requests for a specific range generated by clicking "show more". We
     // generate property changes and "shield" UI elements only for toplevel
@@ -789,14 +763,18 @@
     $this->isTopLevel = (($range_start === null) && ($range_len === null));
     $this->highlightEngine = PhabricatorSyntaxHighlighter::newEngine();
 
+    $viewstate = $this->getViewState();
+
     $encoding = null;
-    if ($this->characterEncoding) {
+
+    $character_encoding = $viewstate->getCharacterEncoding();
+    if ($character_encoding) {
       // We are forcing this changeset to be interpreted with a specific
       // character encoding, so force all the hunks into that encoding and
       // propagate it to the renderer.
-      $encoding = $this->characterEncoding;
+      $encoding = $character_encoding;
       foreach ($this->changeset->getHunks() as $hunk) {
-        $hunk->forceEncoding($this->characterEncoding);
+        $hunk->forceEncoding($character_encoding);
       }
     } else {
       // We're just using the default, so tell the renderer what that is
@@ -1794,7 +1772,9 @@
       }
     }
 
-    $engine_key = $this->getDocumentEngineKey();
+    $viewstate = $this->getViewState();
+
+    $engine_key = $viewstate->getDocumentEngineKey();
     if (strlen($engine_key)) {
       if (isset($shared_engines[$engine_key])) {
         $document_engine = $shared_engines[$engine_key];
@@ -1895,4 +1875,31 @@
     return array($old_file, $new_file);
   }
 
+  public function newChangesetResponse() {
+    // NOTE: This has to happen first because it has side effects. Yuck.
+    $rendered_changeset = $this->renderChangeset();
+
+    $renderer = $this->getRenderer();
+    $renderer_key = $renderer->getRendererKey();
+
+    $viewstate = $this->getViewState();
+
+    $undo_templates = $renderer->renderUndoTemplates();
+    foreach ($undo_templates as $key => $undo_template) {
+      $undo_templates[$key] = hsprintf('%s', $undo_template);
+    }
+
+    $state = array(
+      'undoTemplates' => $undo_templates,
+      'rendererKey' => $renderer_key,
+      'highlight' => $viewstate->getHighlightLanguage(),
+      'characterEncoding' => $viewstate->getCharacterEncoding(),
+      'documentEngine' => $viewstate->getDocumentEngineKey(),
+    );
+
+    return id(new PhabricatorChangesetResponse())
+      ->setRenderedChangeset($rendered_changeset)
+      ->setChangesetState($state);
+  }
+
 }
diff --git a/src/applications/differential/view/DifferentialChangesetDetailView.php b/src/applications/differential/view/DifferentialChangesetDetailView.php
--- a/src/applications/differential/view/DifferentialChangesetDetailView.php
+++ b/src/applications/differential/view/DifferentialChangesetDetailView.php
@@ -11,10 +11,9 @@
   private $renderURI;
   private $renderingRef;
   private $autoload;
-  private $loaded;
-  private $renderer;
   private $repository;
   private $diff;
+  private $changesetResponse;
 
   public function setAutoload($autoload) {
     $this->autoload = $autoload;
@@ -25,22 +24,22 @@
     return $this->autoload;
   }
 
-  public function setLoaded($loaded) {
-    $this->loaded = $loaded;
+  public function setRenderingRef($rendering_ref) {
+    $this->renderingRef = $rendering_ref;
     return $this;
   }
 
-  public function getLoaded() {
-    return $this->loaded;
+  public function getRenderingRef() {
+    return $this->renderingRef;
   }
 
-  public function setRenderingRef($rendering_ref) {
-    $this->renderingRef = $rendering_ref;
+  public function setChangesetResponse(PhabricatorChangesetResponse $response) {
+    $this->changesetResponse = $response;
     return $this;
   }
 
-  public function getRenderingRef() {
-    return $this->renderingRef;
+  public function getChangesetResponse() {
+    return $this->changesetResponse;
   }
 
   public function setRenderURI($render_uri) {
@@ -72,15 +71,6 @@
     return $this;
   }
 
-  public function setRenderer($renderer) {
-    $this->renderer = $renderer;
-    return $this;
-  }
-
-  public function getRenderer() {
-    return $this->renderer;
-  }
-
   public function getID() {
     if (!$this->id) {
       $this->id = celerity_generate_unique_node_id();
@@ -139,9 +129,6 @@
     $icon = id(new PHUIIconView())
       ->setIcon($display_icon);
 
-    $renderer = DifferentialChangesetHTMLRenderer::getHTMLRendererByKey(
-      $this->getRenderer());
-
     $changeset_id = $this->changeset->getID();
 
     $vs_id = $this->getVsChangesetID();
@@ -180,6 +167,17 @@
       ),
       $file_part);
 
+    $response = $this->getChangesetResponse();
+    if ($response) {
+      $is_loaded = true;
+      $changeset_markup = $response->getRenderedChangeset();
+      $changeset_state = $response->getChangesetState();
+    } else {
+      $is_loaded = false;
+      $changeset_markup = null;
+      $changeset_state = null;
+    }
+
     return javelin_tag(
       'div',
       array(
@@ -188,12 +186,8 @@
           'left'  => $left_id,
           'right' => $right_id,
           'renderURI' => $this->getRenderURI(),
-          'highlight' => null,
-          'renderer' => $this->getRenderer(),
           'ref' => $this->getRenderingRef(),
           'autoload' => $this->getAutoload(),
-          'loaded' => $this->getLoaded(),
-          'undoTemplates' => hsprintf('%s', $renderer->renderUndoTemplates()),
           'displayPath' => hsprintf('%s', $display_parts),
           'path' => $display_filename,
           'icon' => $display_icon,
@@ -201,6 +195,9 @@
 
           'editorURI' => $this->getEditorURI(),
           'editorConfigureURI' => $this->getEditorConfigureURI(),
+
+          'loaded' => $is_loaded,
+          'changesetState' => $changeset_state,
         ),
         'class' => $class,
         'id'    => $id,
@@ -225,7 +222,10 @@
             'class' => 'changeset-view-content',
             'sigil' => 'changeset-view-content',
           ),
-          $this->renderChildren()),
+          array(
+            $changeset_markup,
+            $this->renderChildren(),
+          )),
       ));
   }
 
diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php
--- a/src/applications/differential/view/DifferentialChangesetListView.php
+++ b/src/applications/differential/view/DifferentialChangesetListView.php
@@ -153,9 +153,6 @@
 
     $changesets = $this->changesets;
 
-    $renderer = DifferentialChangesetParser::getDefaultRendererForViewer(
-      $viewer);
-
     $repository = $this->getRepository();
     $diff = $this->getDiff();
 
@@ -167,7 +164,7 @@
       $ref = $this->references[$key];
 
       $detail = id(new DifferentialChangesetDetailView())
-        ->setUser($viewer);
+        ->setViewer($viewer);
 
       if ($repository) {
         $detail->setRepository($repository);
@@ -193,11 +190,11 @@
       $detail->setRenderingRef($ref);
 
       $detail->setRenderURI($this->renderURI);
-      $detail->setRenderer($renderer);
 
-      if ($this->getParser()) {
-        $detail->appendChild($this->getParser()->renderChangeset());
-        $detail->setLoaded(true);
+      $parser = $this->getParser();
+      if ($parser) {
+        $response = $parser->newChangesetResponse();
+        $detail->setChangesetResponse($response);
       } else {
         $detail->setAutoload(isset($this->visibleChangesets[$key]));
         if (isset($this->visibleChangesets[$key])) {
diff --git a/src/applications/diffusion/controller/DiffusionDiffController.php b/src/applications/diffusion/controller/DiffusionDiffController.php
--- a/src/applications/diffusion/controller/DiffusionDiffController.php
+++ b/src/applications/diffusion/controller/DiffusionDiffController.php
@@ -79,8 +79,6 @@
         'action' => 'rendering-ref',
       )));
 
-    $parser->readParametersFromRequest($request);
-
     $coverage = $drequest->loadCoverage();
     if ($coverage) {
       $parser->setCoverage($coverage);
@@ -132,8 +130,6 @@
     $parser->setRange($range_s, $range_e);
     $parser->setMask($mask);
 
-    return id(new PhabricatorChangesetResponse())
-      ->setRenderedChangeset($parser->renderChangeset())
-      ->setUndoTemplates($parser->getRenderer()->renderUndoTemplates());
+    return $parser->newChangesetResponse();
   }
 }
diff --git a/src/infrastructure/diff/PhabricatorChangesetResponse.php b/src/infrastructure/diff/PhabricatorChangesetResponse.php
--- a/src/infrastructure/diff/PhabricatorChangesetResponse.php
+++ b/src/infrastructure/diff/PhabricatorChangesetResponse.php
@@ -4,20 +4,19 @@
 
   private $renderedChangeset;
   private $coverage;
-  private $undoTemplates;
+  private $changesetState;
 
   public function setRenderedChangeset($rendered_changeset) {
     $this->renderedChangeset = $rendered_changeset;
     return $this;
   }
 
-  public function setCoverage($coverage) {
-    $this->coverage = $coverage;
-    return $this;
+  public function getRenderedChangeset() {
+    return $this->renderedChangeset;
   }
 
-  public function setUndoTemplates($undo_templates) {
-    $this->undoTemplates = $undo_templates;
+  public function setCoverage($coverage) {
+    $this->coverage = $coverage;
     return $this;
   }
 
@@ -27,18 +26,23 @@
 
   public function reduceProxyResponse() {
     $content = array(
-      'changeset' => $this->renderedChangeset,
-    );
+      'changeset' => $this->getRenderedChangeset(),
+    ) + $this->getChangesetState();
 
     if ($this->coverage) {
       $content['coverage'] = $this->coverage;
     }
 
-    if ($this->undoTemplates) {
-      $content['undoTemplates'] = $this->undoTemplates;
-    }
-
     return $this->getProxy()->setContent($content);
   }
 
+  public function setChangesetState(array $state) {
+    $this->changesetState = $state;
+    return $this;
+  }
+
+  public function getChangesetState() {
+    return $this->changesetState;
+  }
+
 }
diff --git a/src/infrastructure/diff/viewstate/PhabricatorChangesetViewState.php b/src/infrastructure/diff/viewstate/PhabricatorChangesetViewState.php
--- a/src/infrastructure/diff/viewstate/PhabricatorChangesetViewState.php
+++ b/src/infrastructure/diff/viewstate/PhabricatorChangesetViewState.php
@@ -4,6 +4,10 @@
   extends Phobject {
 
   private $highlightLanguage;
+  private $characterEncoding;
+  private $documentEngineKey;
+  private $rendererKey;
+  private $defaultDeviceRendererKey;
 
   public function setHighlightLanguage($highlight_language) {
     $this->highlightLanguage = $highlight_language;
@@ -14,4 +18,40 @@
     return $this->highlightLanguage;
   }
 
+  public function setCharacterEncoding($character_encoding) {
+    $this->characterEncoding = $character_encoding;
+    return $this;
+  }
+
+  public function getCharacterEncoding() {
+    return $this->characterEncoding;
+  }
+
+  public function setDocumentEngineKey($document_engine_key) {
+    $this->documentEngineKey = $document_engine_key;
+    return $this;
+  }
+
+  public function getDocumentEngineKey() {
+    return $this->documentEngineKey;
+  }
+
+  public function setRendererKey($renderer_key) {
+    $this->rendererKey = $renderer_key;
+    return $this;
+  }
+
+  public function getRendererKey() {
+    return $this->rendererKey;
+  }
+
+  public function setDefaultDeviceRendererKey($renderer_key) {
+    $this->defaultDeviceRendererKey = $renderer_key;
+    return $this;
+  }
+
+  public function getDefaultDeviceRendererKey() {
+    return $this->defaultDeviceRendererKey;
+  }
+
 }
diff --git a/src/infrastructure/diff/viewstate/PhabricatorChangesetViewStateEngine.php b/src/infrastructure/diff/viewstate/PhabricatorChangesetViewStateEngine.php
--- a/src/infrastructure/diff/viewstate/PhabricatorChangesetViewStateEngine.php
+++ b/src/infrastructure/diff/viewstate/PhabricatorChangesetViewStateEngine.php
@@ -41,10 +41,25 @@
     $this->setStorage($storage);
 
     $highlight = $request->getStr('highlight');
-    if ($highlight !== null && strlen($highlight)) {
+    if ($highlight !== null) {
       $this->setChangesetProperty('highlight', $highlight);
     }
 
+    $encoding = $request->getStr('encoding');
+    if ($encoding !== null) {
+      $this->setChangesetProperty('encoding', $encoding);
+    }
+
+    $engine = $request->getStr('engine');
+    if ($engine !== null) {
+      $this->setChangesetProperty('engine', $engine);
+    }
+
+    $renderer = $request->getStr('renderer');
+    if ($renderer !== null) {
+      $this->setChangesetProperty('renderer', $renderer);
+    }
+
     $this->saveViewStateStorage();
 
     $state = new PhabricatorChangesetViewState();
@@ -52,6 +67,23 @@
     $highlight_language = $this->getChangesetProperty('highlight');
     $state->setHighlightLanguage($highlight_language);
 
+    $encoding = $this->getChangesetProperty('encoding');
+    $state->setCharacterEncoding($encoding);
+
+    $document_engine = $this->getChangesetProperty('engine');
+    $state->setDocumentEngineKey($document_engine);
+
+    $renderer = $this->getChangesetProperty('renderer');
+    $state->setRendererKey($renderer);
+
+    // This is the client-selected default renderer based on viewport
+    // dimensions.
+
+    $device_key = $request->getStr('device');
+    if ($device_key !== null && strlen($device_key)) {
+      $state->setDefaultDeviceRendererKey($device_key);
+    }
+
     return $state;
   }
 
diff --git a/webroot/rsrc/js/application/diff/DiffChangeset.js b/webroot/rsrc/js/application/diff/DiffChangeset.js
--- a/webroot/rsrc/js/application/diff/DiffChangeset.js
+++ b/webroot/rsrc/js/application/diff/DiffChangeset.js
@@ -22,10 +22,6 @@
 
     this._renderURI = data.renderURI;
     this._ref = data.ref;
-    this._renderer = data.renderer;
-    this._highlight = data.highlight;
-    this._documentEngine = data.documentEngine;
-    this._encoding = data.encoding;
     this._loaded = data.loaded;
     this._treeNodeID = data.treeNodeID;
 
@@ -39,6 +35,10 @@
     this._editorConfigureURI = data.editorConfigureURI;
 
     this._inlines = [];
+
+    if (data.changesetState) {
+      this._loadChangesetState(data.changesetState);
+    }
   },
 
   members: {
@@ -49,10 +49,10 @@
 
     _renderURI: null,
     _ref: null,
-    _renderer: null,
+    _rendererKey: null,
     _highlight: null,
     _documentEngine: null,
-    _encoding: null,
+    _characterEncoding: null,
     _undoTemplates: null,
 
     _leftID: null,
@@ -187,11 +187,11 @@
      *
      * @return this
      */
-    reload: function() {
+    reload: function(state) {
       this._loaded = true;
       this._sequence++;
 
-      var params = this._getViewParameters();
+      var params = this._getViewParameters(state);
       var pht = this.getChangesetList().getTranslations();
 
       var workflow = new JX.Workflow(this._renderURI, params)
@@ -321,14 +321,17 @@
     /**
      * Get parameters which define the current rendering options.
      */
-    _getViewParameters: function() {
-      return {
+    _getViewParameters: function(state) {
+      var parameters = {
         ref: this._ref,
-        renderer: this.getRenderer() || '',
-        highlight: this._highlight || '',
-        engine: this._documentEngine || '',
-        encoding: this._encoding || ''
+        device: this._getDefaultDeviceRenderer()
       };
+
+      if (state) {
+        JX.copy(parameters, state);
+      }
+
+      return parameters;
     },
 
     /**
@@ -344,16 +347,11 @@
       return JX.Router.getInstance().getRoutableByKey(this._getRoutableKey());
     },
 
-    setRenderer: function(renderer) {
-      this._renderer = renderer;
-      return this;
+    getRendererKey: function() {
+      return this._rendererKey;
     },
 
-    getRenderer: function() {
-      if (this._renderer !== null) {
-        return this._renderer;
-      }
-
+    _getDefaultDeviceRenderer: function() {
       // NOTE: If you load the page at one device resolution and then resize to
       // a different one we don't re-render the diffs, because it's a
       // complicated mess and you could lose inline comments, cursor positions,
@@ -365,28 +363,14 @@
       return this._undoTemplates;
     },
 
-    setEncoding: function(encoding) {
-      this._encoding = encoding;
-      return this;
-    },
-
-    getEncoding: function() {
-      return this._encoding;
-    },
-
-    setHighlight: function(highlight) {
-      this._highlight = highlight;
-      return this;
+    getCharacterEncoding: function() {
+      return this._characterEncoding;
     },
 
     getHighlight: function() {
       return this._highlight;
     },
 
-    setDocumentEngine: function(engine) {
-      this._documentEngine = engine;
-    },
-
     getDocumentEngine: function(engine) {
       return this._documentEngine;
     },
@@ -614,25 +598,34 @@
     _onchangesetresponse: function(response) {
       // Code shared by autoload and context responses.
 
-      if (response.coverage) {
-        for (var k in response.coverage) {
+      this._loadChangesetState(response);
+
+      JX.Stratcom.invoke('differential-inline-comment-refresh');
+
+      this._rebuildAllInlines();
+
+      JX.Stratcom.invoke('resize');
+    },
+
+    _loadChangesetState: function(state) {
+      if (state.coverage) {
+        for (var k in state.coverage) {
           try {
-            JX.DOM.replace(JX.$(k), JX.$H(response.coverage[k]));
+            JX.DOM.replace(JX.$(k), JX.$H(state.coverage[k]));
           } catch (ignored) {
             // Not terribly important.
           }
         }
       }
 
-      if (response.undoTemplates) {
-        this._undoTemplates = response.undoTemplates;
+      if (state.undoTemplates) {
+        this._undoTemplates = state.undoTemplates;
       }
 
-      JX.Stratcom.invoke('differential-inline-comment-refresh');
-
-      this._rebuildAllInlines();
-
-      JX.Stratcom.invoke('resize');
+      this._rendererKey = state.rendererKey;
+      this._highlight = state.highlight;
+      this._characterEncoding = state.characterEncoding;
+      this._documentEngine = state.documentEngine;
     },
 
     _getContentFrame: function() {
diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js
--- a/webroot/rsrc/js/application/diff/DiffChangesetList.js
+++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js
@@ -798,15 +798,16 @@
               }
             }
 
-            var renderer = changeset.getRenderer();
+            var renderer = changeset.getRendererKey();
             if (renderer == '1up') {
               renderer = '2up';
             } else {
               renderer = '1up';
             }
-            changeset.setRenderer(renderer);
+            changeset.reload({renderer: renderer});
+          } else {
+            changeset.reload();
           }
-          changeset.reload();
 
           e.prevent();
           menu.close();
@@ -818,13 +819,12 @@
         .setName(pht('Change Text Encoding...'))
         .setHandler(function(e) {
           var params = {
-            encoding: changeset.getEncoding()
+            encoding: changeset.getCharacterEncoding()
           };
 
           new JX.Workflow('/services/encoding/', params)
             .setHandler(function(r) {
-              changeset.setEncoding(r.encoding);
-              changeset.reload();
+              changeset.reload({encoding: r.encoding});
             })
             .start();
 
@@ -843,8 +843,7 @@
 
           new JX.Workflow('/services/highlight/', params)
             .setHandler(function(r) {
-              changeset.setHighlight(r.highlight);
-              changeset.reload();
+              changeset.reload({highlight: r.highlight});
             })
             .start();
 
@@ -863,8 +862,7 @@
 
           new JX.Workflow('/services/viewas/', params)
             .setHandler(function(r) {
-              changeset.setDocumentEngine(r.engine);
-              changeset.reload();
+              changeset.reload({engine: r.engine});
             })
             .start();
 
@@ -917,7 +915,7 @@
         engine_item.setDisabled(!changeset.isLoaded());
 
         if (changeset.isLoaded()) {
-          if (changeset.getRenderer() == '2up') {
+          if (changeset.getRendererKey() == '2up') {
             up_item
               .setIcon('fa-list-alt')
               .setName(pht('View Unified'));
diff --git a/webroot/rsrc/js/application/diff/DiffInline.js b/webroot/rsrc/js/application/diff/DiffInline.js
--- a/webroot/rsrc/js/application/diff/DiffInline.js
+++ b/webroot/rsrc/js/application/diff/DiffInline.js
@@ -461,7 +461,7 @@
         op: operation,
         id: this._id,
         on_right: ((this.getDisplaySide() == 'right') ? 1 : 0),
-        renderer: this.getChangeset().getRenderer(),
+        renderer: this.getChangeset().getRendererKey(),
         number: this.getLineNumber(),
         length: this.getLineLength(),
         is_new: this.isNewFile(),