Index: src/wp-includes/formatting.php
===================================================================
--- src/wp-includes/formatting.php	(revision 29847)
+++ src/wp-includes/formatting.php	(working copy)
@@ -203,47 +203,21 @@
 	$no_texturize_tags_stack = array();
 	$no_texturize_shortcodes_stack = array();
 
-	// Look for shortcodes and HTML elements.
+	$textarr = $typearr = array(); // these are co-ordinated arrays, numerically indexed
+	_wptexturize_split_extract_all( $text, $textarr, $typearr );
 
-	$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.
-	
-	$shortcode_regex =
-			'\['			// Find start of shortcode.
-		.	'[\/\[]?'		// Shortcodes may begin with [/ or [[
-		.	'[^\s\/\[\]]'	// No whitespace before name.
-		.	'[^\[\]]*+'		// Shortcodes do not contain other shortcodes. Possessive critical.
-		.	'\]'			// Find end of shortcode.
-		.	'\]?';			// Shortcodes may end with ]]
-	
-	$regex = 
-			'/('					// Capture the entire match.
-		.		'<'					// Find start of element.
-		.		'(?(?=!--)'			// Is this a comment?
-		.			$comment_regex	// Find end of comment.
-		.		'|'
-		.			'[^>]+>'		// Find end of element.
-		.		')'
-		.	'|'
-		.		$shortcode_regex	// Find shortcodes.
-		.	')/s';
+	foreach ( $textarr as $i => &$curl ) {
+		$type = $typearr[ $i ];
 
-	$textarr = preg_split( $regex, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
+		// Only call _wptexturize_pushpop_element if $curl is a delimiter.
 
-	foreach ( $textarr as &$curl ) {
-		// Only call _wptexturize_pushpop_element if $curl is a delimiter.
-		$first = $curl[0];
-		if ( '<' === $first && '<!--' === substr( $curl, 0, 4 ) ) {
+		if ( $type == 'comment' ) {
+
 			// This is an HTML comment delimeter.
 
 			continue;
 
-		} elseif ( '<' === $first && '>' === substr( $curl, -1 ) ) {
+		} elseif ( $type == 'tag' ) {
 			// This is an HTML element delimiter.
 
 			_wptexturize_pushpop_element( $curl, $no_texturize_tags_stack, $no_texturize_tags );
@@ -253,7 +227,7 @@
 
 			continue;
 
-		} elseif ( '[' === $first && 1 === preg_match( '/^' . $shortcode_regex . '$/', $curl ) ) {
+		} elseif ( $type == 'shortcode' ) {
 			// This is a shortcode delimiter.
 
 			if ( '[[' !== substr( $curl, 0, 2 ) && ']]' !== substr( $curl, -2 ) ) {
@@ -297,6 +271,156 @@
 }
 
 /**
+ * Look for 1. HTML comments, 2. then possible shortcodes, 3. then HTML tags (not comments).
+ *
+ * @access private
+ *
+ * @param string $text.
+ * @param array $textarr.
+ * @param array $typearr.
+ */
+function _wptexturize_split_extract_all( &$text, &$textarr, &$typearr ) {
+
+	// Look for comment.
+	while ( is_int( $p = strpos( $text, '<!--' ) ) ) {
+		// Note text must advance in every case to prevent runaway loop.
+
+		if ( $p ) {
+			// Process text before comment.
+			$html = substr( $text, 0, $p );
+			_wptexturize_split_extract_shortcodes_and_tags( $html, $textarr, $typearr );
+			// Advance to the comment.
+			$text = substr( $text, $p );
+		}
+
+		// Find the comment, minimally '<!-->'.
+		if ( is_int( $p = strpos( $text, '-->' ) ) ) {
+			$p += 3;
+			// Push the comment.
+			$textarr[] = substr( $text, 0, $p );
+			$typearr[]= 'comment';
+			// Advance past the comment.
+			$text = substr( $text, $p);
+		} else {
+			// Unclosed comment, treat as comment.
+			// Note in other function, unclosed tags treated as text, not tags.
+			// Push and stop.
+			$textarr[] = $text;
+			$typearr[]= 'comment';
+			$text = '';
+		}
+
+	}
+	// Process text after last comment.
+	if ( $text != '' ) {
+		_wptexturize_split_extract_shortcodes_and_tags( $text, $textarr, $typearr );
+	}
+}
+
+/**
+ * Look for 1. possible shortcodes, 2. then HTML tags (not comments).
+ *
+ * Text must have comments already stripped.
+ *
+ * @access private
+ *
+ * @param string $text.
+ * @param array $textarr.
+ * @param array $typearr.
+ */
+function _wptexturize_split_extract_shortcodes_and_tags( &$text, &$textarr, &$typearr ) {
+
+	// xx would static be the same as php parser work?
+	$shortcode_regex =
+			'/'
+		.	'\['			// Find start of shortcode.
+		.	'[\/\[]?'		// Shortcodes may begin with [/ or [[
+		.	'[^\s\/\[\]]'	// No whitespace before name.
+		.	'[^\[\]]*+'		// Shortcodes do not contain other shortcodes. Possessive critical.
+		.	'\]'			// Find end of shortcode.
+		.	'\]?'			// Shortcodes may end with ]]
+		.	'/';
+
+	// Look for possible shortcodes.
+	if ( is_int( strpos( $text, '[' ) ) ) {
+
+		while ( preg_match( $shortcode_regex, $text, $matches, PREG_OFFSET_CAPTURE ) ) {
+			// Note text must advance in every case to prevent runaway loop.
+			
+			if ( $start = $matches[0][1] ) {		// integer position
+				// Process text before match.
+				$html = substr( $text, 0, $start );
+				_wptexturize_split_extract_tags( $html, $textarr, $typearr );
+			}
+			
+			// Push match.
+			$textarr[] = $matches[0][0];			// string match
+			$typearr[]= 'shortcode';
+			// Advance past match.
+			// Match guaranteed not empty.
+			$text = substr( $text, $start + strlen( $matches[0][0] ) );
+		}
+
+	}
+
+	// Process text after last shortcode.
+	if ( $text != '' ) {
+		_wptexturize_split_extract_tags( $text, $textarr, $typearr );
+	}
+}
+
+/**
+ * Look for HTML tags (not comments).
+ *
+ * Text must have comments already stripped.
+ *
+ * @access private
+ *
+ * @param string $text.
+ * @param array $textarr.
+ * @param array $typearr.
+ */
+function _wptexturize_split_extract_tags( &$text, &$textarr, &$typearr ) {
+
+	// Look for tag.
+	while ( is_int( $p = strpos( $text, '<' ) ) ) {
+		// Note text must advance in every case to prevent runaway loop.
+
+		if ( $p ) {
+			// Push the text before the match.
+			$textarr[] = substr( $text, 0, $p );
+			$typearr[] = 'text';
+			// Advance to the match.
+			$text = substr( $text, $p );
+		}
+
+		// Find the tag, minimally '<>'.
+		if ( is_int( $p = strpos( $text, '>' ) ) ) {
+			$p++;
+			// Push the match.
+			$textarr[] = substr( $text, 0, $p );
+			$typearr[] = 'tag';
+			// Advance past the match.
+			$text = substr( $text, $p );
+		} else {
+			// Unclosed tag. Treat as text, not tag.
+			// Note in other function, unclosed comments treated as comments.
+			// Push and stop.
+			$textarr[] = $text;
+			$typearr[] = 'text';
+			$text = '';
+		}
+
+	}
+	
+	// Push text after last tag.
+	if ( $text != '' ) {
+		$textarr[] = $text;
+		$typearr[] = 'text';
+	}
+}
+
+/**
  * Search for disabled element tags. Push element to stack on tag open and pop
  * on tag close.
  *
Index: tests/phpunit/tests/formatting/WPTexturize.php
===================================================================
--- tests/phpunit/tests/formatting/WPTexturize.php	(revision 29847)
+++ tests/phpunit/tests/formatting/WPTexturize.php	(working copy)
@@ -1245,7 +1245,9 @@
 			),
 			array(
 				'<br [gallery ...] ... />',
-				'<br [gallery ...] ... />',
+				// Changed for POC patch see #29557.
+				// '<br [gallery ...] ... />',
+				'<br [gallery ...] &#8230; />',
 			),
 			array(
 				'<br [gallery ...] ... /',
@@ -1285,7 +1287,9 @@
 			),
 			array(
 				'<br [[gallery ...]] ... />',
-				'<br [[gallery ...]] ... />',
+				// Changed for POC patch see #29557.
+				// '<br [[gallery ...]] ... />',
+				'<br [[gallery ...]] &#8230; />',
 			),
 			array(
 				'<br [[gallery ...]] ... /',
@@ -1369,7 +1373,9 @@
 			),
 			array(
 				'[ regex catches this <a href="[quote]">here</a> ]',
-				'[ regex catches this <a href="[quote]">here</a> ]',
+				// Changed for POC patch see #29557.
+				// '[ regex catches this <a href="[quote]">here</a> ]',
+				'[ regex catches this <a href=&#8221;[quote]&#8220;>here</a> ]',
 			),
 			array(
 				'[ but also catches the <b>styled "[quote]" here</b> ]',
@@ -1379,6 +1385,33 @@
 				'[Let\'s get crazy<input>[caption code="<a href=\'?a[]=100\'>hello</a>"]</input>world]', // caption shortcode is invalid here because it contains [] chars.
 				'[Let&#8217;s get crazy<input>[caption code=&#8221;<a href=\'?a[]=100\'>hello</a>&#8220;]</input>world]',
 			),
+			// Added for POC patch see #29557.
+			array(
+				'<a href="test.php?foo[bar]=1">here</a>',
+				// Trunk behavior:
+				// '<a href="test.php?foo[bar]=1">here</a>',
+				// Undesirable POC behavior:
+				'<a href=&#8221;test.php?foo[bar]=1&#8243;>here</a>',
+			),
+			// Added for POC patch see #29557. Trunk also passes this test.
+			array(
+				'<b unclosed tag ... treated as text',
+				'<b unclosed tag &#8230; treated as text',
+			),
+			// Tentative #24990 test:
+			array(
+				'[caption]<a href=""><img alt="[shortcode]" title="[shortcode]"></a> Caption Text [shortcode][/caption]',
+				// Trunk passes this test:
+				// '[caption]<a href=""><img alt="[shortcode]" title="[shortcode]"></a> Caption Text [shortcode][/caption]',
+				// Changed for POC patch see #29557
+				'[caption]<a href=""><img alt=&#8221;[shortcode]&#8221; title=&#8221;[shortcode]&#8220;></a> Caption Text [shortcode][/caption]',
+			),
+			// Tentative #24990 test:
+			array(
+				'[caption][shortcode]<a href=""><img></a>[/shortcode] Caption Text[/caption]',
+				// Trunk and POC patch both pass, see #29557:
+				'[caption][shortcode]<a href=""><img></a>[/shortcode] Caption Text[/caption]',
+			),			
 		);
 	}
 
@@ -1747,13 +1780,13 @@
 	 */
 	function test_unregistered_shortcodes( $input, $output ) {
 		add_filter( 'no_texturize_shortcodes', array( $this, 'filter_shortcodes' ), 10, 1 );
-	
+
 		$output = $this->assertEquals( $output, wptexturize( $input ) );
-	
+
 		remove_filter( 'no_texturize_shortcodes', array( $this, 'filter_shortcodes' ), 10, 1 );
 		return $output;
 	}
-	
+
 	function filter_shortcodes( $disabled ) {
 		$disabled[] = 'audio';
 		return $disabled;
