Index: src/wp-includes/class-wp-embed.php
===================================================================
--- src/wp-includes/class-wp-embed.php	(revision 33446)
+++ src/wp-includes/class-wp-embed.php	(working copy)
@@ -129,6 +129,11 @@
 	 *                      `->maybe_make_link()` can return false on failure.
 	 */
 	public function shortcode( $attr, $url = '' ) {
+		$custom = apply_filters( 'wp_embed_shortcode_custom', false, $attr, $url );
+		if ( $custom !== false ) {
+			return $custom;
+		}
+		
 		$post = get_post();
 
 		if ( empty( $url ) && ! empty( $attr['src'] ) ) {
@@ -318,11 +323,14 @@
 	 * @return string Potentially modified $content.
 	 */
 	public function autoembed( $content ) {
-		// Strip newlines from all elements.
-		$content = wp_replace_in_html_tags( $content, array( "\n" => " " ) );
+		// Replace line breaks from all HTML elements with placeholders.
+		$content = wp_replace_in_html_tags( $content, array( "\n" => '<!-- wp-line-break -->' ) );
 
 		// Find URLs that are on their own line.
-		return preg_replace_callback( '|^(\s*)(https?://[^\s"]+)(\s*)$|im', array( $this, 'autoembed_callback' ), $content );
+		$content = preg_replace_callback( '|^(\s*)(https?://[^\s"]+)(\s*)$|im', array( $this, 'autoembed_callback' ), $content );
+
+		// Put the line breaks back.
+		return str_replace( '<!-- wp-line-break -->', "\n", $content );
 	}
 
 	/**
Index: src/wp-includes/formatting.php
===================================================================
--- src/wp-includes/formatting.php	(revision 33446)
+++ src/wp-includes/formatting.php	(working copy)
@@ -504,8 +504,8 @@
 	// Standardize newline characters to "\n".
 	$pee = str_replace(array("\r\n", "\r"), "\n", $pee);
 
-	// Strip newlines from all elements.
-	$pee = wp_replace_in_html_tags( $pee, array( "\n" => " " ) );
+	// Find newlines in all elements and add placeholders.
+	$pee = wp_replace_in_html_tags( $pee, array( "\n" => " <!-- wpnl --> " ) );
 
 	// Collapse line breaks before and after <option> elements so they don't get autop'd.
 	if ( strpos( $pee, '<option' ) !== false ) {
@@ -592,10 +592,60 @@
 	if ( !empty($pre_tags) )
 		$pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);
 
+	// Restore newlines in all elements.
+	$pee = str_replace( " <!-- wpnl --> ", "\n", $pee );
+
 	return $pee;
 }
 
 /**
+ * Separate HTML elements and comments from the text.
+ *
+ * @since 4.2.4
+ *
+ * @param string $input The text which has to be formatted.
+ * @return array The formatted text.
+ */
+function wp_html_split( $input ) {
+	static $regex;
+
+	if ( ! isset( $regex ) ) {
+		$comments =
+			  '!'           // Start of comment, after the <.
+			. '(?:'         // Unroll the loop: Consume everything until --> is found.
+			.     '-(?!->)' // Dash not followed by end of comment.
+			.     '[^\-]*+' // Consume non-dashes.
+			. ')*+'         // Loop possessively.
+			. '(?:-->)?';   // End of comment. If not found, match all input.
+
+		$cdata =
+			  '!\[CDATA\['  // Start of comment, after the <.
+			. '[^\]]*+'     // Consume non-].
+			. '(?:'         // Unroll the loop: Consume everything until ]]> is found.
+			.     '](?!]>)' // One ] not followed by end of comment.
+			.     '[^\]]*+' // Consume non-].
+			. ')*+'         // Loop possessively.
+			. '(?:]]>)?';   // End of comment. If not found, match all input.
+
+		$regex =
+			  '/('              // Capture the entire match.
+			.     '<'           // Find start of element.
+			.     '(?(?=!--)'   // Is this a comment?
+			.         $comments // Find end of comment.
+			.     '|'
+			.         '(?(?=!\[CDATA\[)' // Is this a comment?
+			.             $cdata // Find end of comment.
+			.         '|'
+			.             '[^>]*>?' // Find end of element. If not found, match all input.
+			.         ')'
+			.     ')'
+			. ')/s';
+	}
+
+	return preg_split( $regex, $input, -1, PREG_SPLIT_DELIM_CAPTURE );
+}
+
+/**
  * Replace characters or phrases within HTML elements only.
  *
  * @since 4.2.3
@@ -606,25 +656,7 @@
  */
 function wp_replace_in_html_tags( $haystack, $replace_pairs ) {
 	// Find all elements.
-	$comments =
-		  '!'           // Start of comment, after the <.
-		. '(?:'         // Unroll the loop: Consume everything until --> is found.
-		.     '-(?!->)' // Dash not followed by end of comment.
-		.     '[^\-]*+' // Consume non-dashes.
-		. ')*+'         // Loop possessively.
-		. '(?:-->)?';   // End of comment. If not found, match all input.
-
-	$regex =
-		  '/('              // Capture the entire match.
-		.     '<'           // Find start of element.
-		.     '(?(?=!--)'   // Is this a comment?
-		.         $comments // Find end of comment.
-		.     '|'
-		.         '[^>]*>?' // Find end of element. If not found, match all input.
-		.     ')'
-		. ')/s';
-
-	$textarr = preg_split( $regex, $haystack, -1, PREG_SPLIT_DELIM_CAPTURE );
+	$textarr = wp_html_split( $haystack );
 	$changed = false;
 
 	// Optimize when searching for one item.
Index: src/wp-includes/shortcodes.php
===================================================================
--- src/wp-includes/shortcodes.php	(revision 33446)
+++ src/wp-includes/shortcodes.php	(working copy)
@@ -333,29 +333,10 @@
 	$trans = array( '[' => '&#91;', ']' => '&#93;' );
 	
 	$pattern = get_shortcode_regex();
+	$textarr = wp_html_split( $content );
 
-	$comment_regex =
-		  '!'           // Start of comment, after the <.
-		. '(?:'         // Unroll the loop: Consume everything until --> is found.
-		.     '-(?!->)' // Dash not followed by end of comment.
-		.     '[^\-]*+' // Consume non-dashes.
-		. ')*+'         // Loop possessively.
-		. '(?:-->)?';   // End of comment. If not found, match all input.
-
-	$regex =
-		  '/('                   // Capture the entire match.
-		.     '<'                // Find start of element.
-		.     '(?(?=!--)'        // Is this a comment?
-		.         $comment_regex // Find end of comment.
-		.     '|'
-		.         '[^>]*>?'      // Find end of element. If not found, match all input.
-		.     ')'
-		. ')/s';
-
-	$textarr = preg_split( $regex, $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
-
 	foreach ( $textarr as &$element ) {
-		if ( '<' !== $element[0] ) {
+		if ( '' == $element || '<' !== $element[0] ) {
 			continue;
 		}
 
@@ -370,7 +351,7 @@
 			continue;
 		}
 
-		if ( $ignore_html || '<!--' === substr( $element, 0, 4 ) ) {
+		if ( $ignore_html || '<!--' === substr( $element, 0, 4 ) || '<![CDATA[' === substr( $element, 0, 9 ) ) {
 			// Encode all [ and ] chars.
 			$element = strtr( $element, $trans );
 			continue;
Index: tests/phpunit/tests/formatting/Autop.php
===================================================================
--- tests/phpunit/tests/formatting/Autop.php	(revision 33446)
+++ tests/phpunit/tests/formatting/Autop.php	(working copy)
@@ -399,4 +399,50 @@
 
 		$this->assertEquals( $expected, trim( wpautop( $content ) ) );
 	}
+
+	/**
+	 * Do not allow newlines within HTML elements to become mangled.
+	 *
+	 * @ticket 33106
+	 * @dataProvider data_element_sanity
+	 */
+	function test_element_sanity( $input, $output ) {
+		return $this->assertEquals( $output, wpautop( $input ) );
+	}
+
+	function data_element_sanity() {
+		return array(
+			array(
+				"Hello <a\nhref='world'>",
+				"<p>Hello <a\nhref='world'></p>\n",
+			),
+			array(
+				"Hello <!-- a\nhref='world' -->",
+				"<p>Hello <!-- a\nhref='world' --></p>\n",
+			),
+/* Block elements inside comments will fail this test in all versions, it's not a regression.
+			array(
+				"Hello <!-- <hr> a\nhref='world' -->",
+				"<p>Hello <!-- <hr> a\nhref='world' --></p>\n",
+			),
+			array(
+				"Hello <![CDATA[ <hr> a\nhttps://youtu.be/jgz0uSaOZbE\n ]]>",
+				"<p>Hello <![CDATA[ <hr> a\nhttps://youtu.be/jgz0uSaOZbE\n ]]></p>\n",
+			),
+*/
+			array(
+				"Hello <![CDATA[ a\nhttps://youtu.be/jgz0uSaOZbE\n ]]>",
+				"<p>Hello <![CDATA[ a\nhttps://youtu.be/jgz0uSaOZbE\n ]]></p>\n",
+			),
+			array(
+				"Hello <![CDATA[ <!-- a\nhttps://youtu.be/jgz0uSaOZbE\n a\n9 ]]> -->",
+				"<p>Hello <![CDATA[ <!-- a\nhttps://youtu.be/jgz0uSaOZbE\n a\n9 ]]> --></p>\n",
+			),
+			array(
+				"Hello <![CDATA[ <!-- a\nhttps://youtu.be/jgz0uSaOZbE\n a\n9 --> a\n9 ]]>",
+				"<p>Hello <![CDATA[ <!-- a\nhttps://youtu.be/jgz0uSaOZbE\n a\n9 --> a\n9 ]]></p>\n",
+			),
+		);
+	}
+	
 }
