Index: src/wp-admin/css/customize-controls.css
===================================================================
--- src/wp-admin/css/customize-controls.css	(revision 32993)
+++ src/wp-admin/css/customize-controls.css	(working copy)
@@ -762,6 +788,7 @@
 .customize-control-upload .current,
 .customize-control-image .current,
 .customize-control-background .current,
+.customize-control-cropped_image .current,
 .customize-control-header .current {
 	margin-bottom: 8px;
 }
@@ -797,6 +824,9 @@
 .customize-control-background .remove-button,
 .customize-control-background .default-button,
 .customize-control-background .upload-button,
+.customize-control-cropped_image .remove-button,
+.customize-control-cropped_image .default-button,
+.customize-control-cropped_image .upload-button,
 .customize-control-header button.new,
 .customize-control-header button.remove {
 	white-space: normal;
@@ -808,6 +838,7 @@
 .customize-control-upload .current .container,
 .customize-control-image .current .container,
 .customize-control-background .current .container,
+.customize-control-cropped_image .current .container,
 .customize-control-header .current .container {
 	overflow: hidden;
 	-webkit-border-radius: 2px;
@@ -819,6 +850,7 @@
 .customize-control-media .current .container,
 .customize-control-upload .current .container,
 .customize-control-background .current .container,
+.customize-control-cropped_image .current .container,
 .customize-control-image .current .container {
 	min-height: 40px;
 }
@@ -827,6 +859,7 @@
 .customize-control-upload .placeholder,
 .customize-control-image .placeholder,
 .customize-control-background .placeholder,
+.customize-control-cropped_image .placeholder,
 .customize-control-header .placeholder {
 	width: 100%;
 	position: relative;
@@ -838,6 +871,7 @@
 .customize-control-upload .inner,
 .customize-control-image .inner,
 .customize-control-background .inner,
+.customize-control-cropped_image .inner,
 .customize-control-header .inner {
 	display: none;
 	position: absolute;
@@ -851,6 +885,7 @@
 .customize-control-media .inner,
 .customize-control-upload .inner,
 .customize-control-background .inner,
+.customize-control-cropped_image .inner,
 .customize-control-image .inner {
 	display: block;
 	min-height: 40px;
@@ -860,6 +895,7 @@
 .customize-control-upload .inner,
 .customize-control-image .inner,
 .customize-control-background .inner,
+.customize-control-cropped_image .inner,
 .customize-control-header .inner,
 .customize-control-header .inner .dashicons {
 	line-height: 20px;
@@ -963,6 +999,7 @@
 .customize-control-upload .actions,
 .customize-control-image .actions,
 .customize-control-background .actions,
+.customize-control-cropped_image .actions,
 .customize-control-header .actions {
 	margin-bottom: 32px;
 }
@@ -981,6 +1018,7 @@
 .customize-control-upload img,
 .customize-control-image img,
 .customize-control-background img,
+.customize-control-cropped_image img,
 .customize-control-header img {
 	width: 100%;
 	-webkit-border-radius: 2px;
@@ -995,6 +1033,8 @@
 .customize-control-image .default-button,
 .customize-control-background .remove-button,
 .customize-control-background .default-button,
+.customize-control-cropped_image .remove-button,
+.customize-control-cropped_image .default-button,
 .customize-control-header .remove {
 	float: left;
 	margin-right: 3px;
@@ -1004,6 +1044,7 @@
 .customize-control-upload .upload-button,
 .customize-control-image .upload-button,
 .customize-control-background .upload-button,
+.customize-control-cropped_image .upload-button,
 .customize-control-header .new {
 	float: right;
 }
Index: src/wp-admin/js/customize-controls.js
===================================================================
--- src/wp-admin/js/customize-controls.js	(revision 32993)
+++ src/wp-admin/js/customize-controls.js	(working copy)
@@ -1795,7 +1795,7 @@
 	 * @augments wp.customize.Control
 	 * @augments wp.customize.Class
 	 */
-	api.ImageControl = api.UploadControl.extend({
+	api.ImageControl = api.MediaControl.extend({
 		// @deprecated
 		thumbnailSrc: function() {}
 	});
@@ -1836,78 +1836,82 @@
 	});
 
 	/**
+	 * A control for selecting and cropping an image.
+	 *
 	 * @class
+	 * @augments wp.customize.MediaControl
 	 * @augments wp.customize.Control
 	 * @augments wp.customize.Class
 	 */
-	api.HeaderControl = api.Control.extend({
-		ready: function() {
-			this.btnRemove = $('#customize-control-header_image .actions .remove');
-			this.btnNew    = $('#customize-control-header_image .actions .new');
+	api.CroppedImageControl = api.MediaControl.extend({
+		/**
+		 * Open the media modal to the library state.
+		 */
+		openFrame: function( event ) {
+			if ( api.utils.isKeydownButNotEnterEvent( event ) ) {
+				return;
+			}
 
-			_.bindAll(this, 'openMedia', 'removeImage');
+			if ( this.frame ) {
+				this.frame.setState( 'library' );
+			}
 
-			this.btnNew.on( 'click', this.openMedia );
-			this.btnRemove.on( 'click', this.removeImage );
+			api.MediaControl.prototype.openFrame.call( this, event );
+		},
 
-			api.HeaderTool.currentHeader = this.getInitialHeaderImage();
+		/**
+		 * Create a media modal select frame, and store it so the instance can be reused when needed.
+		 */
+		initFrame: function() {
+			var l10n = _wpMediaViewsL10n;
 
-			new api.HeaderTool.CurrentView({
-				model: api.HeaderTool.currentHeader,
-				el: '#customize-control-header_image .current .container'
+			this.frame = wp.media({
+				button: {
+					text: l10n.selectAndCrop,
+					close: false
+				},
+				states: [
+					new wp.media.controller.Library({
+						title:     this.params.button_labels.frame_title,
+						library:   wp.media.query({ type: 'image' }),
+						multiple:  false,
+						date:      false,
+						priority:  20,
+						suggestedWidth: this.params.width,
+						suggestedHeight: this.params.height
+					}),
+					new wp.media.controller.customizeImageCropper({
+						imgSelectOptions: this.calculateImageSelectOptions,
+						control: this
+					})
+				]
 			});
 
-			new api.HeaderTool.ChoiceListView({
-				collection: api.HeaderTool.UploadsList = new api.HeaderTool.ChoiceList(),
-				el: '#customize-control-header_image .choices .uploaded .list'
-			});
+			this.frame.on( 'select', this.onSelect, this );
+			this.frame.on( 'cropped', this.onCropped, this );
+			this.frame.on( 'skippedcrop', this.onSkippedCrop, this );
+		},
 
-			new api.HeaderTool.ChoiceListView({
-				collection: api.HeaderTool.DefaultsList = new api.HeaderTool.DefaultsList(),
-				el: '#customize-control-header_image .choices .default .list'
-			});
-
-			api.HeaderTool.combinedList = api.HeaderTool.CombinedList = new api.HeaderTool.CombinedList([
-				api.HeaderTool.UploadsList,
-				api.HeaderTool.DefaultsList
-			]);
+		/**
+		 * After an image is selected in the media modal,
+		 * switch to the cropper state.
+		 */
+		onSelect: function() {
+			this.frame.setState( 'cropper' );
 		},
 
 		/**
-		 * Returns a new instance of api.HeaderTool.ImageModel based on the currently
-		 * saved header image (if any).
+		 * After the image has been cropped, apply the cropped image data to the setting.
 		 *
-		 * @since 4.2.0
-		 *
-		 * @returns {Object} Options
+		 * @param {object} croppedImage Cropped attachment data.
 		 */
-		getInitialHeaderImage: function() {
-			if ( ! api.get().header_image || ! api.get().header_image_data || _.contains( [ 'remove-header', 'random-default-image', 'random-uploaded-image' ], api.get().header_image ) ) {
-				return new api.HeaderTool.ImageModel();
-			}
-
-			// Get the matching uploaded image object.
-			var currentHeaderObject = _.find( _wpCustomizeHeader.uploads, function( imageObj ) {
-				return ( imageObj.attachment_id === api.get().header_image_data.attachment_id );
-			} );
-			// Fall back to raw current header image.
-			if ( ! currentHeaderObject ) {
-				currentHeaderObject = {
-					url: api.get().header_image,
-					thumbnail_url: api.get().header_image,
-					attachment_id: api.get().header_image_data.attachment_id
-				};
-			}
-
-			return new api.HeaderTool.ImageModel({
-				header: currentHeaderObject,
-				choice: currentHeaderObject.url.split( '/' ).pop()
-			});
+		onCropped: function( croppedImage ) {
+			this.setImageFromPost( croppedImage );
 		},
 
 		/**
 		 * Returns a set of options, computed from the attached image data and
-		 * theme-specific data, to be fed to the imgAreaSelect plugin in
+		 * control-specific data, to be fed to the imgAreaSelect plugin in
 		 * wp.media.view.Cropper.
 		 *
 		 * @param {wp.media.model.Attachment} attachment
@@ -1914,29 +1918,20 @@
 		 * @param {wp.media.controller.Cropper} controller
 		 * @returns {Object} Options
 		 */
-		calculateImageSelectOptions: function(attachment, controller) {
-			var xInit = parseInt(_wpCustomizeHeader.data.width, 10),
-				yInit = parseInt(_wpCustomizeHeader.data.height, 10),
-				flexWidth = !! parseInt(_wpCustomizeHeader.data['flex-width'], 10),
-				flexHeight = !! parseInt(_wpCustomizeHeader.data['flex-height'], 10),
-				ratio, xImg, yImg, realHeight, realWidth,
-				imgSelectOptions;
+		calculateImageSelectOptions: function( attachment, controller ) {
+			var control = controller.get( 'control' ),
+			    xInit = parseInt( control.params.width, 10 ),
+			    yInit = parseInt( control.params.height, 10 ),
+			    flexWidth = !! parseInt( control.params.flex_width, 10 ),
+			    flexHeight = !! parseInt( control.params.flex_height, 10 ),
+			    ratio, xImg, yImg, realHeight, realWidth,
+			    imgSelectOptions;
 
-			realWidth = attachment.get('width');
-			realHeight = attachment.get('height');
+			realWidth = attachment.get( 'width' );
+			realHeight = attachment.get( 'height' );
 
-			this.headerImage = new api.HeaderTool.ImageModel();
-			this.headerImage.set({
-				themeWidth: xInit,
-				themeHeight: yInit,
-				themeFlexWidth: flexWidth,
-				themeFlexHeight: flexHeight,
-				imageWidth: realWidth,
-				imageHeight: realHeight
-			});
+			controller.set( 'canSkipCrop', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) );
 
-			controller.set( 'canSkipCrop', ! this.headerImage.shouldBeCropped() );
-
 			ratio = xInit / yInit;
 			xImg = realWidth;
 			yImg = realHeight;
@@ -1962,13 +1957,13 @@
 				y2: yInit
 			};
 
-			if (flexHeight === false && flexWidth === false) {
+			if ( flexHeight === false && flexWidth === false ) {
 				imgSelectOptions.aspectRatio = xInit + ':' + yInit;
 			}
-			if (flexHeight === false ) {
+			if ( flexHeight === false ) {
 				imgSelectOptions.maxHeight = yInit;
 			}
-			if (flexWidth === false ) {
+			if ( flexWidth === false ) {
 				imgSelectOptions.maxWidth = xInit;
 			}
 
@@ -1976,127 +1971,72 @@
 		},
 
 		/**
-		 * Sets up and opens the Media Manager in order to select an image.
-		 * Depending on both the size of the image and the properties of the
-		 * current theme, a cropping step after selection may be required or
-		 * skippable.
-		 *
-		 * @param {event} event
+		 * Return whether the image must be cropped, based on required dimensions.
 		 */
-		openMedia: function(event) {
-			var l10n = _wpMediaViewsL10n;
+		mustBeCropped: function( flexW, flexH, dstW, dstH, imgW, imgH ) {
+			if ( flexW === true && flexH === true ) {
+				return false;
+			}
 
-			event.preventDefault();
+			if ( flexW === true && dstH === imgH ) {
+				return false;
+			}
 
-			this.frame = wp.media({
-				button: {
-					text: l10n.selectAndCrop,
-					close: false
-				},
-				states: [
-					new wp.media.controller.Library({
-						title:     l10n.chooseImage,
-						library:   wp.media.query({ type: 'image' }),
-						multiple:  false,
-						date:      false,
-						priority:  20,
-						suggestedWidth: _wpCustomizeHeader.data.width,
-						suggestedHeight: _wpCustomizeHeader.data.height
-					}),
-					new wp.media.controller.Cropper({
-						imgSelectOptions: this.calculateImageSelectOptions
-					})
-				]
-			});
+			if ( flexH === true && dstW === imgW ) {
+				return false;
+			}
 
-			this.frame.on('select', this.onSelect, this);
-			this.frame.on('cropped', this.onCropped, this);
-			this.frame.on('skippedcrop', this.onSkippedCrop, this);
+			if ( dstW === imgW && dstH === imgH ) {
+				return false;
+			}
 
-			this.frame.open();
-		},
+			if ( imgW <= dstW ) {
+				return false;
+			}
 
-		/**
-		 * After an image is selected in the media modal,
-		 * switch to the cropper state.
-		 */
-		onSelect: function() {
-			this.frame.setState('cropper');
+			return true;
 		},
 
 		/**
-		 * After the image has been cropped, apply the cropped image data to the setting.
-		 *
-		 * @param {object} croppedImage Cropped attachment data.
-		 */
-		onCropped: function(croppedImage) {
-			var url = croppedImage.post_content,
-				attachmentId = croppedImage.attachment_id,
-				w = croppedImage.width,
-				h = croppedImage.height;
-			this.setImageFromURL(url, attachmentId, w, h);
-		},
-
-		/**
 		 * If cropping was skipped, apply the image data directly to the setting.
 		 *
 		 * @param {object} selection
 		 */
-		onSkippedCrop: function(selection) {
-			var url = selection.get('url'),
-				w = selection.get('width'),
-				h = selection.get('height');
-			this.setImageFromURL(url, selection.id, w, h);
+		onSkippedCrop: function( selection ) {
+			this.setImageFromPost( selection );
 		},
 
 		/**
-		 * Creates a new wp.customize.HeaderTool.ImageModel from provided
-		 * header image data and inserts it into the user-uploaded headers
-		 * collection.
+		 * Creates a new attachment model from provided header image data 
+		 * and updates the setting, re-rendering the control UI.
 		 *
-		 * @param {String} url
-		 * @param {Number} attachmentId
-		 * @param {Number} width
-		 * @param {Number} height
+		 * @param {object} post
 		 */
-		setImageFromURL: function(url, attachmentId, width, height) {
-			var choice, data = {};
+		setImageFromPost: function( post ) {
+			var attachment = {
+				id: post.attachment_id,
+				type: 'image',
+				sizes: {
+					full: {
+						url: post.guid
+					}
+				}
+			};
+			this.params.attachment = attachment;
 
-			data.url = url;
-			data.thumbnail_url = url;
-			data.timestamp = _.now();
+			// Set the Customizer setting; the callback takes care of rendering.
+			this.setting( attachment.id );
+		},
 
-			if (attachmentId) {
-				data.attachment_id = attachmentId;
-			}
+	});
 
-			if (width) {
-				data.width = width;
-			}
+	/**
+	 * @class
+	 * @augments wp.customize.Control
+	 * @augments wp.customize.Class
+	 */
+	api.HeaderControl = api.CroppedImageControl.extend({
 
-			if (height) {
-				data.height = height;
-			}
-
-			choice = new api.HeaderTool.ImageModel({
-				header: data,
-				choice: url.split('/').pop()
-			});
-			api.HeaderTool.UploadsList.add(choice);
-			api.HeaderTool.currentHeader.set(choice.toJSON());
-			choice.save();
-			choice.importImage();
-		},
-
-		/**
-		 * Triggers the necessary events to deselect an image which was set as
-		 * the currently selected one.
-		 */
-		removeImage: function() {
-			api.HeaderTool.currentHeader.trigger('hide');
-			api.HeaderTool.CombinedList.trigger('control:removeImage');
-		}
-
 	});
 
 	/**
@@ -2695,13 +2635,14 @@
 	});
 
 	api.controlConstructor = {
-		color:      api.ColorControl,
-		media:      api.MediaControl,
-		upload:     api.UploadControl,
-		image:      api.ImageControl,
-		header:     api.HeaderControl,
-		background: api.BackgroundControl,
-		theme:      api.ThemeControl
+		color:         api.ColorControl,
+		media:         api.MediaControl,
+		upload:        api.UploadControl,
+		image:         api.ImageControl,
+		cropped_image: api.CroppedImageControl,
+		header:        api.HeaderControl,
+		background:    api.BackgroundControl,
+		theme:         api.ThemeControl
 	};
 	api.panelConstructor = {};
 	api.sectionConstructor = {
Index: src/wp-includes/class-wp-customize-ajax-actions.php
===================================================================
--- src/wp-includes/class-wp-customize-ajax-actions.php	(revision 0)
+++ src/wp-includes/class-wp-customize-ajax-actions.php	(working copy)
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Ajax Actions for the Customizer.
+ *
+ * @package WordPress
+ * @subpackage Customize
+ */
+
+/**
+ * The custom header image class.
+ *
+ * @since 2.1.0
+ * @package WordPress
+ * @subpackage Administration
+ */
+class WP_Customize_Ajax_Actions {
+	public function __construct() {
+		add_action( 'wp_ajax_customize-image-crop', array( $this, 'ajax_image_crop' ) );
+	}
+
+	/**
+	 * Gets attachment uploaded by Media Manager, crops it, then saves it as a
+	 * new object. Returns JSON-encoded object details.
+	 */
+	public function ajax_image_crop() {
+		check_ajax_referer( 'image_editor-' . $_POST['id'], 'nonce' );
+		if ( ! current_user_can( 'customize' ) ) {
+			wp_send_json_error();
+		}
+		$crop_details = $_POST['cropDetails'];
+		$attachment_id = absint( $_POST['id'] );
+		$cropped = wp_crop_image(
+			$attachment_id,
+			(int) $crop_details['x1'],
+			(int) $crop_details['y1'],
+			(int) $crop_details['width'],
+			(int) $crop_details['height'],
+			(int) $crop_details['dst_width'],
+			(int) $crop_details['dst_height']
+		);
+		if ( ! $cropped || is_wp_error( $cropped ) ) {
+			wp_send_json_error( array( 'message' => __( 'Image could not be processed. Please go back and try again.' ) ) );
+		}
+		/** This filter is documented in wp-admin/custom-header.php */
+		$cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication
+		$object = $this->create_attachment_object( $cropped, $attachment_id );
+		unset( $object['ID'] );
+		$new_attachment_id = $this->insert_attachment( $object, $cropped );
+//		$object['attachment_id'] = $new_attachment_id;
+//		$object['width']         = $dimensions['dst_width'];
+//		$object['height']        = $dimensions['dst_height'];
+		wp_send_json_success( wp_prepare_attachment_for_js( $new_attachment_id ) ); // was object, no prepare attachment
+	}
+
+	/**
+	 * Create an attachment 'object'.
+	 *
+	 * @param string $cropped              Cropped image URL.
+	 * @param int    $parent_attachment_id Attachment ID of parent image.
+	 *
+	 * @return array Attachment object.
+	 */
+	final public function create_attachment_object( $cropped, $parent_attachment_id ) {
+		$parent = get_post( $parent_attachment_id );
+		$parent_url = $parent->guid;
+		$url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
+		$size = @getimagesize( $cropped );
+		$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
+		$object = array(
+			'ID' => $parent_attachment_id,
+			'post_title' => basename($cropped),
+			'post_content' => $url,
+			'post_mime_type' => $image_type,
+			'guid' => $url,
+			'context' => 'customize-cropped'
+		);
+		return $object;
+	}
+
+	/**
+	 * Insert an attachment and its metadata.
+	 *
+	 * @param array  $object  Attachment object.
+	 * @param string $cropped Cropped image URL.
+	 *
+	 * @return int Attachment ID.
+	 */
+	final public function insert_attachment( $object, $cropped ) {
+		$attachment_id = wp_insert_attachment( $object, $cropped );
+		$metadata = wp_generate_attachment_metadata( $attachment_id, $cropped );
+		wp_update_attachment_metadata( $attachment_id, $metadata );
+		return $attachment_id;
+	}
+}
Index: src/wp-includes/class-wp-customize-control.php
===================================================================
--- src/wp-includes/class-wp-customize-control.php	(revision 32993)
+++ src/wp-includes/class-wp-customize-control.php	(working copy)
@@ -1001,32 +1001,30 @@
 }
 
 /**
- * Customize Header Image Control class.
+ * Customize Cropped Image Control class.
  *
- * @since 3.4.0
+ * @since 4.3.0
  *
  * @see WP_Customize_Image_Control
  */
-class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
-	public $type = 'header';
-	public $uploaded_headers;
-	public $default_headers;
+class WP_Customize_Cropped_Image_Control extends WP_Customize_Image_Control {
+	public $type = 'cropped_image';
 
+	protected $width  = 150;
+	protected $height = 150;
+	protected $flex_width  = false;
+	protected $flex_height = false;
+
 	/**
+	 * Constructor.
+	 *
+	 * @since 4.3.0
+	 * @uses WP_Customize_Image_Control::__construct()
+	 *
 	 * @param WP_Customize_Manager $manager
 	 */
-	public function __construct( $manager ) {
-		parent::__construct( $manager, 'header_image', array(
-			'label'    => __( 'Header Image' ),
-			'settings' => array(
-				'default' => 'header_image',
-				'data'    => 'header_image_data',
-			),
-			'section'  => 'header_image',
-			'removed'  => 'remove-header',
-			'get_url'  => 'get_header_image',
-		) );
-
+	public function __construct( $manager, $id, $args ) {
+		parent::__construct( $manager, $id, $args );
 	}
 
 	/**
@@ -1033,28 +1031,62 @@
 	 * @access public
 	 */
 	public function enqueue() {
-		wp_enqueue_media();
 		wp_enqueue_script( 'customize-views' );
 
-		$this->prepare_control();
+		parent::enqueue();
+	}
 
-		wp_localize_script( 'customize-views', '_wpCustomizeHeader', array(
-			'data' => array(
-				'width' => absint( get_theme_support( 'custom-header', 'width' ) ),
-				'height' => absint( get_theme_support( 'custom-header', 'height' ) ),
-				'flex-width' => absint( get_theme_support( 'custom-header', 'flex-width' ) ),
-				'flex-height' => absint( get_theme_support( 'custom-header', 'flex-height' ) ),
-				'currentImgSrc' => $this->get_current_image_src(),
+	/**
+	 * Refresh the parameters passed to the JavaScript via JSON.
+	 *
+	 * @since 4.3.0
+	 * @access public
+	 * @uses WP_Customize_Image_Control::to_json()
+	 *
+	 * @see WP_Customize_Control::to_json()
+	 */
+	public function to_json() {
+		parent::to_json();
+
+		$this->json['width']       = absint( $this->width );
+		$this->json['height']      = absint( $this->height );
+		$this->json['flex_width']  = absint( $this->flex_width );
+		$this->json['flex_height'] = absint( $this->flex_height );
+	}
+
+}
+
+/**
+ * Customize Header Image Control class.
+ *
+ * @since 3.4.0
+ * @since 4.3.0 extends WP_Customize_Cropped_Image_Control
+ *
+ * @see WP_Customize_Cropped_Image_Control
+ */
+class WP_Customize_Header_Image_Control extends WP_Customize_Cropped_Image_Control {
+	public $type = 'header';
+
+	/**
+	 * @param WP_Customize_Manager $manager
+	 */
+	public function __construct( $manager ) {
+		parent::__construct( $manager, 'header_image', array(
+			'label'         => __( 'Header Image' ),
+			'current_title' => __( 'Current header' ),
+			'settings' => array(
+				'default' => 'header_image',
+				'data'    => 'header_image_data',
 			),
-			'nonces' => array(
-				'add' => wp_create_nonce( 'header-add' ),
-				'remove' => wp_create_nonce( 'header-remove' ),
-			),
-			'uploads' => $this->uploaded_headers,
-			'defaults' => $this->default_headers
+			'section'       => 'header_image',
+			'removed'       => 'remove-header',
 		) );
 
-		parent::enqueue();
+		$this->width  = get_theme_support( 'custom-header', 'width' );
+		$this->height = get_theme_support( 'custom-header', 'height' );
+		$this->flex_width  = get_theme_support( 'custom-header', 'flex-width' );
+		$this->flex_height = get_theme_support( 'custom-header', 'flex-height' );
+		$this->localized_name = '_wpCustomizeHeader';
 	}
 
 	/**
@@ -1063,6 +1095,7 @@
 	 */
 	public function prepare_control() {
 		global $custom_image_header;
+
 		if ( empty( $custom_image_header ) ) {
 			return;
 		}
@@ -1069,8 +1102,8 @@
 
 		// Process default headers and uploaded headers.
 		$custom_image_header->process_default_headers();
-		$this->default_headers = $custom_image_header->get_default_header_images();
-		$this->uploaded_headers = $custom_image_header->get_uploaded_header_images();
+		$this->default_images  = $custom_image_header->get_default_header_images();
+		$this->uploaded_images = $custom_image_header->get_uploaded_header_images();
 	}
 
 	/**
Index: src/wp-includes/class-wp-customize-manager.php
===================================================================
--- src/wp-includes/class-wp-customize-manager.php	(revision 32993)
+++ src/wp-includes/class-wp-customize-manager.php	(working copy)
@@ -112,9 +112,11 @@
 		require_once( ABSPATH . WPINC . '/class-wp-customize-control.php' );
 		require_once( ABSPATH . WPINC . '/class-wp-customize-widgets.php' );
 		require_once( ABSPATH . WPINC . '/class-wp-customize-nav-menus.php' );
+		require_once( ABSPATH . WPINC . '/class-wp-customize-ajax-actions.php' );
 
 		$this->widgets = new WP_Customize_Widgets( $this );
 		$this->nav_menus = new WP_Customize_Nav_Menus( $this );
+		$this->ajax_actions = new WP_Customize_Ajax_Actions();
 
 		add_filter( 'wp_die_handler', array( $this, 'wp_die_handler' ) );
 
@@ -1278,6 +1280,7 @@
 		$this->register_control_type( 'WP_Customize_Upload_Control' );
 		$this->register_control_type( 'WP_Customize_Image_Control' );
 		$this->register_control_type( 'WP_Customize_Background_Image_Control' );
+		$this->register_control_type( 'WP_Customize_Cropped_Image_Control' );
 		$this->register_control_type( 'WP_Customize_Theme_Control' );
 
 		/* Themes */
@@ -1324,10 +1327,10 @@
 			) ) );
 		}
 
-		/* Site Title & Tagline */
+		/* Site Identity */
 
 		$this->add_section( 'title_tagline', array(
-			'title'    => __( 'Site Title & Tagline' ),
+			'title'    => __( 'Site Identity' ),
 			'priority' => 20,
 		) );
 
@@ -1353,6 +1356,18 @@
 			'section'    => 'title_tagline',
 		) );
 
+		$this->add_setting( 'site_icon', array(
+			'type'       => 'option',
+			'capability' => 'manage_options',
+		) );
+
+		$this->add_control( new WP_Customize_Cropped_Image_Control( $this, 'site_icon', array(
+			'label'       => __( 'Site Icon' ),
+			'description' => __( 'The site icon is used as the browser and device icon for your site. Your theme may also display the site icon. Icons must be square, and at least 512px wide and tall.' ),
+			'section'     => 'title_tagline',
+			'priority'    => 60,
+		) ) );
+
 		/* Colors */
 
 		$this->add_section( 'colors', array(
@@ -1375,6 +1390,7 @@
 			'label'    => __( 'Display Header Text' ),
 			'section'  => 'title_tagline',
 			'type'     => 'checkbox',
+			'priority' => 40,
 		) );
 
 		$this->add_control( new WP_Customize_Color_Control( $this, 'header_textcolor', array(
Index: src/wp-includes/js/customize-views.js
===================================================================
--- src/wp-includes/js/customize-views.js	(revision 32993)
+++ src/wp-includes/js/customize-views.js	(working copy)
@@ -3,6 +3,21 @@
 	if ( ! wp || ! wp.customize ) { return; }
 	var api = wp.customize;
 
+	/**
+	 * Use a custom ajax action for cropped image controls
+	 */
+	wp.media.controller.customizeImageCropper = wp.media.controller.Cropper.extend( {
+		doCrop: function( attachment ) {
+			var cropDetails = attachment.get( 'cropDetails' );
+			cropDetails.dst_height = this.collection.models[0].attributes.suggestedHeight;
+			cropDetails.dst_width = this.collection.models[0].attributes.suggestedWidth;
+			return wp.ajax.post( 'customize-image-crop', {
+				nonce: attachment.get( 'nonces' ).edit,
+				id: attachment.get( 'id' ),
+				cropDetails: cropDetails
+			} );
+		}
+	} );
 
 	/**
 	 * wp.customize.HeaderTool.CurrentView
@@ -16,7 +31,7 @@
 	 * @augments wp.Backbone.View
 	 */
 	api.HeaderTool.CurrentView = wp.Backbone.View.extend({
-		template: wp.template('header-current'),
+		template: wp.template('cropped-current'),
 
 		initialize: function() {
 			this.listenTo(this.model, 'change', this.render);
@@ -86,7 +101,7 @@
 	 * Represents a choosable header image, be it user-uploaded,
 	 * theme-suggested or a special Randomize choice.
 	 *
-	 * Takes a wp.customize.HeaderTool.ImageModel.
+	 * Takes a wp.customize.CropTool.ImageModel.
 	 *
 	 * Manually changes model wp.customize.HeaderTool.currentHeader via the
 	 * `select` method.
