Index: src/wp-admin/edit-form-advanced.php
===================================================================
--- src/wp-admin/edit-form-advanced.php	(revision 33152)
+++ src/wp-admin/edit-form-advanced.php	(working copy)
@@ -494,7 +494,7 @@
 	$title_placeholder = apply_filters( 'enter_title_here', __( 'Enter title here' ), $post );
 	?>
 	<label class="screen-reader-text" id="title-prompt-text" for="title"><?php echo $title_placeholder; ?></label>
-	<input type="text" name="post_title" size="30" value="<?php echo esc_attr( htmlspecialchars( $post->post_title ) ); ?>" id="title" spellcheck="true" autocomplete="off" />
+	<input type="text" name="post_title" size="30" value="<?php echo esc_attr( $post->post_title ); ?>" id="title" spellcheck="true" autocomplete="off" />
 </div>
 <?php
 /**
Index: src/wp-includes/formatting.php
===================================================================
--- src/wp-includes/formatting.php	(revision 33152)
+++ src/wp-includes/formatting.php	(working copy)
@@ -751,25 +751,14 @@
 		$quote_style = ENT_NOQUOTES;
 	}
 
-	// Handle double encoding ourselves
-	if ( $double_encode ) {
-		$string = @htmlspecialchars( $string, $quote_style, $charset );
-	} else {
-		// Decode &amp; into &
-		$string = wp_specialchars_decode( $string, $_quote_style );
-
-		// Guarantee every &entity; is valid or re-encode the &
+	if ( ! $double_encode ) {
+		// Guarantee every &entity; is valid, convert &garbage; into &amp;garbage;
+		// This is required for PHP < 5.4.0 because ENT_HTML401 flag is unavailable.
 		$string = wp_kses_normalize_entities( $string );
+	}
 
-		// Now re-encode everything except &entity;
-		$string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
+	$string = @htmlspecialchars( $string, $quote_style, $charset, $double_encode );
 
-		for ( $i = 0, $c = count( $string ); $i < $c; $i += 2 ) {
-			$string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset );
-		}
-		$string = implode( '', $string );
-	}
-
 	// Backwards compatibility
 	if ( 'single' === $_quote_style )
 		$string = str_replace( "'", '&#039;', $string );
Index: tests/phpunit/tests/formatting/EscAttr.php
===================================================================
--- tests/phpunit/tests/formatting/EscAttr.php	(revision 33152)
+++ tests/phpunit/tests/formatting/EscAttr.php	(working copy)
@@ -26,7 +26,7 @@
 	}
 
 	function test_esc_attr_amp() {
-		$out = esc_attr( 'foo & bar &baz; &apos;' );
-		$this->assertEquals( "foo &amp; bar &amp;baz; &apos;", $out );
+		$out = esc_attr( 'foo & bar &baz; &nbsp;' );
+		$this->assertEquals( "foo &amp; bar &amp;baz; &nbsp;", $out );
 	}
 }
Index: tests/phpunit/tests/formatting/EscHtml.php
===================================================================
--- tests/phpunit/tests/formatting/EscHtml.php	(revision 33152)
+++ tests/phpunit/tests/formatting/EscHtml.php	(working copy)
@@ -34,7 +34,7 @@
 
 	function test_ignores_existing_entities() {
 		$source = '&#038; &#x00A3; &#x22; &amp;';
-		$res = '&amp; &#xA3; &quot; &amp;';
+		$res = '&#038; &#xA3; &#x22; &amp;';
 		$this->assertEquals( $res, esc_html($source) );
 	}
 }
Index: tests/phpunit/tests/formatting/JSEscape.php
===================================================================
--- tests/phpunit/tests/formatting/JSEscape.php	(revision 33152)
+++ tests/phpunit/tests/formatting/JSEscape.php	(working copy)
@@ -23,13 +23,13 @@
 	}
 
 	function test_js_escape_amp() {
-		$out = esc_js('foo & bar &baz; &apos;');
-		$this->assertEquals("foo &amp; bar &amp;baz; &apos;", $out);
+		$out = esc_js('foo & bar &baz; &nbsp;');
+		$this->assertEquals("foo &amp; bar &amp;baz; &nbsp;", $out);
 	}
 
 	function test_js_escape_quote_entity() {
 		$out = esc_js('foo &#x27; bar &#39; baz &#x26;');
-		$this->assertEquals("foo \\' bar \\' baz &amp;", $out);
+		$this->assertEquals("foo \\' bar \\' baz &#x26;", $out);
 	}
 
 	function test_js_no_carriage_return() {
Index: tests/phpunit/tests/formatting/WPSpecialchars.php
===================================================================
--- tests/phpunit/tests/formatting/WPSpecialchars.php	(revision 33152)
+++ tests/phpunit/tests/formatting/WPSpecialchars.php	(working copy)
@@ -17,6 +17,10 @@
 
 		// Allowed entities should be unchanged
 		foreach ( $allowedentitynames as $ent ) {
+			if ( 'apos' == $ent ) {
+				// But for some reason, PHP doesn't allow &apos;
+				continue;
+			}
 			$ent = '&' . $ent . ';';
 			$this->assertEquals( $ent, _wp_specialchars( $ent ) );
 		}
@@ -39,4 +43,58 @@
 		$this->assertEquals( '&quot;&#039;hello!&#039;&quot;', _wp_specialchars($source, true) );
 		$this->assertEquals( $source, _wp_specialchars($source) );
 	}
+
+	/**
+	 * Check some of the double-encoding features for entity references.
+	 *
+	 * @ticket 17780
+	 * @dataProvider data_double_encoding
+	 */
+	function test_double_encoding( $input, $output ) {
+		return $this->assertEquals( $output, _wp_specialchars( $input, ENT_NOQUOTES, false, true ) );
+	}
+
+	function data_double_encoding() {
+		return array(
+			array(
+				'This & that, this &amp; that, &#8212; &quot; &QUOT; &Uacute; &nbsp; &#34; &#034; &#0034; &#x00022; &#x22; &dollar; &times;',
+				'This &amp; that, this &amp;amp; that, &amp;#8212; &amp;quot; &amp;QUOT; &amp;Uacute; &amp;nbsp; &amp;#34; &amp;#034; &amp;#0034; &amp;#x00022; &amp;#x22; &amp;dollar; &amp;times;',
+			),
+			array(
+				'&& &&amp; &amp;&amp; &amp;;',
+				'&amp;&amp; &amp;&amp;amp; &amp;amp;&amp;amp; &amp;amp;;',
+			),
+			array(
+				'&garbage; &***; &aaaa; &0000; &####; &;;',
+				'&amp;garbage; &amp;***; &amp;aaaa; &amp;0000; &amp;####; &amp;;;',
+			),
+		);
+	}
+
+	/**
+	 * Check some of the double-encoding features for entity references.
+	 *
+	 * @ticket 17780
+	 * @dataProvider data_no_double_encoding
+	 */
+	function test_no_double_encoding( $input, $output ) {
+		return $this->assertEquals( $output, _wp_specialchars( $input, ENT_NOQUOTES, false, false ) );
+	}
+
+	function data_no_double_encoding() {
+		return array(
+			array(
+				'This & that, this &amp; that, &#8212; &quot; &QUOT; &Uacute; &nbsp; &#34; &#034; &#0034; &#x00022; &#x22; &dollar; &times;',
+				'This &amp; that, this &amp; that, &#8212; &quot; &amp;QUOT; &Uacute; &nbsp; &#034; &#034; &#034; &#x22; &#x22; &amp;dollar; &times;',
+			),
+			array(
+				'&& &&amp; &amp;&amp; &amp;;',
+				'&amp;&amp; &amp;&amp; &amp;&amp; &amp;;',
+			),
+			array(
+				'&garbage; &***; &aaaa; &0000; &####; &;;',
+				'&amp;garbage; &amp;***; &amp;aaaa; &amp;0000; &amp;####; &amp;;;',
+			),
+		);
+	}
 }
