diff --git a/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php b/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
index dd8c990..e7e5238 100644
--- a/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
+++ b/core/modules/contextual/src/Plugin/views/field/ContextualLinks.php
@@ -86,7 +86,7 @@ public function preRender(&$values) {
   public function render(ResultRow $values) {
     $links = array();
     foreach ($this->options['fields'] as $field) {
-      $rendered_field = $this->view->style_plugin->getField($this->view->row_index, $field);
+      $rendered_field = $this->view->style_plugin->getField($values->index, $field);
       if (empty($rendered_field)) {
         continue;
       }
diff --git a/core/modules/entity_reference/src/Plugin/views/style/EntityReference.php b/core/modules/entity_reference/src/Plugin/views/style/EntityReference.php
index d0b3bbe..258e66e 100644
--- a/core/modules/entity_reference/src/Plugin/views/style/EntityReference.php
+++ b/core/modules/entity_reference/src/Plugin/views/style/EntityReference.php
@@ -88,17 +88,14 @@ public function render() {
     // @todo We don't display grouping info for now. Could be useful for select
     // widget, though.
     $results = array();
-    $this->view->row_index = 0;
     foreach ($sets as $records) {
       foreach ($records as $values) {
         // Sanitize HTML, remove line breaks and extra whitespace.
         $output = $this->view->rowPlugin->render($values);
         $output = drupal_render($output);
         $results[$values->{$id_field_alias}] = Xss::filterAdmin(preg_replace('/\s\s+/', ' ', str_replace("\n", '', $output)));
-        $this->view->row_index++;
       }
     }
-    unset($this->view->row_index);
     return $results;
   }
 
diff --git a/core/modules/field/src/Plugin/views/field/Field.php b/core/modules/field/src/Plugin/views/field/Field.php
index 0bd93b2..fd2a712 100644
--- a/core/modules/field/src/Plugin/views/field/Field.php
+++ b/core/modules/field/src/Plugin/views/field/Field.php
@@ -22,6 +22,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
+use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -722,7 +723,7 @@ protected function renderItems($items) {
   /**
    * Return an array of items for the field.
    */
-  public function getItems($values) {
+  public function getItems(ResultRow $values) {
     $original_entity = $this->getEntity($values);
     if (!$original_entity) {
       return array();
@@ -739,7 +740,7 @@ public function getItems($values) {
       // Pass the View object in the display so that fields can act on it.
       'views_view' => $this->view,
       'views_field' => $this,
-      'views_row_id' => $this->view->row_index,
+      'views_row_id' => $values->index,
     );
     $render_array = $entity->get($this->definition['field_name'])->view($display);
 
diff --git a/core/modules/node/src/Tests/Views/RowPluginTest.php b/core/modules/node/src/Tests/Views/RowPluginTest.php
index 4813bd6..e0e863e 100644
--- a/core/modules/node/src/Tests/Views/RowPluginTest.php
+++ b/core/modules/node/src/Tests/Views/RowPluginTest.php
@@ -139,9 +139,10 @@ public function testRowPlugin() {
     // Test with links enabled.
     $view->rowPlugin->options['links'] = TRUE;
     \Drupal::entityManager()->getViewBuilder('node')->resetCache();
-    $output = $view->preview();
-    $output = drupal_render($output);
+    $build = $view->preview();
+    $output = drupal_render($build);
     $this->drupalSetContent($output);
+    debug($output);
     foreach ($this->nodes as $node) {
       $this->assertTrue($this->xpath('//li[contains(@class, :class)]/a[contains(@href, :href)]', array(':class' => 'node-readmore', ':href' => "node/{$node->id()}")), 'Make sure no readmore link appears.');
     }
diff --git a/core/modules/system/src/Plugin/views/field/BulkForm.php b/core/modules/system/src/Plugin/views/field/BulkForm.php
index bae235d..232a11c 100644
--- a/core/modules/system/src/Plugin/views/field/BulkForm.php
+++ b/core/modules/system/src/Plugin/views/field/BulkForm.php
@@ -134,7 +134,7 @@ public function validateOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function render(ResultRow $values) {
-    return '<!--form-item-' . $this->options['id'] . '--' . $this->view->row_index . '-->';
+    return '<!--form-item-' . $this->options['id'] . '--' . $values->index . '-->';
   }
 
   /**
diff --git a/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php b/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php
index 5af5a3e..6612ec4 100644
--- a/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php
+++ b/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php
@@ -43,7 +43,6 @@ public function testRole() {
 
     $view = Views::getView('test_views_handler_field_role');
     $this->executeView($view);
-    $view->row_index = 0;
     // The role field is populated during preRender.
     $view->field['rid']->preRender($view->result);
     $render = $view->field['rid']->advancedRender($view->result[0]);
diff --git a/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php b/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php
index 573a579..752d87d 100644
--- a/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php
+++ b/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php
@@ -30,8 +30,6 @@ public function testUserName() {
     $view = Views::getView('test_views_handler_field_user_name');
     $this->executeView($view);
 
-    $view->row_index = 0;
-
     $view->field['name']->options['link_to_user'] = TRUE;
     $username = $view->result[0]->users_field_data_name = $this->randomMachineName();
     $view->result[0]->users_field_data_uid = 1;
diff --git a/core/modules/views/src/Form/ViewsForm.php b/core/modules/views/src/Form/ViewsForm.php
index 2273f90..6325b59 100644
--- a/core/modules/views/src/Form/ViewsForm.php
+++ b/core/modules/views/src/Form/ViewsForm.php
@@ -92,7 +92,7 @@ public function __construct(ClassResolverInterface $controller_resolver, UrlGene
    */
   public static function create(ContainerInterface $container, $view_id = NULL, $view_display_id = NULL) {
     return new static(
-      $container->get('controller_resolver'),
+      $container->get('class_resolver'),
       $container->get('url_generator'),
       $container->get('request_stack'),
       $view_id,
@@ -116,7 +116,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = []) {
     $form_state['step'] = isset($form_state['step']) ? $form_state['step'] : 'views_form_views_form';
     $form_state['step_controller']['views_form_views_form'] = 'Drupal\views\Form\ViewsFormMainForm';
 
diff --git a/core/modules/views/src/Form/ViewsFormMainForm.php b/core/modules/views/src/Form/ViewsFormMainForm.php
index 6c48b7e..f65310c 100644
--- a/core/modules/views/src/Form/ViewsFormMainForm.php
+++ b/core/modules/views/src/Form/ViewsFormMainForm.php
@@ -22,7 +22,7 @@ public function getFormID() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ViewExecutable $view = NULL, $output = []) {
     $form['#prefix'] = '<div class="views-form">';
     $form['#suffix'] = '</div>';
     $form['#theme'] = 'form';
@@ -30,12 +30,10 @@ public function buildForm(array $form, FormStateInterface $form_state, ViewExecu
 
     // Add the output markup to the form array so that it's included when the form
     // array is passed to the theme function.
-    $form['output'] = array(
-      '#markup' => $output,
-      // This way any additional form elements will go before the view
-      // (below the exposed widgets).
-      '#weight' => 50,
-    );
+    $form['output'] = $output;
+    // This way any additional form elements will go before the view
+    // (below the exposed widgets).
+    $form['output']['#weight'] = 50;
 
     $form['actions'] = array(
       '#type' => 'actions',
diff --git a/core/modules/views/src/Plugin/views/cache/CachePluginBase.php b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
index c8f9429..55a637d 100644
--- a/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
+++ b/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
@@ -142,8 +142,8 @@ public function cacheSet($type) {
         \Drupal::cache($this->resultsBin)->set($this->generateResultsKey(), $data, $this->cacheSetExpire($type), $this->getCacheTags());
         break;
       case 'output':
-        $this->storage['output'] = $this->view->display_handler->output;
-        $this->gatherHeaders();
+        $this->gatherHeaders($this->view->display_handler->output);
+        $this->storage['output'] = drupal_render($this->view->display_handler->output, TRUE);
         \Drupal::cache($this->outputBin)->set($this->generateOutputKey(), $this->storage, $this->cacheSetExpire($type), $this->getCacheTags());
         break;
     }
@@ -177,8 +177,13 @@ public function cacheGet($type) {
         if ($cache = \Drupal::cache($this->outputBin)->get($this->generateOutputKey())) {
           if (!$cutoff || $cache->created > $cutoff) {
             $this->storage = $cache->data;
-            $this->view->display_handler->output = $cache->data['output'];
+
             $this->restoreHeaders();
+            $this->view->display_handler->output = array(
+              '#attached' => &$this->view->element['#attached'],
+              '#markup' => $cache->data['output'],
+            );
+
             return TRUE;
           }
         }
@@ -235,7 +240,7 @@ public function cacheStart() {
   /**
    * Gather the JS/CSS from the render array, the html head from the band data.
    */
-  protected function gatherHeaders() {
+  protected function gatherHeaders(array $render_array = []) {
     // Simple replacement for head
     if (isset($this->storage['head'])) {
       $this->storage['head'] = str_replace($this->storage['head'], '', drupal_add_html_head());
@@ -244,7 +249,7 @@ protected function gatherHeaders() {
       $this->storage['head'] = '';
     }
 
-    $attached = $this->storage['output']['#attached'];
+    $attached = drupal_render_collect_attached($render_array, TRUE);
     $this->storage['css'] = $attached['css'];
     $this->storage['js'] = $attached['js'];
   }
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index 7d3232f..6491f58 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Theme\Registry;
+use Drupal\views\Form\ViewsForm;
 use Drupal\views\Plugin\views\area\AreaPluginBase;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Plugin\views\PluginBase;
@@ -2125,11 +2126,82 @@ public function getMenuLinks() {
    * Render this display.
    */
   public function render() {
+    $rows = (!empty($this->view->result) || $this->view->style_plugin->evenEmpty()) ? $this->view->style_plugin->render($this->view->result) : array();
+
     $element = array(
       '#theme' => $this->themeFunctions(),
       '#view' => $this->view,
+      '#attached' => &$this->view->element['#attached'],
+      '#pre_render' => [[$this, 'elementPreRender']],
+      '#rows' => $rows,
     );
-    $element['#attached'] = &$this->view->element['#attached'];
+
+    return $element;
+  }
+
+  /**
+   * Pre render callback for view display rendering.
+   *
+   * @see self::render()
+   *
+   * @param array $element
+   *
+   * @return array
+   */
+  public function elementPreRender($element) {
+    $view = $element['#view'];
+    $empty = empty($view->result);
+
+    // Force a render array so CSS/JS can be added.
+    if (!is_array($element['#rows'])) {
+      $element['#rows'] = array('#markup' => $element['#rows']);
+    }
+
+    $element['#header'] = $view->display_handler->renderArea('header', $empty);
+    $element['#footer'] = $view->display_handler->renderArea('footer', $empty);
+    $element['#empty'] = $empty ? $view->display_handler->renderArea('empty', $empty) : array();
+    $element['#exposed'] = !empty($view->exposed_widgets) ? $view->exposed_widgets : array();
+    $element['#more'] = $view->display_handler->renderMoreLink();
+    $element['#feed_icon'] = !empty($view->feed_icon) ? $view->feed_icon : array();
+
+    if ($view->display_handler->renderPager()) {
+      $exposed_input = isset($view->exposed_raw_input) ? $view->exposed_raw_input : NULL;
+      $element['#pager'] = $view->renderPager($exposed_input);
+    }
+
+    if (!empty($view->attachment_before)) {
+      $element['#attachment_before'] = $view->attachment_before;
+    }
+    if (!empty($view->attachment_after)) {
+      $element['#attachment_after'] = $view->attachment_after;
+    }
+
+    // If form fields were found in the view, reformat the view output as a form.
+    if ($view->hasFormElements()) {
+      // Only render row output if there are rows. Otherwise, render the empty
+      // region.
+      if (!empty($element['#rows'])) {
+        $output = $element['#rows'];
+      }
+      else {
+        $output = $element['#empty'];
+      }
+
+      $form_object = ViewsForm::create(\Drupal::getContainer(), $view->storage->id(), $view->current_display);
+      $form = \Drupal::formBuilder()->getForm($form_object, $view, $output);
+      // The form is requesting that all non-essential views elements be hidden,
+      // usually because the rendered step is not a view result.
+      if ($form['show_view_elements']['#value'] == FALSE) {
+        $element['#header'] = array();
+        $element['#exposed'] = array();
+        $element['#pager'] = array();
+        $element['#footer'] = array();
+        $element['#more'] = array();
+        $element['#feed_icon'] = array();
+      }
+
+      $element['#rows'] = $form;
+    }
 
     return $element;
   }
diff --git a/core/modules/views/src/Plugin/views/display/Feed.php b/core/modules/views/src/Plugin/views/display/Feed.php
index bd84581..3170a29 100644
--- a/core/modules/views/src/Plugin/views/display/Feed.php
+++ b/core/modules/views/src/Plugin/views/display/Feed.php
@@ -80,7 +80,7 @@ public function execute() {
 
     $response = $this->view->getResponse();
 
-    $response->setContent($output);
+    $response->setContent(drupal_render($output));
 
     return $response;
   }
@@ -94,7 +94,7 @@ public function preview() {
     if (!empty($this->view->live_preview)) {
       $output = array(
         '#prefix' => '<pre>',
-        '#markup' => String::checkPlain($output),
+        '#markup' => String::checkPlain(drupal_render($output)),
         '#suffix' => '</pre>',
       );
     }
diff --git a/core/modules/views/src/Plugin/views/query/Sql.php b/core/modules/views/src/Plugin/views/query/Sql.php
index 25b1a23..c52ccac 100644
--- a/core/modules/views/src/Plugin/views/query/Sql.php
+++ b/core/modules/views/src/Plugin/views/query/Sql.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Database\DatabaseExceptionWrapper;
 use Drupal\views\Plugin\views\join\JoinPluginBase;
 use Drupal\views\Plugin\views\HandlerBase;
+use Drupal\views\ResultRow;
 use Drupal\views\ViewExecutable;
 use Drupal\views\Views;
 
@@ -1428,7 +1429,12 @@ function execute(ViewExecutable $view) {
 
         $result = $query->execute();
         $result->setFetchMode(\PDO::FETCH_CLASS, 'Drupal\views\ResultRow');
+
+        // Setup the result row objects.
         $view->result = iterator_to_array($result);
+        array_walk($view->result, function(ResultRow $row, $index) {
+          $row->index = $index;
+        });
 
         $view->pager->postExecute($view->result);
         $view->pager->updatePageInfo();
diff --git a/core/modules/views/src/Plugin/views/style/Opml.php b/core/modules/views/src/Plugin/views/style/Opml.php
index 11b359c..7080edb 100644
--- a/core/modules/views/src/Plugin/views/style/Opml.php
+++ b/core/modules/views/src/Plugin/views/style/Opml.php
@@ -83,7 +83,7 @@ public function render() {
       '#rows' => $rows,
     );
     unset($this->view->row_index);
-    return drupal_render($build);
+    return $build;
   }
 
 }
diff --git a/core/modules/views/src/Plugin/views/style/Rss.php b/core/modules/views/src/Plugin/views/style/Rss.php
index e710fac..788e13a 100644
--- a/core/modules/views/src/Plugin/views/style/Rss.php
+++ b/core/modules/views/src/Plugin/views/style/Rss.php
@@ -44,14 +44,10 @@ public function attachTo($display_id, $path, $title) {
     $url = url($this->view->getUrl(NULL, $path), $url_options);
     if ($display->hasPath()) {
       if (empty($this->preview)) {
-        $build['#attached']['drupal_add_feed'][] = array($url, $title);
-        drupal_process_attached($build);
+        drupal_add_feed($url, $title);
       }
     }
     else {
-      if (empty($this->view->feed_icon)) {
-        $this->view->feed_icon = '';
-      }
       $feed_icon = array(
         '#theme' => 'feed_icon',
         '#url' => $url,
@@ -63,7 +59,7 @@ public function attachTo($display_id, $path, $title) {
         'title' => $title,
         'href' => $url,
       );
-      $this->view->feed_icon .= drupal_render($feed_icon);
+      $this->view->feed_icon = $feed_icon;
       drupal_process_attached($feed_icon);
     }
   }
@@ -116,7 +112,7 @@ public function getDescription() {
   public function render() {
     if (empty($this->view->rowPlugin)) {
       debug('Drupal\views\Plugin\views\style\Rss: Missing row plugin');
-      return;
+      return array();
     }
     $rows = '';
 
@@ -145,7 +141,7 @@ public function render() {
       '#rows' => SafeMarkup::set($rows),
     );
     unset($this->view->row_index);
-    return drupal_render($build);
+    return $build;
   }
 
 }
diff --git a/core/modules/views/src/Plugin/views/style/StylePluginBase.php b/core/modules/views/src/Plugin/views/style/StylePluginBase.php
index 0cafc1d..b77228b 100644
--- a/core/modules/views/src/Plugin/views/style/StylePluginBase.php
+++ b/core/modules/views/src/Plugin/views/style/StylePluginBase.php
@@ -476,9 +476,7 @@ public function renderGroupingSets($sets, $level = 0) {
         if ($this->usesRowPlugin()) {
           foreach ($set['rows'] as $index => $row) {
             $this->view->row_index = $index;
-            $render = $this->view->rowPlugin->render($row);
-            // Row render arrays cannot be contained by style render arrays.
-            $set['rows'][$index] = drupal_render($render);
+            $set['rows'][$index] = $this->view->rowPlugin->render($row);
           }
         }
 
diff --git a/core/modules/views/src/ResultRow.php b/core/modules/views/src/ResultRow.php
index 018a0de..a74ed91 100644
--- a/core/modules/views/src/ResultRow.php
+++ b/core/modules/views/src/ResultRow.php
@@ -27,6 +27,13 @@ class ResultRow {
   public $_relationship_entities = array();
 
   /**
+   * An incremental number which represents the row in the entire result.
+   *
+   * @var integer
+   */
+  public $index;
+
+  /**
    * Constructs a ResultRow object.
    *
    * @param array $values
diff --git a/core/modules/views/src/Tests/Plugin/StyleTest.php b/core/modules/views/src/Tests/Plugin/StyleTest.php
index 074abb7..ff87a72 100644
--- a/core/modules/views/src/Tests/Plugin/StyleTest.php
+++ b/core/modules/views/src/Tests/Plugin/StyleTest.php
@@ -144,14 +144,14 @@ function _testGrouping($stripped = FALSE) {
     $expected['Job: Singer']['group'] = 'Job: Singer';
     $expected['Job: Singer']['rows']['Age: 25'] = array();
     $expected['Job: Singer']['rows']['Age: 25']['group'] = 'Age: 25';
-    $expected['Job: Singer']['rows']['Age: 25']['rows'][0] = new ResultRow();
+    $expected['Job: Singer']['rows']['Age: 25']['rows'][0] = new ResultRow(['index' => 0]);
     $expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_name = 'John';
     $expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_job = 'Singer';
     $expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_age = '25';
     $expected['Job: Singer']['rows']['Age: 25']['rows'][0]->views_test_data_id = '1';
     $expected['Job: Singer']['rows']['Age: 27'] = array();
     $expected['Job: Singer']['rows']['Age: 27']['group'] = 'Age: 27';
-    $expected['Job: Singer']['rows']['Age: 27']['rows'][1] = new ResultRow();
+    $expected['Job: Singer']['rows']['Age: 27']['rows'][1] = new ResultRow(['index' => 1]);
     $expected['Job: Singer']['rows']['Age: 27']['rows'][1]->views_test_data_name = 'George';
     $expected['Job: Singer']['rows']['Age: 27']['rows'][1]->views_test_data_job = 'Singer';
     $expected['Job: Singer']['rows']['Age: 27']['rows'][1]->views_test_data_age = '27';
@@ -160,7 +160,7 @@ function _testGrouping($stripped = FALSE) {
     $expected['Job: Drummer']['group'] = 'Job: Drummer';
     $expected['Job: Drummer']['rows']['Age: 28'] = array();
     $expected['Job: Drummer']['rows']['Age: 28']['group'] = 'Age: 28';
-    $expected['Job: Drummer']['rows']['Age: 28']['rows'][2] = new ResultRow();
+    $expected['Job: Drummer']['rows']['Age: 28']['rows'][2] = new ResultRow(['index' => 2]);
     $expected['Job: Drummer']['rows']['Age: 28']['rows'][2]->views_test_data_name = 'Ringo';
     $expected['Job: Drummer']['rows']['Age: 28']['rows'][2]->views_test_data_job = 'Drummer';
     $expected['Job: Drummer']['rows']['Age: 28']['rows'][2]->views_test_data_age = '28';
diff --git a/core/modules/views/src/ViewExecutable.php b/core/modules/views/src/ViewExecutable.php
index cdbd39d..0c2538a 100644
--- a/core/modules/views/src/ViewExecutable.php
+++ b/core/modules/views/src/ViewExecutable.php
@@ -1314,6 +1314,7 @@ public function render($display_id = NULL) {
       $cache = $this->display_handler->getPlugin('cache');
     }
 
+    /** @var \Drupal\views\Plugin\views\cache\CachePluginBase $cache */
     if ($cache && $cache->cacheGet('output')) {
     }
     else {
diff --git a/core/modules/views/tests/src/Plugin/field/CounterTest.php b/core/modules/views/tests/src/Plugin/field/CounterTest.php
index 151b80e..07ba93b 100644
--- a/core/modules/views/tests/src/Plugin/field/CounterTest.php
+++ b/core/modules/views/tests/src/Plugin/field/CounterTest.php
@@ -86,8 +86,8 @@ protected function setUp() {
     $this->view->display_handler = $this->display;
     $this->view->pager = $this->pager;
 
-    foreach (ViewTestData::dataSet() as $set) {
-      $this->testData[] = new ResultRow($set);
+    foreach (ViewTestData::dataSet() as $count => $set) {
+      $this->testData[] = new ResultRow($set + ['index' => $count]);
     }
 
     $this->definition = array('title' => 'counter field', 'plugin_type' => 'field');
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 5a30bf0..2095253 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -128,7 +128,21 @@ function views_theme($existing, $type, $theme, $path) {
     // For displays, we pass in a dummy array as the first parameter, since
     // $view is an object but the core contextual_preprocess() function only
     // attaches contextual links when the primary theme argument is an array.
-    'display' => array('view_array' => array(), 'view' => NULL),
+    'display' => array(
+      'view_array' => array(),
+      'view' => NULL,
+      'rows' => array(),
+      'header' => array(),
+      'footer' => array(),
+      'empty' => array(),
+      'exposed' => array(),
+      'more' => array(),
+      'feed_icon' => array(),
+      'pager' => array(),
+      'title' => '',
+      'attachment_before' => array(),
+      'attachment_after' => array(),
+    ),
     'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL),
     'row' => array('view' => NULL, 'options' => NULL, 'row' => NULL, 'field_alias' => NULL),
     'exposed_form' => array('view' => NULL, 'options' => NULL),
@@ -776,11 +790,12 @@ function views_pre_render_views_form_views_form($element) {
   }
 
   // Apply substitutions to the rendered output.
-  $element['output']['#markup'] = str_replace($search, $replace, $element['output']['#markup']);
+  $element['output'] = array('#markup' => str_replace($search, $replace, drupal_render($element['output'])));
 
   // Sort, render and add remaining form fields.
   $children = Element::children($element, TRUE);
   $element['#children'] = drupal_render_children($element, $children);
+
   return $element;
 }
 
diff --git a/core/modules/views/views.theme.inc b/core/modules/views/views.theme.inc
index 7af7216..2c8ab3d 100644
--- a/core/modules/views/views.theme.inc
+++ b/core/modules/views/views.theme.inc
@@ -23,20 +23,13 @@
  */
 function template_preprocess_views_view(&$variables) {
   $view = $variables['view'];
+  $id = $view->storage->id();
 
-  $variables['rows'] = (!empty($view->result) || $view->style_plugin->evenEmpty()) ? $view->style_plugin->render($view->result) : array();
-  // Force a render array so CSS/JS can be added.
-  if (!is_array($variables['rows'])) {
-    $variables['rows'] = array('#markup' => $variables['rows']);
-  }
-
-  $variables['css_name'] = drupal_clean_css_identifier($view->storage->id());
-  $variables['id'] = $view->storage->id();
+  $variables['css_name'] = drupal_clean_css_identifier($id);
+  $variables['id'] = $id;
   $variables['display_id'] = $view->current_display;
 
   // Basic classes.
-  $variables['css_class'] = '';
-
   $variables['attributes']['class'] = array();
   $variables['attributes']['class'][] = 'view';
   $variables['attributes']['class'][] = 'view-' . drupal_clean_css_identifier($variables['id']);
@@ -49,39 +42,6 @@ function template_preprocess_views_view(&$variables) {
     $variables['attributes']['class'][] = $variables['css_class'];
   }
 
-  $empty = empty($view->result);
-  $variables['header'] = $view->display_handler->renderArea('header', $empty);
-  $variables['footer'] = $view->display_handler->renderArea('footer', $empty);
-  $variables['empty'] = $empty ? $view->display_handler->renderArea('empty', $empty) : FALSE;
-
-  $variables['exposed']    = !empty($view->exposed_widgets) ? $view->exposed_widgets : '';
-  $variables['more']       = $view->display_handler->renderMoreLink();
-  $variables['feed_icon']  = !empty($view->feed_icon) ? $view->feed_icon : '';
-
-  $variables['pager']      = '';
-
-  // @todo: Figure out whether this belongs into views_ui_preprocess_views_view.
-  // Render title for the admin preview.
-  $variables['title'] = !empty($view->views_ui_context) ? Xss::filterAdmin($view->getTitle()) : '';
-
-  if ($view->display_handler->renderPager()) {
-    $exposed_input = isset($view->exposed_raw_input) ? $view->exposed_raw_input : NULL;
-    $variables['pager'] = $view->renderPager($exposed_input);
-  }
-
-  if (!empty($view->attachment_before)) {
-    $variables['attachment_before'] = $view->attachment_before;
-  }
-  else {
-    $variables['attachment_before'] = array();
-  }
-  if (!empty($view->attachment_after)) {
-    $variables['attachment_after'] = $view->attachment_after;
-  }
-  else {
-    $variables['attachment_after'] = array();
-  }
-
   // Add contextual links to the view. We need to attach them to the dummy
   // $view_array variable, since contextual_preprocess() requires that they be
   // attached to an array (not an object) in order to process them. For our
@@ -105,36 +65,6 @@ function template_preprocess_views_view(&$variables) {
     $variables['dom_id'] = $view->dom_id;
     $variables['attributes']['class'][] = 'view-dom-id-' . $variables['dom_id'];
   }
-
-  // If form fields were found in the view, reformat the view output as a form.
-  if ($view->hasFormElements()) {
-    // Copy the rows so as not to modify them by reference when rendering.
-    $rows = $variables['rows'];
-    // Only render row output if there are rows. Otherwise, render the empty
-    // region.
-    if (!empty($rows)) {
-      $output = drupal_render($rows);
-    }
-    else {
-      $empty = $variables['empty'];
-      $output = drupal_render($empty);
-    }
-
-    $container = \Drupal::getContainer();
-    $form_object = new ViewsForm($container->get('class_resolver'), $container->get('url_generator'), $container->get('request_stack'), $view->storage->id(), $view->current_display);
-    $form = \Drupal::formBuilder()->getForm($form_object, $view, $output);
-    // The form is requesting that all non-essential views elements be hidden,
-    // usually because the rendered step is not a view result.
-    if ($form['show_view_elements']['#value'] == FALSE) {
-      $variables['header'] = '';
-      $variables['exposed'] = '';
-      $variables['pager'] = '';
-      $variables['footer'] = '';
-      $variables['more'] = '';
-      $variables['feed_icon'] = '';
-    }
-    $variables['rows'] = $form;
-  }
 }
 
 /**
@@ -162,9 +92,11 @@ function template_preprocess_views_view_fields(&$variables) {
   // Loop through the fields for this view.
   $previous_inline = FALSE;
   $variables['fields'] = array(); // ensure it's at least an empty array.
+  /** @var \Drupal\views\ResultRow $row */
+  $row = $variables['row'];
   foreach ($view->field as $id => $field) {
     // render this even if set to exclude so it can be used elsewhere.
-    $field_output = $view->style_plugin->getField($view->row_index, $id);
+    $field_output = $view->style_plugin->getField($row->index, $id);
     $empty = $field->isValueEmpty($field_output, $field->options['empty_zero']);
     if (empty($field->options['exclude']) && (!$empty || (empty($field->options['hide_empty']) && empty($variables['options']['hide_empty'])))) {
       $object = new stdClass();
@@ -178,7 +110,7 @@ function template_preprocess_views_view_fields(&$variables) {
           $attributes['class'][] = 'field-content';
         }
 
-        if ($classes = $object->handler->elementClasses($view->row_index)) {
+        if ($classes = $object->handler->elementClasses($row->index)) {
           $attributes['class'][] = $classes;
         }
         $attributes = new Attribute($attributes);
@@ -195,8 +127,8 @@ function template_preprocess_views_view_fields(&$variables) {
       }
 
       $object->content = $field_output;
-      if (isset($view->field[$id]->field_alias) && isset($variables['row']->{$view->field[$id]->field_alias})) {
-        $object->raw = $variables['row']->{$view->field[$id]->field_alias};
+      if (isset($view->field[$id]->field_alias) && isset($row->{$view->field[$id]->field_alias})) {
+        $object->raw = $row->{$view->field[$id]->field_alias};
       }
       else {
         $object->raw = NULL; // make sure it exists to reduce NOTICE
@@ -225,7 +157,7 @@ function template_preprocess_views_view_fields(&$variables) {
           $attributes['class'][] = 'views-field-' . $object->class;
         }
 
-        if ($classes = $object->handler->elementWrapperClasses($view->row_index)) {
+        if ($classes = $object->handler->elementWrapperClasses($row->index)) {
           $attributes['class'][] = $classes;
         }
         $attributes = new Attribute($attributes);
@@ -254,7 +186,7 @@ function template_preprocess_views_view_fields(&$variables) {
             $attributes['class'][] = 'views-label-' . $object->class;
           }
 
-          $element_label_class = $object->handler->elementLabelClasses($view->row_index);
+          $element_label_class = $object->handler->elementLabelClasses($row->index);
           if ($element_label_class) {
             $attributes['class'][] = $element_label_class;
           }
diff --git a/core/modules/views_ui/src/ViewUI.php b/core/modules/views_ui/src/ViewUI.php
index 51e16b2..ab77b38 100644
--- a/core/modules/views_ui/src/ViewUI.php
+++ b/core/modules/views_ui/src/ViewUI.php
@@ -590,7 +590,6 @@ public function renderPreview($display_id, $args = array()) {
     if (empty($errors)) {
       $this->ajax = TRUE;
       $this->executable->live_preview = TRUE;
-      $this->views_ui_context = TRUE;
 
       // AJAX happens via HTTP POST but everything expects exposed data to
       // be in GET. Copy stuff but remove ajax-framework specific keys.
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 3c9c234..5e92597 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -13,6 +13,7 @@
 use Drupal\views\Analyzer;
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\ReplaceCommand;
+use Drupal\Component\Utility\Xss;
 
 /**
  * Implements hook_help().
@@ -129,6 +130,12 @@ function views_ui_theme() {
  */
 function views_ui_preprocess_views_view(&$variables) {
   $view = $variables['view'];
+
+  // Render title for the admin preview.
+  if (!empty($view->live_preview)) {
+    $variables['title'] = Xss::filterAdmin($view->getTitle());
+  }
+
   if (!empty($view->live_preview) && \Drupal::moduleHandler()->moduleExists('contextual')) {
     $view->setShowAdminLinks(FALSE);
     foreach (array('title', 'header', 'exposed', 'rows', 'pager', 'more', 'footer', 'empty', 'attachment_after', 'attachment_before') as $section) {
