diff --git a/core/includes/mail.inc b/core/includes/mail.inc
index 7b08ad3376bcb4e3064376d2b14422aacaf03e98..0209bd501f74af9ab934531b37b0716ce83f0eae 100644
--- a/core/includes/mail.inc
+++ b/core/includes/mail.inc
@@ -5,6 +5,9 @@
  * API functions for processing and sending e-mail.
  */
 
+use Drupal\Component\Utility\Html;
+use Drupal\Component\Utility\Xss;
+
 /**
  * Composes and optionally sends an e-mail message.
  *
@@ -288,7 +291,7 @@ function drupal_html_to_text($string, $allowed_tags = NULL) {
   $allowed_tags = isset($allowed_tags) ? array_intersect($supported_tags, $allowed_tags) : $supported_tags;
 
   // Make sure tags, entities and attributes are well-formed and properly nested.
-  $string = _filter_htmlcorrector(filter_xss($string, $allowed_tags));
+  $string = Html::normalize(Xss::filter($string, $allowed_tags));
 
   // Apply inline styles.
   $string = preg_replace('!</?(em|i)((?> +)[^>]*)?>!i', '/', $string);
diff --git a/core/lib/Drupal/Component/Utility/Html.php b/core/lib/Drupal/Component/Utility/Html.php
new file mode 100644
index 0000000000000000000000000000000000000000..bc0a91621433fb10589ff125854248cb2877e254
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/Html.php
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Component\Utility\Html.
+ */
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Provides DOMDocument helpers for parsing and serializing HTML strings.
+ */
+class Html {
+
+  /**
+   * Normalizes an HTML snippet.
+   *
+   * This function is essentially \DOMDocument::normalizeDocument(), but
+   * operates on an HTML string instead of a \DOMDocument.
+   *
+   * @param string $html
+   *   The HTML string to normalize.
+   *
+   * @return string
+   *   The normalized HTML string.
+   */
+  public static function normalize($html) {
+    $document = static::load($html);
+    return static::serialize($document);
+  }
+
+  /**
+   * Parses an HTML snippet and returns it as a DOM object.
+   *
+   * This function loads the body part of a partial (X)HTML document and returns
+   * a full \DOMDocument object that represents this document.
+   *
+   * Use \Drupal\Component\Utility\Html::serialize() to serialize this
+   * \DOMDocument back to a string.
+   *
+   * @param string $html
+   *   The partial (X)HTML snippet to load. Invalid markup will be corrected on
+   *   import.
+   *
+   * @return \DOMDocument
+   *   A \DOMDocument that represents the loaded (X)HTML snippet.
+   */
+  public static function load($html) {
+    $document = <<<EOD
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>
+<body>!html</body>
+</html>
+EOD;
+    // PHP's \DOMDocument serialization adds straw whitespace in case the markup
+    // of the wrapping document contains newlines, so ensure to remove all
+    // newlines before injecting the actual HTML body to process.
+    $document = strtr($document, array("\n" => '', '!html' => $html));
+
+    $dom = new \DOMDocument();
+    // Ignore warnings during HTML soup loading.
+    @$dom->loadHTML($document);
+
+    return $dom;
+  }
+
+  /**
+   * Converts the body of a \DOMDocument back to an HTML snippet.
+   *
+   * The function serializes the body part of a \DOMDocument back to an (X)HTML
+   * snippet. The resulting (X)HTML snippet will be properly formatted to be
+   * compatible with HTML user agents.
+   *
+   * @param \DOMDocument $document
+   *   A \DOMDocument object to serialize, only the tags below the first <body>
+   *   node will be converted.
+   *
+   * @return string
+   *   A valid (X)HTML snippet, as a string.
+   */
+  public static function serialize(\DOMDocument $document) {
+    $body_node = $document->getElementsByTagName('body')->item(0);
+    $html = '';
+
+    foreach ($body_node->getElementsByTagName('script') as $node) {
+      static::escapeCdataElement($node);
+    }
+    foreach ($body_node->getElementsByTagName('style') as $node) {
+      static::escapeCdataElement($node, '/*', '*/');
+    }
+    foreach ($body_node->childNodes as $node) {
+      $html .= $document->saveXML($node);
+    }
+    return $html;
+  }
+
+  /**
+   * Adds comments around a <!CDATA section in a \DOMNode.
+   *
+   * \DOMDocument::loadHTML() in \Drupal\Component\Utility\Html::load() makes
+   * CDATA sections from the contents of inline script and style tags. This can
+   * cause HTML4 browsers to throw exceptions.
+   *
+   * This function attempts to solve the problem by creating a
+   * \DOMDocumentFragment to comment the CDATA tag.
+   *
+   * @param \DOMNode $node
+   *   The element potentially containing a CDATA node.
+   * @param string $comment_start
+   *   (optional) A string to use as a comment start marker to escape the CDATA
+   *   declaration. Defaults to '//'.
+   * @param string $comment_end
+   *   (optional) A string to use as a comment end marker to escape the CDATA
+   *   declaration. Defaults to an empty string.
+   */
+  public static function escapeCdataElement(\DOMNode $node, $comment_start = '//', $comment_end = '') {
+    foreach ($node->childNodes as $child_node) {
+      if ($child_node instanceof \DOMCdataSection) {
+        $embed_prefix = "\n<!--{$comment_start}--><![CDATA[{$comment_start} ><!--{$comment_end}\n";
+        $embed_suffix = "\n{$comment_start}--><!]]>{$comment_end}\n";
+
+        // Prevent invalid cdata escaping as this would throw a DOM error.
+        // This is the same behavior as found in libxml2.
+        // Related W3C standard: http://www.w3.org/TR/REC-xml/#dt-cdsection
+        // Fix explanation: http://en.wikipedia.org/wiki/CDATA#Nesting
+        $data = str_replace(']]>', ']]]]><![CDATA[>', $child_node->data);
+
+        $fragment = $node->ownerDocument->createDocumentFragment();
+        $fragment->appendXML($embed_prefix . $data . $embed_suffix);
+        $node->appendChild($fragment);
+        $node->removeChild($child_node);
+      }
+    }
+  }
+
+}
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
index a0bf85ea1f955dd7592bd3fc46e34e8b9c6a0750..544ff2e32afc6204635dc70a46195134e0b65715 100644
--- a/core/modules/editor/editor.module
+++ b/core/modules/editor/editor.module
@@ -5,6 +5,7 @@
  * Adds bindings for client-side "text editors" to text formats.
  */
 
+use Drupal\Component\Utility\Html;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\editor\Entity\Editor;
 use Drupal\Component\Utility\NestedArray;
@@ -661,7 +662,7 @@ function _editor_get_processed_text_fields(ContentEntityInterface $entity) {
  *   An array of all found UUIDs.
  */
 function _editor_parse_file_uuids($text) {
-  $dom = filter_dom_load($text);
+  $dom = Html::load($text);
   $xpath = new \DOMXPath($dom);
   $uuids = array();
   foreach ($xpath->query('//*[@data-editor-file-uuid]') as $node) {
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 6a8b941125447bc85e32b34cf043f41a03e657ba..2dd3469c61eea2e409546f7d34688e225a5cd002 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -4,6 +4,8 @@
  * Attach custom data fields to Drupal entities.
  */
 
+use Drupal\Component\Utility\Html;
+use Drupal\Component\Utility\Xss;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Template\Attribute;
 use Drupal\entity\Entity\EntityViewDisplay;
@@ -304,7 +306,7 @@ function field_cache_clear() {
  *   UTF-8.
  */
 function field_filter_xss($string) {
-  return _filter_htmlcorrector(filter_xss($string, _field_filter_xss_allowed_tags()));
+  return Html::normalize(Xss::filter($string, _field_filter_xss_allowed_tags()));
 }
 
 /**
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index 3252cecf78f971d4032bb94dd4e7c856589b78c3..8a643322f96715f158f53ef9db4a90e60c1fbb1b 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -5,6 +5,7 @@
  * Field module functionality for the File module.
  */
 
+use Drupal\Component\Utility\Html;
 use Drupal\field\FieldInterface;
 
 /**
@@ -181,8 +182,8 @@ function theme_file_upload_help($variables) {
 
   $descriptions = array();
 
-  if (strlen($description)) {
-    $descriptions[] = _filter_htmlcorrector($description);
+  if (!empty($description)) {
+    $descriptions[] = Html::normalize($description);
   }
   if (isset($cardinality)) {
     if ($cardinality == -1) {
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 38af864a61372b4e4d01d540575cfe7ce55e9cac..e9c04d43fb349910fcfca8426ac94c9f08fd0818 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -5,6 +5,7 @@
  * Framework for handling the filtering of content.
  */
 
+use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Language\Language;
@@ -693,103 +694,6 @@ function _filter_tips($format_id, $long = FALSE) {
   return $tips;
 }
 
-/**
- * Parses an HTML snippet and returns it as a DOM object.
- *
- * This function loads the body part of a partial (X)HTML document and returns
- * a full DOMDocument object that represents this document. You can use
- * filter_dom_serialize() to serialize this DOMDocument back to a XHTML
- * snippet.
- *
- * @param $text
- *   The partial (X)HTML snippet to load. Invalid markup will be corrected on
- *   import.
- *
- * @return
- *   A DOMDocument that represents the loaded (X)HTML snippet.
- */
-function filter_dom_load($text) {
-  $dom_document = new DOMDocument();
-  // Ignore warnings during HTML soup loading.
-  @$dom_document->loadHTML('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body>' . $text . '</body></html>');
-
-  return $dom_document;
-}
-
-/**
- * Converts a DOM object back to an HTML snippet.
- *
- * The function serializes the body part of a DOMDocument back to an XHTML
- * snippet. The resulting XHTML snippet will be properly formatted to be
- * compatible with HTML user agents.
- *
- * @param $dom_document
- *   A DOMDocument object to serialize, only the tags below
- *   the first <body> node will be converted.
- *
- * @return
- *   A valid (X)HTML snippet, as a string.
- */
-function filter_dom_serialize($dom_document) {
-  $body_node = $dom_document->getElementsByTagName('body')->item(0);
-  $body_content = '';
-
-  foreach ($body_node->getElementsByTagName('script') as $node) {
-    filter_dom_serialize_escape_cdata_element($dom_document, $node);
-  }
-
-  foreach ($body_node->getElementsByTagName('style') as $node) {
-    filter_dom_serialize_escape_cdata_element($dom_document, $node, '/*', '*/');
-  }
-
-  foreach ($body_node->childNodes as $child_node) {
-    $body_content .= $dom_document->saveXML($child_node);
-  }
-  return $body_content;
-}
-
-/**
- * Adds comments around the <!CDATA section in a dom element.
- *
- * DOMDocument::loadHTML in filter_dom_load() makes CDATA sections from the
- * contents of inline script and style tags.  This can cause HTML 4 browsers to
- * throw exceptions.
- *
- * This function attempts to solve the problem by creating a DocumentFragment
- * and imitating the behavior in drupal_get_js(), commenting the CDATA tag.
- *
- * @param $dom_document
- *   The DOMDocument containing the $dom_element.
- * @param $dom_element
- *   The element potentially containing a CDATA node.
- * @param $comment_start
- *   (optional) A string to use as a comment start marker to escape the CDATA
- *   declaration. Defaults to '//'.
- * @param $comment_end
- *   (optional) A string to use as a comment end marker to escape the CDATA
- *   declaration. Defaults to an empty string.
- */
-function filter_dom_serialize_escape_cdata_element($dom_document, $dom_element, $comment_start = '//', $comment_end = '') {
-  foreach ($dom_element->childNodes as $node) {
-    if (get_class($node) == 'DOMCdataSection') {
-      // See drupal_get_js().  This code is more or less duplicated there.
-      $embed_prefix = "\n<!--{$comment_start}--><![CDATA[{$comment_start} ><!--{$comment_end}\n";
-      $embed_suffix = "\n{$comment_start}--><!]]>{$comment_end}\n";
-
-      // Prevent invalid cdata escaping as this would throw a DOM error.
-      // This is the same behavior as found in libxml2.
-      // Related W3C standard: http://www.w3.org/TR/REC-xml/#dt-cdsection
-      // Fix explanation: http://en.wikipedia.org/wiki/CDATA#Nesting
-      $data = str_replace(']]>', ']]]]><![CDATA[>', $node->data);
-
-      $fragment = $dom_document->createDocumentFragment();
-      $fragment->appendXML($embed_prefix . $data . $embed_suffix);
-      $dom_element->appendChild($fragment);
-      $dom_element->removeChild($node);
-    }
-  }
-}
-
 /**
  * Prepares variables for text format guideline templates.
  *
@@ -878,12 +782,12 @@ function _filter_html($text, $filter) {
   $text = filter_xss($text, $allowed_tags);
 
   if ($filter->settings['filter_html_nofollow']) {
-    $html_dom = filter_dom_load($text);
+    $html_dom = Html::load($text);
     $links = $html_dom->getElementsByTagName('a');
     foreach ($links as $link) {
       $link->setAttribute('rel', 'nofollow');
     }
-    $text = filter_dom_serialize($html_dom);
+    $text = Html::serialize($html_dom);
   }
 
   return trim($text);
@@ -1127,13 +1031,6 @@ function _filter_url_trim($text, $length = NULL) {
   return $text;
 }
 
-/**
- * Scans the input and makes sure that HTML tags are properly closed.
- */
-function _filter_htmlcorrector($text) {
-  return filter_dom_serialize(filter_dom_load($text));
-}
-
 /**
  * Converts line breaks into <p> and <br> in an intelligent fashion.
  *
@@ -1219,7 +1116,7 @@ function _filter_html_image_secure_process($text) {
   // Find the directory on the server where index.php resides.
   $local_dir = DRUPAL_ROOT . '/';
 
-  $html_dom = filter_dom_load($text);
+  $html_dom = Html::load($text);
   $images = $html_dom->getElementsByTagName('img');
   foreach ($images as $image) {
     $src = $image->getAttribute('src');
@@ -1245,7 +1142,7 @@ function _filter_html_image_secure_process($text) {
     // indicator. See filter_filter_secure_image_alter().
     \Drupal::moduleHandler()->alter('filter_secure_image', $image);
   }
-  $text = filter_dom_serialize($html_dom);
+  $text = Html::serialize($html_dom);
   return $text;
 }
 
diff --git a/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterCaption.php b/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterCaption.php
index 5b5ce632edcc6880ecece728a7e1f4b5d385d2b0..51cb70a37b62f5a0440f283cf731a3206f134e0f 100644
--- a/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterCaption.php
+++ b/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterCaption.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\filter\Plugin\Filter;
 
+use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\String;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\Xss;
@@ -30,7 +31,7 @@ class FilterCaption extends FilterBase {
   public function process($text, $langcode, $cache, $cache_id) {
 
     if (stristr($text, 'data-caption') !== FALSE || stristr($text, 'data-align') !== FALSE) {
-      $dom = filter_dom_load($text);
+      $dom = Html::load($text);
       $xpath = new \DOMXPath($dom);
       foreach ($xpath->query('//*[@data-caption or @data-align]') as $node) {
         $caption = NULL;
@@ -82,7 +83,7 @@ public function process($text, $langcode, $cache, $cache_id) {
         $altered_html = drupal_render($filter_caption);
 
         // Load the altered HTML into a new DOMDocument and retrieve the element.
-        $updated_node = filter_dom_load($altered_html)->getElementsByTagName('body')
+        $updated_node = Html::load($altered_html)->getElementsByTagName('body')
           ->item(0)
           ->childNodes
           ->item(0);
@@ -94,7 +95,7 @@ public function process($text, $langcode, $cache, $cache_id) {
         $node->parentNode->replaceChild($updated_node, $node);
       }
 
-      return filter_dom_serialize($dom);
+      return Html::serialize($dom);
     }
 
     return $text;
diff --git a/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterHtmlCorrector.php b/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterHtmlCorrector.php
index 8d9b8e0abbbbc756ca3e2acfe6aa6b708bd58f46..bc0a036f51ccf3458be22e321d08c607ce6d9133 100644
--- a/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterHtmlCorrector.php
+++ b/core/modules/filter/lib/Drupal/filter/Plugin/Filter/FilterHtmlCorrector.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\filter\Plugin\Filter;
 
+use Drupal\Component\Utility\Html;
 use Drupal\filter\Plugin\FilterBase;
 
 /**
@@ -25,7 +26,7 @@ class FilterHtmlCorrector extends FilterBase {
    * {@inheritdoc}
    */
   public function process($text, $langcode, $cache, $cache_id) {
-    return _filter_htmlcorrector($text);
+    return Html::normalize($text);
   }
 
 }
diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterUnitTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterUnitTest.php
index f686cee49ff979442d8892bdebbe5f1406bd5b78..a51d6b9bd1c72a8f337d860435448e522831ebe0 100644
--- a/core/modules/filter/lib/Drupal/filter/Tests/FilterUnitTest.php
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterUnitTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\filter\Tests;
 
+use Drupal\Component\Utility\Html;
 use Drupal\simpletest\DrupalUnitTestBase;
 use Drupal\filter\FilterBag;
 
@@ -741,117 +742,117 @@ function testUrlFilterContent() {
    */
   function testHtmlCorrectorFilter() {
     // Tag closing.
-    $f = _filter_htmlcorrector('<p>text');
+    $f = Html::normalize('<p>text');
     $this->assertEqual($f, '<p>text</p>', 'HTML corrector -- tag closing at the end of input.');
 
-    $f = _filter_htmlcorrector('<p>text<p><p>text');
+    $f = Html::normalize('<p>text<p><p>text');
     $this->assertEqual($f, '<p>text</p><p></p><p>text</p>', 'HTML corrector -- tag closing.');
 
-    $f = _filter_htmlcorrector("<ul><li>e1<li>e2");
+    $f = Html::normalize("<ul><li>e1<li>e2");
     $this->assertEqual($f, "<ul><li>e1</li><li>e2</li></ul>", 'HTML corrector -- unclosed list tags.');
 
-    $f = _filter_htmlcorrector('<div id="d">content');
+    $f = Html::normalize('<div id="d">content');
     $this->assertEqual($f, '<div id="d">content</div>', 'HTML corrector -- unclosed tag with attribute.');
 
     // XHTML slash for empty elements.
-    $f = _filter_htmlcorrector('<hr><br>');
+    $f = Html::normalize('<hr><br>');
     $this->assertEqual($f, '<hr /><br />', 'HTML corrector -- XHTML closing slash.');
 
-    $f = _filter_htmlcorrector('<P>test</P>');
+    $f = Html::normalize('<P>test</P>');
     $this->assertEqual($f, '<p>test</p>', 'HTML corrector -- Convert uppercased tags to proper lowercased ones.');
 
-    $f = _filter_htmlcorrector('<P>test</p>');
+    $f = Html::normalize('<P>test</p>');
     $this->assertEqual($f, '<p>test</p>', 'HTML corrector -- Convert uppercased tags to proper lowercased ones.');
 
-    $f = _filter_htmlcorrector('test<hr />');
+    $f = Html::normalize('test<hr />');
     $this->assertEqual($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through.');
 
-    $f = _filter_htmlcorrector('test<hr/>');
+    $f = Html::normalize('test<hr/>');
     $this->assertEqual($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through, but ensure there is a single space before the closing slash.');
 
-    $f = _filter_htmlcorrector('test<hr    />');
+    $f = Html::normalize('test<hr    />');
     $this->assertEqual($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through, but ensure there are not too many spaces before the closing slash.');
 
-    $f = _filter_htmlcorrector('<span class="test" />');
+    $f = Html::normalize('<span class="test" />');
     $this->assertEqual($f, '<span class="test"></span>', 'HTML corrector -- Convert XHTML that is properly formed but that would not be compatible with typical HTML user agents.');
 
-    $f = _filter_htmlcorrector('test1<br class="test">test2');
+    $f = Html::normalize('test1<br class="test">test2');
     $this->assertEqual($f, 'test1<br class="test" />test2', 'HTML corrector -- Automatically close single tags.');
 
-    $f = _filter_htmlcorrector('line1<hr>line2');
+    $f = Html::normalize('line1<hr>line2');
     $this->assertEqual($f, 'line1<hr />line2', 'HTML corrector -- Automatically close single tags.');
 
-    $f = _filter_htmlcorrector('line1<HR>line2');
+    $f = Html::normalize('line1<HR>line2');
     $this->assertEqual($f, 'line1<hr />line2', 'HTML corrector -- Automatically close single tags.');
 
-    $f = _filter_htmlcorrector('<img src="http://example.com/test.jpg">test</img>');
+    $f = Html::normalize('<img src="http://example.com/test.jpg">test</img>');
     $this->assertEqual($f, '<img src="http://example.com/test.jpg" />test', 'HTML corrector -- Automatically close single tags.');
 
-    $f = _filter_htmlcorrector('<br></br>');
+    $f = Html::normalize('<br></br>');
     $this->assertEqual($f, '<br />', "HTML corrector -- Transform empty tags to a single closed tag if the tag's content model is EMPTY.");
 
-    $f = _filter_htmlcorrector('<div></div>');
+    $f = Html::normalize('<div></div>');
     $this->assertEqual($f, '<div></div>', "HTML corrector -- Do not transform empty tags to a single closed tag if the tag's content model is not EMPTY.");
 
-    $f = _filter_htmlcorrector('<p>line1<br/><hr/>line2</p>');
+    $f = Html::normalize('<p>line1<br/><hr/>line2</p>');
     $this->assertEqual($f, '<p>line1<br /></p><hr />line2', 'HTML corrector -- Move non-inline elements outside of inline containers.');
 
-    $f = _filter_htmlcorrector('<p>line1<div>line2</div></p>');
+    $f = Html::normalize('<p>line1<div>line2</div></p>');
     $this->assertEqual($f, '<p>line1</p><div>line2</div>', 'HTML corrector -- Move non-inline elements outside of inline containers.');
 
-    $f = _filter_htmlcorrector('<p>test<p>test</p>\n');
+    $f = Html::normalize('<p>test<p>test</p>\n');
     $this->assertEqual($f, '<p>test</p><p>test</p>\n', 'HTML corrector -- Auto-close improperly nested tags.');
 
-    $f = _filter_htmlcorrector('<p>Line1<br><STRONG>bold stuff</b>');
+    $f = Html::normalize('<p>Line1<br><STRONG>bold stuff</b>');
     $this->assertEqual($f, '<p>Line1<br /><strong>bold stuff</strong></p>', 'HTML corrector -- Properly close unclosed tags, and remove useless closing tags.');
 
-    $f = _filter_htmlcorrector('test <!-- this is a comment -->');
+    $f = Html::normalize('test <!-- this is a comment -->');
     $this->assertEqual($f, 'test <!-- this is a comment -->', 'HTML corrector -- Do not touch HTML comments.');
 
-    $f = _filter_htmlcorrector('test <!--this is a comment-->');
+    $f = Html::normalize('test <!--this is a comment-->');
     $this->assertEqual($f, 'test <!--this is a comment-->', 'HTML corrector -- Do not touch HTML comments.');
 
-    $f = _filter_htmlcorrector('test <!-- comment <p>another
+    $f = Html::normalize('test <!-- comment <p>another
     <strong>multiple</strong> line
     comment</p> -->');
     $this->assertEqual($f, 'test <!-- comment <p>another
     <strong>multiple</strong> line
     comment</p> -->', 'HTML corrector -- Do not touch HTML comments.');
 
-    $f = _filter_htmlcorrector('test <!-- comment <p>another comment</p> -->');
+    $f = Html::normalize('test <!-- comment <p>another comment</p> -->');
     $this->assertEqual($f, 'test <!-- comment <p>another comment</p> -->', 'HTML corrector -- Do not touch HTML comments.');
 
-    $f = _filter_htmlcorrector('test <!--break-->');
+    $f = Html::normalize('test <!--break-->');
     $this->assertEqual($f, 'test <!--break-->', 'HTML corrector -- Do not touch HTML comments.');
 
-    $f = _filter_htmlcorrector('<p>test\n</p>\n');
+    $f = Html::normalize('<p>test\n</p>\n');
     $this->assertEqual($f, '<p>test\n</p>\n', 'HTML corrector -- New-lines are accepted and kept as-is.');
 
-    $f = _filter_htmlcorrector('<p>دروبال');
+    $f = Html::normalize('<p>دروبال');
     $this->assertEqual($f, '<p>دروبال</p>', 'HTML corrector -- Encoding is correctly kept.');
 
-    $f = _filter_htmlcorrector('<script>alert("test")</script>');
+    $f = Html::normalize('<script>alert("test")</script>');
     $this->assertEqual($f, '<script>
 <!--//--><![CDATA[// ><!--
 alert("test")
 //--><!]]>
 </script>', 'HTML corrector -- CDATA added to script element');
 
-    $f = _filter_htmlcorrector('<p><script>alert("test")</script></p>');
+    $f = Html::normalize('<p><script>alert("test")</script></p>');
     $this->assertEqual($f, '<p><script>
 <!--//--><![CDATA[// ><!--
 alert("test")
 //--><!]]>
 </script></p>', 'HTML corrector -- CDATA added to a nested script element');
 
-    $f = _filter_htmlcorrector('<p><style> /* Styling */ body {color:red}</style></p>');
+    $f = Html::normalize('<p><style> /* Styling */ body {color:red}</style></p>');
     $this->assertEqual($f, '<p><style>
 <!--/*--><![CDATA[/* ><!--*/
  /* Styling */ body {color:red}
 /*--><!]]>*/
 </style></p>', 'HTML corrector -- CDATA added to a style element.');
 
-    $filtered_data = _filter_htmlcorrector('<p><style>
+    $filtered_data = Html::normalize('<p><style>
 /*<![CDATA[*/
 /* Styling */
 body {color:red}
@@ -870,7 +871,7 @@ function testHtmlCorrectorFilter() {
       format_string('HTML corrector -- Existing cdata section @pattern_name properly escaped', array('@pattern_name' => '/*<![CDATA[*/'))
     );
 
-    $filtered_data = _filter_htmlcorrector('<p><style>
+    $filtered_data = Html::normalize('<p><style>
   <!--/*--><![CDATA[/* ><!--*/
   /* Styling */
   body {color:red}
@@ -889,7 +890,7 @@ function testHtmlCorrectorFilter() {
       format_string('HTML corrector -- Existing cdata section @pattern_name properly escaped', array('@pattern_name' => '<!--/*--><![CDATA[/* ><!--*/'))
     );
 
-    $filtered_data = _filter_htmlcorrector('<p><script>
+    $filtered_data = Html::normalize('<p><script>
 <!--//--><![CDATA[// ><!--
   alert("test");
 //--><!]]>
@@ -906,7 +907,7 @@ function testHtmlCorrectorFilter() {
       format_string('HTML corrector -- Existing cdata section @pattern_name properly escaped', array('@pattern_name' => '<!--//--><![CDATA[// ><!--'))
     );
 
-    $filtered_data = _filter_htmlcorrector('<p><script>
+    $filtered_data = Html::normalize('<p><script>
 // <![CDATA[
   alert("test");
 // ]]>
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
index a42f111bcfeefa182391835b766e28cef87b5e8b..d4655306c3dc312b744b692ca3f90ab46fc39f40 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Tests\Common;
 
+use Drupal\Component\Utility\Html;
 use Drupal\simpletest\DrupalUnitTestBase;
 
 /**
@@ -616,7 +617,7 @@ function testDrupalRenderChildrenPostRenderCache() {
       ),
     );
 
-    $dom = filter_dom_load($cached_element['#markup']);
+    $dom = Html::load($cached_element['#markup']);
     $xpath = new \DOMXPath($dom);
     $parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length;
     $child =  $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length;
@@ -699,7 +700,7 @@ function testDrupalRenderChildrenPostRenderCache() {
       ),
     );
 
-    $dom = filter_dom_load($cached_parent_element['#markup']);
+    $dom = Html::load($cached_parent_element['#markup']);
     $xpath = new \DOMXPath($dom);
     $parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length;
     $child =  $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length;
@@ -724,7 +725,7 @@ function testDrupalRenderChildrenPostRenderCache() {
       ),
     );
 
-    $dom = filter_dom_load($cached_child_element['#markup']);
+    $dom = Html::load($cached_child_element['#markup']);
     $xpath = new \DOMXPath($dom);
     $child =  $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length;
     $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length;
@@ -806,7 +807,7 @@ function testDrupalRenderRenderCachePlaceholder() {
     $element = array('#cache' => array('cid' => 'render_cache_placeholder_test_GET'));
     $cached_element = cache()->get(drupal_render_cid_create($element))->data;
     // Parse unique token out of the markup.
-    $dom = filter_dom_load($cached_element['#markup']);
+    $dom = Html::load($cached_element['#markup']);
     $xpath = new \DOMXPath($dom);
     $nodes = $xpath->query('//*[@token]');
     $token = $nodes->item(0)->getAttribute('token');
diff --git a/core/modules/text/text.module b/core/modules/text/text.module
index 675c63e42dad99bedd56814718f79d40c4da6b96..b0eb8fa7edba026a8a56d623429204bf408552c1 100644
--- a/core/modules/text/text.module
+++ b/core/modules/text/text.module
@@ -5,6 +5,7 @@
  * Defines simple text field types.
  */
 
+use Drupal\Component\Utility\Html;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -170,7 +171,7 @@ function text_summary($text, $format = NULL, $size = NULL) {
 
   // If the htmlcorrector filter is present, apply it to the generated summary.
   if (isset($format) && $filters->has('filter_htmlcorrector') && $filters->get('filter_htmlcorrector')->status) {
-    $summary = _filter_htmlcorrector($summary);
+    $summary = Html::normalize($summary);
   }
 
   return $summary;
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
index aaf6e894d08081a61ec2a407cd9858319dde76bb..5f66de4db4ef7c591baf30f56ad78868d3fde52f 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/FieldPluginBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\views\Plugin\views\field;
 
+use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\String;
 use Drupal\views\Plugin\views\HandlerBase;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
@@ -1681,7 +1682,7 @@ public static function trimText($alter, $value) {
       }
     }
     if (!empty($alter['html'])) {
-      $value = _filter_htmlcorrector($value);
+      $value = Html::normalize($value);
     }
 
     return $value;