Index: src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js
===================================================================
--- src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js	(revision 37916)
+++ src/wp-includes/js/tinymce/plugins/wptextpattern/plugin.js	(working copy)
@@ -35,8 +35,14 @@
 
 		var inlinePatterns = [
 			{ start: '`', end: '`', format: 'code' }
+			// { regExp: /(?:^|\s):-?\)/, text: '\ud83d\ude42' },
+			// { regExp: /(?:^|\s)<3/, text: '\u2764\ufe0f' }
 		];
 
+		var smilies = {
+			':)': '\ud83d\ude42'
+		};
+
 		var canUndo;
 		var chars = [];
 
@@ -48,6 +54,14 @@
 			} );
 		} );
 
+		tinymce.each( smilies, function( value, key ) {
+			var c = key.slice( -1 );
+
+			if ( tinymce.inArray( chars, c ) === -1 ) {
+				chars.push( c );
+			}
+		} );
+
 		editor.on( 'selectionchange', function() {
 			canUndo = null;
 		} );
@@ -75,6 +89,7 @@
 			var rng = editor.selection.getRng();
 			var node = rng.startContainer;
 			var offset = rng.startOffset;
+			var findStart;
 			var startOffset;
 			var endOffset;
 			var pattern;
@@ -85,11 +100,12 @@
 				return;
 			}
 
+			// Fast check for matching characters.
 			if ( tinymce.inArray( chars, node.data.charAt( offset - 1 ) ) === -1 ) {
 				return;
 			}
 
-			function findStart( node ) {
+			findStart = function( node ) {
 				var i = inlinePatterns.length;
 				var offset;
 
@@ -101,59 +117,88 @@
 						return offset;
 					}
 				}
-			}
+			};
 
 			startOffset = findStart( node );
-			endOffset = node.data.lastIndexOf( pattern.end );
 
-			if ( startOffset === endOffset || endOffset === -1 ) {
-				return;
-			}
-
-			if ( endOffset - startOffset <= pattern.start.length ) {
-				return;
-			}
+			if ( startOffset ) {
+				endOffset = node.data.lastIndexOf( pattern.end );
 
-			if ( node.data.slice( startOffset + pattern.start.length, endOffset ).indexOf( pattern.start.slice( 0, 1 ) ) !== -1 ) {
-				return;
-			}
-
-			format = editor.formatter.get( pattern.format );
+				if ( startOffset === endOffset || endOffset === -1 ) {
+					return;
+				}
 
-			if ( format && format[0].inline ) {
-				editor.undoManager.add();
+				if ( endOffset - startOffset <= pattern.start.length ) {
+					return;
+				}
 
-				editor.undoManager.transact( function() {
-					node.insertData( offset, '\u200b' );
+				if ( node.data.slice( startOffset + pattern.start.length, endOffset ).indexOf( pattern.start.slice( 0, 1 ) ) !== -1 ) {
+					return;
+				}
 
-					node = node.splitText( startOffset );
-					zero = node.splitText( offset - startOffset );
+				format = editor.formatter.get( pattern.format );
 
-					node.deleteData( 0, pattern.start.length );
-					node.deleteData( node.data.length - pattern.end.length, pattern.end.length );
+				if ( format && format[0].inline ) {
+					editor.undoManager.add();
 
-					editor.formatter.apply( pattern.format, {}, node );
+					editor.undoManager.transact( function() {
+						node.insertData( offset, '\u200b' );
 
-					editor.selection.setCursorLocation( zero, 1 );
-				} );
+						node = node.splitText( startOffset );
+						zero = node.splitText( offset - startOffset );
 
-				// We need to wait for native events to be triggered.
-				setTimeout( function() {
-					canUndo = 'space';
+						node.deleteData( 0, pattern.start.length );
+						node.deleteData( node.data.length - pattern.end.length, pattern.end.length );
 
-					editor.once( 'selectionchange', function() {
-						var offset;
+						editor.formatter.apply( pattern.format, {}, node );
 
-						if ( zero ) {
-							offset = zero.data.indexOf( '\u200b' );
+						editor.selection.setCursorLocation( zero, 1 );
+					} );
 
-							if ( offset !== -1 ) {
-								zero.deleteData( offset, offset + 1 );
+					// We need to wait for native events to be triggered.
+					setTimeout( function() {
+						canUndo = 'space';
+
+						editor.once( 'selectionchange', function() {
+							var offset;
+
+							if ( zero ) {
+								offset = zero.data.indexOf( '\u200b' );
+
+								if ( offset !== -1 ) {
+									zero.deleteData( offset, offset + 1 );
+								}
 							}
-						}
+						} );
 					} );
-				} );
+				}
 			}
+
+			findStart = function( node ) {
+				var key;
+				var offset;
+
+				for ( key in smilies ) {
+					offset = node.data.lastIndexOf( ' ' + key );
+
+					if ( offset !== -1 ) {
+						editor.undoManager.add();
+
+						editor.undoManager.transact( function() {
+							node.replaceData( offset + 1, key.length, smilies[ key ] );
+
+							editor.selection.setCursorLocation( node, offset + 3 );
+						} );
+
+						// We need to wait for native events to be triggered.
+						setTimeout( function() {
+							canUndo = 'space';
+						} );
+					}
+				}
+			};
+
+			findStart( node );
 		}
 
 		function firstTextNode( node ) {
