diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 2595dd0..f6aa037 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1256,7 +1256,7 @@ function template_preprocess_html(&$variables) {
   // Construct page title.
   if (!empty($variables['page']['#title'])) {
     $head_title = array(
-      'title' => trim(strip_tags($variables['page']['#title'])),
+      'title' => $variables['page']['#title'],
       'name' => $site_config->get('name'),
     );
   }
diff --git a/core/lib/Drupal/Component/Utility/SafeMarkup.php b/core/lib/Drupal/Component/Utility/SafeMarkup.php
index af9170d..28b53e0 100644
--- a/core/lib/Drupal/Component/Utility/SafeMarkup.php
+++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php
@@ -15,9 +15,9 @@
  * provides a store for known safe strings and methods to manage them
  * throughout the page request.
  *
- * Strings sanitized by self::checkPlain() and self::escape() or
- * self::xssFilter() are automatically marked safe, as are markup strings
- * created from @link theme_render render arrays @endlink via drupal_render().
+ * Strings sanitized by self::checkPlain() and self::escape() are automatically
+ * marked safe, as are markup strings created from @link theme_render render
+ * arrays @endlink via drupal_render().
  *
  * This class should be limited to internal use only. Module developers should
  * instead use the appropriate
@@ -139,60 +139,6 @@ public static function escape($string) {
   }
 
   /**
-   * Filters HTML for XSS vulnerabilities and marks the result as safe.
-   *
-   * Calling this method unnecessarily will result in bloating the safe string
-   * list and increases the chance of unintended side effects.
-   *
-   * If Twig receives a value that is not marked as safe then it will
-   * automatically encode special characters in a plain-text string for display
-   * as HTML. Therefore, SafeMarkup::xssFilter() should only be used when the
-   * string might contain HTML that needs to be rendered properly by the
-   * browser.
-   *
-   * If you need to filter for admin use, like Xss::filterAdmin(), then:
-   * - If the string is used as part of a @link theme_render render array @endlink,
-   *   use #markup to allow the render system to filter by the admin tag list
-   *   automatically.
-   * - Otherwise, use the SafeMarkup::xssFilter() with tag list provided by
-   *   Xss::getAdminTagList() instead.
-   *
-   * This method should only be used instead of Xss::filter() when the result is
-   * being added to a render array that is constructed before rendering begins.
-   *
-   * In the rare instance that the caller does not want to filter strings that
-   * are marked safe already, it needs to check SafeMarkup::isSafe() itself.
-   *
-   * @param $string
-   *   The string with raw HTML in it. It will be stripped of everything that
-   *   can cause an XSS attack. The string provided will always be escaped
-   *   regardless of whether the string is already marked as safe.
-   * @param array $html_tags
-   *   (optional) An array of HTML tags. If omitted, it uses the default tag
-   *   list defined by \Drupal\Component\Utility\Xss::filter().
-   *
-   * @return string
-   *   An XSS-safe version of $string, or an empty string if $string is not
-   *   valid UTF-8. The string is marked as safe.
-   *
-   * @ingroup sanitization
-   *
-   * @see \Drupal\Component\Utility\Xss::filter()
-   * @see \Drupal\Component\Utility\Xss::filterAdmin()
-   * @see \Drupal\Component\Utility\Xss::getAdminTagList()
-   * @see \Drupal\Component\Utility\SafeMarkup::isSafe()
-   */
-  public static function xssFilter($string, $html_tags = NULL) {
-    if (is_null($html_tags)) {
-      $string = Xss::filter($string);
-    }
-    else {
-      $string = Xss::filter($string, $html_tags);
-    }
-    return static::set($string);
-  }
-
-  /**
   * Gets all strings currently marked as safe.
   *
   * This is useful for the batch and form APIs, where it is important to
diff --git a/core/lib/Drupal/Component/Utility/Xss.php b/core/lib/Drupal/Component/Utility/Xss.php
index a68ca2b..17e3d4d 100644
--- a/core/lib/Drupal/Component/Utility/Xss.php
+++ b/core/lib/Drupal/Component/Utility/Xss.php
@@ -23,19 +23,13 @@ class Xss {
    */
   protected static $adminTags = array('a', 'abbr', 'acronym', 'address', 'article', 'aside', 'b', 'bdi', 'bdo', 'big', 'blockquote', 'br', 'caption', 'cite', 'code', 'col', 'colgroup', 'command', 'dd', 'del', 'details', 'dfn', 'div', 'dl', 'dt', 'em', 'figcaption', 'figure', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'i', 'img', 'ins', 'kbd', 'li', 'mark', 'menu', 'meter', 'nav', 'ol', 'output', 'p', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'small', 'span', 'strong', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'time', 'tr', 'tt', 'u', 'ul', 'var', 'wbr');
 
+  protected static $htmlTags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd');
   /**
    * Filters HTML to prevent cross-site-scripting (XSS) vulnerabilities.
    *
    * Based on kses by Ulf Harnhammar, see http://sourceforge.net/projects/kses.
    * For examples of various XSS attacks, see: http://ha.ckers.org/xss.html.
    *
-   * This method is preferred to
-   * \Drupal\Component\Utility\SafeMarkup::xssFilter() when the result is not
-   * being used directly in the rendering system (for example, when its result
-   * is being combined with other strings before rendering). This avoids
-   * bloating the safe string list with partial strings if the whole result will
-   * be marked safe.
-   *
    * This code does four things:
    * - Removes characters and constructs that can trick browsers.
    * - Makes sure all HTML entities are well-formed.
@@ -54,11 +48,13 @@ class Xss {
    *   valid UTF-8.
    *
    * @see \Drupal\Component\Utility\Unicode::validateUtf8()
-   * @see \Drupal\Component\Utility\SafeMarkup::xssFilter()
    *
    * @ingroup sanitization
    */
-  public static function filter($string, $html_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd')) {
+  public static function filter($string, array $html_tags = NULL) {
+    if (is_null($html_tags)) {
+      $html_tags = static::$htmlTags;
+    }
     // Only operate on valid UTF-8 strings. This is necessary to prevent cross
     // site scripting issues on Internet Explorer 6.
     if (!Unicode::validateUtf8($string)) {
@@ -108,13 +104,6 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
    * is desired (so \Drupal\Component\Utility\SafeMarkup::checkPlain() is
    * not acceptable).
    *
-   * This method is preferred to
-   * \Drupal\Component\Utility\SafeMarkup::xssFilter() when the result is
-   * not being used directly in the rendering system (for example, when its
-   * result is being combined with other strings before rendering). This avoids
-   * bloating the safe string list with partial strings if the whole result will
-   * be marked safe.
-   *
    * Allows all tags that can be used inside an HTML body, save
    * for scripts and styles.
    *
@@ -126,7 +115,6 @@ public static function filter($string, $html_tags = array('a', 'em', 'strong', '
    *
    * @ingroup sanitization
    *
-   * @see \Drupal\Component\Utility\SafeMarkup::xssFilter()
    * @see \Drupal\Component\Utility\Xss::getAdminTagList()
    *
    */
@@ -347,4 +335,13 @@ public static function getAdminTagList() {
     return static::$adminTags;
   }
 
+  /**
+   * Gets the standard list of html tags allowed by Xss::filter().
+   *
+   * @return array
+   *   The list of html tags allowed by Xss::filter().
+   */
+  public static function getHtmlTagList() {
+    return static::$htmlTags;
+  }
 }
diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php
index 52a849c..a1c2746 100644
--- a/core/lib/Drupal/Core/Render/Renderer.php
+++ b/core/lib/Drupal/Core/Render/Renderer.php
@@ -415,7 +415,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
     if (!empty($elements['#markup'])) {
       // @todo Decide how to support non-HTML in the render API in
       //   https://www.drupal.org/node/2501313.
-      $elements['#markup'] = $this->xssFilterAdminIfUnsafe($elements['#markup']);
+      $elements['#markup'] = $this->safeMarkup($elements);
     }
 
     // Assume that if #theme is set it represents an implemented hook.
@@ -737,6 +737,36 @@ public function addCacheableDependency(array &$elements, $dependency) {
   }
 
   /**
+   * Escapes or filters #markup as required.
+   *
+   * @param array $elements
+   *   A render array with #markup set.
+   *
+   * @return \Drupal\Component\Utility\SafeStringInterface|string
+   *   The escaped string wrapped in a SafeString object. If
+   *   SafeMarkup::isSafe($elements['#markup']) returns TRUE, it won't be
+   *   escaped again.
+   */
+  protected function safeMarkup(array $elements) {
+    $strategy = isset($elements['#markup_safe_strategy']) ? $elements['#markup_safe_strategy'] : $this::SAFE_MARKUP_XSS;
+    if (SafeMarkup::isSafe($elements['#markup'])) {
+      // Nothing to do as #markup is already marked as safe.
+      $string = $elements['#markup'];
+    }
+    elseif ($strategy == $this::SAFE_MARKUP_ESCAPE) {
+      $string = htmlspecialchars($elements['#markup'], ENT_QUOTES, 'UTF-8');
+    }
+    else {
+      // The default behaviour is to XSS filter using the admin tag list.
+      $tags = isset($elements['#markup_xss_tags']) ? $elements['#markup_xss_tags'] : Xss::getAdminTagList();
+      $string = Xss::filter($elements['#markup'], $tags);
+    }
+
+    // @todo Do we need to clean up #markup_safe_strategy and #markup_xss_tags?
+    return SafeString::create($string);
+  }
+
+  /**
    * Applies a very permissive XSS/HTML filter for admin-only use.
    *
    * Note: This method only filters if $string is not marked safe already. This
diff --git a/core/lib/Drupal/Core/Render/RendererInterface.php b/core/lib/Drupal/Core/Render/RendererInterface.php
index 155eec4..5c835c3 100644
--- a/core/lib/Drupal/Core/Render/RendererInterface.php
+++ b/core/lib/Drupal/Core/Render/RendererInterface.php
@@ -12,6 +12,8 @@
  */
 interface RendererInterface {
 
+  const SAFE_MARKUP_XSS = 'xss';
+  const SAFE_MARKUP_ESCAPE = 'escape';
   /**
    * Renders final HTML given a structured array tree.
    *
diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module
index 744861c..4cc4cb4 100644
--- a/core/modules/aggregator/aggregator.module
+++ b/core/modules/aggregator/aggregator.module
@@ -157,16 +157,13 @@ function aggregator_cron() {
 }
 
 /**
- * Renders the HTML content safely, as allowed.
+ * Gets the permitted list of tags.
  *
- * @param string $value
- *   The content to be filtered.
- *
- * @return string
- *   The filtered content.
+ * @return array
+ *   The array of permitted tags.
  */
-function aggregator_filter_xss($value) {
-  return SafeMarkup::xssFilter($value, preg_split('/\s+|<|>/', \Drupal::config('aggregator.settings')->get('items.allowed_html'), -1, PREG_SPLIT_NO_EMPTY));
+function aggregator_xss_tags() {
+  return preg_split('/\s+|<|>/', \Drupal::config('aggregator.settings')->get('items.allowed_html'), -1, PREG_SPLIT_NO_EMPTY);
 }
 
 /**
diff --git a/core/modules/aggregator/src/Controller/AggregatorController.php b/core/modules/aggregator/src/Controller/AggregatorController.php
index 13ff3d9..360a6fe 100644
--- a/core/modules/aggregator/src/Controller/AggregatorController.php
+++ b/core/modules/aggregator/src/Controller/AggregatorController.php
@@ -8,6 +8,7 @@
 namespace Drupal\aggregator\Controller;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\Xss;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Datetime\DateFormatter;
 use Drupal\aggregator\FeedInterface;
@@ -187,7 +188,7 @@ public function pageLast() {
    *   The feed label.
    */
   public function feedTitle(FeedInterface $aggregator_feed) {
-    return SafeMarkup::xssFilter($aggregator_feed->label());
+    return ['#markup' => $aggregator_feed->label(), '#markup_xss_tags' => Xss::getHtmlTagList()];
   }
 
 }
diff --git a/core/modules/aggregator/src/FeedViewBuilder.php b/core/modules/aggregator/src/FeedViewBuilder.php
index 8e4152b..176f35a 100644
--- a/core/modules/aggregator/src/FeedViewBuilder.php
+++ b/core/modules/aggregator/src/FeedViewBuilder.php
@@ -79,7 +79,8 @@ public function buildComponents(array &$build, array $entities, array $displays,
 
       if ($display->getComponent('description')) {
         $build[$id]['description'] = array(
-          '#markup' => aggregator_filter_xss($entity->getDescription()),
+          '#markup' => $entity->getDescription(),
+          '#markup_xss_tags' => aggregator_xss_tags(),
           '#prefix' => '<div class="feed-description">',
           '#suffix' => '</div>',
         );
diff --git a/core/modules/aggregator/src/ItemViewBuilder.php b/core/modules/aggregator/src/ItemViewBuilder.php
index 9207b71..d42a2cf 100644
--- a/core/modules/aggregator/src/ItemViewBuilder.php
+++ b/core/modules/aggregator/src/ItemViewBuilder.php
@@ -26,7 +26,8 @@ public function buildComponents(array &$build, array $entities, array $displays,
 
       if ($display->getComponent('description')) {
         $build[$id]['description'] = array(
-          '#markup' => aggregator_filter_xss($entity->getDescription()),
+          '#markup' => $entity->getDescription(),
+          '#markup_xss_tags' => aggregator_xss_tags(),
           '#prefix' => '<div class="item-description">',
           '#suffix' => '</div>',
         );
diff --git a/core/modules/aggregator/src/Plugin/Field/FieldFormatter/AggregatorXSSFormatter.php b/core/modules/aggregator/src/Plugin/Field/FieldFormatter/AggregatorXSSFormatter.php
index 58d31e1..6bf73bc 100644
--- a/core/modules/aggregator/src/Plugin/Field/FieldFormatter/AggregatorXSSFormatter.php
+++ b/core/modules/aggregator/src/Plugin/Field/FieldFormatter/AggregatorXSSFormatter.php
@@ -36,7 +36,8 @@ public function viewElements(FieldItemListInterface $items) {
     foreach ($items as $delta => $item) {
       $elements[$delta] = [
         '#type' => 'markup',
-        '#markup' => aggregator_filter_xss($item->value),
+        '#markup' => $item->value,
+        '#markup_xss_tags' => aggregator_xss_tags(),
       ];
     }
     return $elements;
diff --git a/core/modules/aggregator/src/Tests/Views/IntegrationTest.php b/core/modules/aggregator/src/Tests/Views/IntegrationTest.php
index 9444808..8b499f5 100644
--- a/core/modules/aggregator/src/Tests/Views/IntegrationTest.php
+++ b/core/modules/aggregator/src/Tests/Views/IntegrationTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\aggregator\Tests\Views;
 
+use Drupal\Component\Utility\Xss;
 use Drupal\Core\Render\RenderContext;
 use Drupal\Core\Url;
 use Drupal\views\Views;
@@ -121,13 +122,13 @@ public function testAggregatorItemView() {
       });
       $this->assertEqual($output, $expected_link, 'Ensure the right link is generated');
 
-      $expected_author = aggregator_filter_xss($items[$iid]->getAuthor());
+      $expected_author = Xss::filter($items[$iid]->getAuthor(), aggregator_xss_tags());
       $output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
         return $view->field['author']->advancedRender($row);
       });
       $this->assertEqual($output, $expected_author, 'Ensure the author got filtered');
 
-      $expected_description = aggregator_filter_xss($items[$iid]->getDescription());
+      $expected_description = Xss::filter($items[$iid]->getDescription(), aggregator_xss_tags());
       $output = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $row) {
         return $view->field['description']->advancedRender($row);
       });
diff --git a/core/modules/dblog/src/Controller/DbLogController.php b/core/modules/dblog/src/Controller/DbLogController.php
index 0d1e4f2..81f9156 100644
--- a/core/modules/dblog/src/Controller/DbLogController.php
+++ b/core/modules/dblog/src/Controller/DbLogController.php
@@ -206,7 +206,7 @@ public function overview() {
           $this->dateFormatter->format($dblog->timestamp, 'short'),
           $message,
           array('data' => $username),
-          SafeMarkup::xssFilter($dblog->link),
+          array('data' => array('#markup' => $dblog->link)),
         ),
         // Attributes for table row.
         'class' => array(Html::getClass('dblog-' . $dblog->type), $classes[$dblog->severity]),
diff --git a/core/modules/filter/src/Plugin/Filter/FilterCaption.php b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
index ed241d8..39ca3ba 100644
--- a/core/modules/filter/src/Plugin/Filter/FilterCaption.php
+++ b/core/modules/filter/src/Plugin/Filter/FilterCaption.php
@@ -45,7 +45,7 @@ public function process($text, $langcode) {
         // Sanitize caption: decode HTML encoding, limit allowed HTML tags; only
         // allow inline tags that are allowed by default, plus <br>.
         $caption = Html::decodeEntities($caption);
-        $caption = SafeMarkup::xssFilter($caption, array('a', 'em', 'strong', 'cite', 'code', 'br'));
+        $caption = ['#markup' => $caption, '#markup_xss_tags' => ['a', 'em', 'strong', 'cite', 'code', 'br']];
 
         // The caption must be non-empty.
         if (Unicode::strlen($caption) === 0) {
diff --git a/core/modules/menu_ui/src/Controller/MenuController.php b/core/modules/menu_ui/src/Controller/MenuController.php
index 560bb18..276cc92 100644
--- a/core/modules/menu_ui/src/Controller/MenuController.php
+++ b/core/modules/menu_ui/src/Controller/MenuController.php
@@ -8,6 +8,7 @@
 namespace Drupal\menu_ui\Controller;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\Xss;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Menu\MenuParentFormSelectorInterface;
 use Drupal\system\MenuInterface;
@@ -77,7 +78,7 @@ public function getParentOptions(Request $request) {
    *   The menu label.
    */
   public function menuTitle(MenuInterface $menu) {
-    return SafeMarkup::xssFilter($menu->label());
+    return ['#markup' => $menu->label(), '#markup_xss_tags' => Xss::getHtmlTagList()];
   }
 
 }
diff --git a/core/modules/node/src/Controller/NodeController.php b/core/modules/node/src/Controller/NodeController.php
index 3291f33..25164e6 100644
--- a/core/modules/node/src/Controller/NodeController.php
+++ b/core/modules/node/src/Controller/NodeController.php
@@ -8,6 +8,7 @@
 namespace Drupal\node\Controller;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\Xss;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Datetime\DateFormatter;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
@@ -194,7 +195,7 @@ public function revisionOverview(NodeInterface $node) {
           '#context' => [
             'date' => $link,
             'username' => $this->renderer->renderPlain($username),
-            'message' => SafeMarkup::xssFilter($revision->revision_log->value),
+            'message' => ['#markup' => $revision->revision_log->value, '#markup_xss_tags' => Xss::getHtmlTagList()],
           ],
         ],
       ];
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index 25d52b5..9d4c340 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -767,7 +767,7 @@ function search_excerpt($keys, $text, $langcode = NULL) {
   // Highlight keywords. Must be done at once to prevent conflicts ('strong'
   // and '<strong>').
   $text = trim(preg_replace('/' . $boundary . '(?:' . implode('|', $keys) . ')' . $boundary . '/iu', '<strong>\0</strong>', ' ' . $text . ' '));
-  return SafeMarkup::xssFilter($text, ['strong']);
+  return ['#markup' => $text, '#markup_xss_tags' => ['strong']];
 }
 
 /**
diff --git a/core/modules/system/templates/html.html.twig b/core/modules/system/templates/html.html.twig
index 50fa76f..50978c7 100644
--- a/core/modules/system/templates/html.html.twig
+++ b/core/modules/system/templates/html.html.twig
@@ -33,7 +33,7 @@
 <html{{ html_attributes }}>
   <head>
     {{ head }}
-    <title>{{ head_title|safe_join(' | ') }}</title>
+    <title>{{ head_title.title|render|striptags|trim }} | {{ head_title.name }}</title>
     {{ styles }}
     {{ scripts }}
   </head>
diff --git a/core/modules/taxonomy/src/Controller/TaxonomyController.php b/core/modules/taxonomy/src/Controller/TaxonomyController.php
index 2e35678..d109b84 100644
--- a/core/modules/taxonomy/src/Controller/TaxonomyController.php
+++ b/core/modules/taxonomy/src/Controller/TaxonomyController.php
@@ -55,7 +55,7 @@ public function addForm(VocabularyInterface $taxonomy_vocabulary) {
    *   The term label.
    */
   public function vocabularyTitle(VocabularyInterface $taxonomy_vocabulary) {
-    return SafeMarkup::xssFilter($taxonomy_vocabulary->label());
+    return ['#markup' => $taxonomy_vocabulary->label(), '#markup_xss_tags' => Xss::getHtmlTagList()];
   }
 
   /**
@@ -68,7 +68,7 @@ public function vocabularyTitle(VocabularyInterface $taxonomy_vocabulary) {
    *   The term label.
    */
   public function termTitle(TermInterface $taxonomy_term) {
-    return SafeMarkup::xssFilter($taxonomy_term->getName());
+    return ['#markup' => $taxonomy_term->getName(), '#markup_xss_tags' => Xss::getHtmlTagList()];
   }
 
 }
diff --git a/core/modules/user/src/Controller/UserController.php b/core/modules/user/src/Controller/UserController.php
index a52372d..d1133aa 100644
--- a/core/modules/user/src/Controller/UserController.php
+++ b/core/modules/user/src/Controller/UserController.php
@@ -162,7 +162,7 @@ public function userPage() {
    *   The user account name.
    */
   public function userTitle(UserInterface $user = NULL) {
-    return $user ? SafeMarkup::xssFilter($user->getUsername()) : '';
+    return $user ? ['#markup' => $user->getUsername(), '#markup_xss_tags' => Xss::getHtmlTagList()] : '';
   }
 
   /**
diff --git a/core/modules/views/src/Plugin/Block/ViewsBlock.php b/core/modules/views/src/Plugin/Block/ViewsBlock.php
index 97db7c9..edad533 100644
--- a/core/modules/views/src/Plugin/Block/ViewsBlock.php
+++ b/core/modules/views/src/Plugin/Block/ViewsBlock.php
@@ -33,8 +33,7 @@ public function build() {
     if ($output = $this->view->buildRenderable($this->displayID, [], FALSE)) {
       // Override the label to the dynamic title configured in the view.
       if (empty($this->configuration['views_label']) && $this->view->getTitle()) {
-        // @todo https://www.drupal.org/node/2527360 remove call to SafeMarkup.
-        $output['#title'] = SafeMarkup::xssFilter($this->view->getTitle(), Xss::getAdminTagList());
+        $output['#title'] = ['#markup' => $this->view->getTitle(), '#markup_xss_tags' => Xss::getHtmlTagList()];
       }
 
       // Before returning the block output, convert it to a renderable array
diff --git a/core/modules/views/src/Plugin/views/display/Page.php b/core/modules/views/src/Plugin/views/display/Page.php
index 7ec3560..7a9b7f5 100644
--- a/core/modules/views/src/Plugin/views/display/Page.php
+++ b/core/modules/views/src/Plugin/views/display/Page.php
@@ -182,8 +182,7 @@ public function execute() {
     //   it should be dropped.
     if (is_array($render)) {
       $render += array(
-        // @todo https://www.drupal.org/node/2527360 remove call to SafeMarkup.
-        '#title' => SafeMarkup::xssFilter($this->view->getTitle(), Xss::getAdminTagList()),
+        '#title' => ['#markup' => $this->view->getTitle(), '#markup_xss_tags' => Xss::getHtmlTagList()],
       );
     }
     return $render;
diff --git a/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
index 90a475f..4769548 100644
--- a/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
@@ -216,36 +216,20 @@ public function testReplace($search, $replace, $subject, $expected, $is_safe) {
   /**
    * Tests the interaction between the safe list and XSS filtering.
    *
-   * @covers ::xssFilter
    * @covers ::escape
    */
   public function testAdminXss() {
-    // Use the predefined XSS admin tag list. This strips the <marquee> tags.
-    $this->assertEquals('text', SafeMarkup::xssFilter('<marquee>text</marquee>', Xss::getAdminTagList()));
-    $this->assertTrue(SafeMarkup::isSafe('text'), 'The string \'text\' is marked as safe.');
-
-    // This won't strip the <marquee> tags and the string with HTML will be
-    // marked as safe.
-    $filtered = SafeMarkup::xssFilter('<marquee>text</marquee>', array('marquee'));
-    $this->assertEquals('<marquee>text</marquee>', $filtered);
-    $this->assertTrue(SafeMarkup::isSafe('<marquee>text</marquee>'), 'The string \'<marquee>text</marquee>\' is marked as safe.');
-
-    // SafeMarkup::xssFilter() with the default tag list will strip the
-    // <marquee> tag even though the string was marked safe above.
-    $this->assertEquals('text', SafeMarkup::xssFilter('<marquee>text</marquee>'));
+    // Mark the string as safe. This is for test purposes only.
+    $text = '<marquee>text</marquee>';
+    SafeMarkup::set($text);
 
     // SafeMarkup::escape() will not escape the markup tag since the string was
     // marked safe above.
-    $this->assertEquals('<marquee>text</marquee>', SafeMarkup::escape($filtered));
+    $this->assertEquals('<marquee>text</marquee>', SafeMarkup::escape($text));
 
     // SafeMarkup::checkPlain() will escape the markup tag even though the
     // string was marked safe above.
-    $this->assertEquals('&lt;marquee&gt;text&lt;/marquee&gt;', SafeMarkup::checkPlain($filtered));
-
-    // Ensure that SafeMarkup::xssFilter strips all tags when passed an empty
-    // array and uses the default tag list when not passed a tag list.
-    $this->assertEquals('text', SafeMarkup::xssFilter('<em>text</em>', []));
-    $this->assertEquals('<em>text</em>', SafeMarkup::xssFilter('<em>text</em>'));
+    $this->assertEquals('&lt;marquee&gt;text&lt;/marquee&gt;', SafeMarkup::checkPlain($text));
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTest.php b/core/tests/Drupal/Tests/Core/Render/RendererTest.php
index c6845f5..76104e5 100644
--- a/core/tests/Drupal/Tests/Core/Render/RendererTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/RendererTest.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Render\Element;
+use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Render\SafeString;
 use Drupal\Core\Template\Attribute;
 
@@ -88,6 +89,22 @@ public function providerTestRenderBasic() {
     $data[] = [[
       'child' => ['#markup' => "This is <script>alert('XSS')</script> test"],
     ], "This is alert('XSS') test"];
+    // XSS filtering test.
+    $data[] = [[
+      'child' => ['#markup' => "This is <script>alert('XSS')</script> test", '#markup_xss_tags' => ['script']],
+    ], "This is <script>alert('XSS')</script> test"];
+    // XSS filtering test.
+    $data[] = [[
+      'child' => ['#markup' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>", '#markup_xss_tags' => ['em', 'strong']],
+    ], "This is <em>alert('XSS')</em> <strong>test</strong>"];
+    // Html escaping test.
+    $data[] = [[
+      'child' => ['#markup' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>", '#markup_safe_strategy' => RendererInterface::SAFE_MARKUP_ESCAPE],
+    ], "This is &lt;script&gt;&lt;em&gt;alert(&#039;XSS&#039;)&lt;/em&gt;&lt;/script&gt; &lt;strong&gt;test&lt;/strong&gt;"];
+    // XSS filtering by default test.
+    $data[] = [[
+      'child' => ['#markup' => "This is <script><em>alert('XSS')</em></script> <strong>test</strong>", '#markup_safe_strategy' => 'nonsense'],
+    ], "This is <em>alert('XSS')</em> <strong>test</strong>"];
     // Ensure non-XSS tags are not filtered out.
     $data[] = [[
       'child' => ['#markup' => "This is <strong><script>alert('not a giraffe')</script></strong> test"],
diff --git a/core/themes/classy/templates/layout/html.html.twig b/core/themes/classy/templates/layout/html.html.twig
index 34c8c56..0dcd35d 100644
--- a/core/themes/classy/templates/layout/html.html.twig
+++ b/core/themes/classy/templates/layout/html.html.twig
@@ -39,7 +39,7 @@
 <html{{ html_attributes }}>
   <head>
     {{ head }}
-    <title>{{ head_title|safe_join(' | ') }}</title>
+    <title>{{ head_title.title|render|striptags|trim }} | {{ head_title.name }}</title>
     {{ styles }}
     {{ scripts }}
   </head>
