Index: /CKEditor/branches/features/v4-paste/_source/core/dom/element.js
===================================================================
--- /CKEditor/branches/features/v4-paste/_source/core/dom/element.js	(revision 7151)
+++ /CKEditor/branches/features/v4-paste/_source/core/dom/element.js	(revision 7152)
@@ -379,4 +379,19 @@
 			return ( this.$.innerHTML = html );
 		},
+		
+		replaceWithHtml : function( html )
+		{
+			var temp = this.getDocument().createElement( 'body' );
+			temp.setHtml( html );
+
+			var child = temp.getLast();
+			while ( child )
+			{
+				child.clone( 1, 1 ).insertAfter( this );
+				child = child.getPrevious();
+			}
+
+			this.remove();
+		},
 
 		/**
Index: /CKEditor/branches/features/v4-paste/_source/core/htmlparser/element.js
===================================================================
--- /CKEditor/branches/features/v4-paste/_source/core/htmlparser/element.js	(revision 7151)
+++ /CKEditor/branches/features/v4-paste/_source/core/htmlparser/element.js	(revision 7152)
@@ -57,5 +57,6 @@
 	{
 		isBlockLike : isBlockLike,
-		hasInlineStarted : isEmpty || !isBlockLike
+		hasInlineStarted : isEmpty || !isBlockLike,
+		pendingBlocks : []
 	};
 };
Index: /CKEditor/branches/features/v4-paste/_source/core/htmlparser/fragment.js
===================================================================
--- /CKEditor/branches/features/v4-paste/_source/core/htmlparser/fragment.js	(revision 7151)
+++ /CKEditor/branches/features/v4-paste/_source/core/htmlparser/fragment.js	(revision 7152)
@@ -1,3 +1,3 @@
-﻿/*
+﻿?/*
 Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
@@ -66,4 +66,5 @@
 			fragment = contextNode || new CKEDITOR.htmlParser.fragment(),
 			pendingInline = [],
+			pendingBlocks = [],
 			pendingBRs = [],
 			currentNode = fragment,
@@ -129,5 +130,20 @@
 			// Ignore any element that has already been added.
 			if ( element.previous !== undefined )
+			{
+				currentNode = target;
 				return;
+			}
+
+			if ( element._.removeIfEmpty )
+			{
+				currentNode = element.returnPoint;
+				delete element._.removeIfEmpty;
+				// Ignore pending block that has no content.
+				if ( !element.children.length )
+				{
+					currentNode = target;
+					return;
+				}
+			}
 
 			target = target || currentNode || fragment;
@@ -186,4 +202,22 @@
 			else
 				currentNode = moveCurrent ? target : savedCurrent;
+
+			// Checking pending blocks.
+			var pendingBlocks = element._.pendingBlocks; 
+
+			var block;
+			while( block = pendingBlocks.shift() )
+			{
+				// Get a clone for the pending block.
+				block = block.clone();
+				// Mark the block as remove if empty
+				block._.removeIfEmpty = 1;
+
+				// Add it to the current node and make it the current.
+				block.parent = currentNode;
+				currentNode = block;
+			}
+
+			delete element._.pendingBlocks;
 		}
 
@@ -269,4 +303,13 @@
 							pendingInline.unshift( currentNode );
 
+						// Unintentionally closed blocks are to be continued 
+						// after adding this element.
+						if ( currentName in CKEDITOR.dtd.$block
+								&& !( currentName in CKEDITOR.dtd.$empty ) )
+						{
+							currentNode._.removeIfEmpty = 1;
+							element._.pendingBlocks.push( currentNode );
+						}
+
 						// The most common case where we just need to close the
 						// current one and append the new one to the parent.
@@ -349,10 +392,5 @@
 					sendPendingBRs();
 
-				addElement( candidate, candidate.parent );
-
-				// The parent should start receiving new nodes now, except if
-				// addElement changed the currentNode.
-				if ( candidate == currentNode )
-					currentNode = currentNode.parent;
+				addElement( candidate, candidate.parent, 1 );
 
 				pendingInline = pendingInline.concat( newPendingInline );
Index: /CKEditor/branches/features/v4-paste/_source/plugins/htmldataprocessor/plugin.js
===================================================================
--- /CKEditor/branches/features/v4-paste/_source/plugins/htmldataprocessor/plugin.js	(revision 7151)
+++ /CKEditor/branches/features/v4-paste/_source/plugins/htmldataprocessor/plugin.js	(revision 7152)
@@ -485,5 +485,5 @@
 	CKEDITOR.htmlDataProcessor.prototype =
 	{
-		toHtml : function( data, fixForBody )
+		toHtml : function( data, fixForBody, nativeParsing )
 		{
 			// The source data is already HTML, but we need to clean
@@ -513,10 +513,13 @@
 			data = protectPreFormatted( data );
 
-			// Call the browser to help us fixing a possibly invalid HTML
-			// structure.
-			var div = new CKEDITOR.dom.element( 'div' );
-			// Add fake character to workaround IE comments bug. (#3801)
-			div.setHtml( 'a' + data );
-			data = div.getHtml().substr( 1 );
+			if ( nativeParsing !== false )
+			{
+				// Call the browser to help us fixing a possibly invalid HTML
+				// structure.
+				var div = new CKEDITOR.dom.element( 'div' );
+				// Add fake character to workaround IE comments bug. (#3801)
+				div.setHtml( 'a' + data );
+				data = div.getHtml().substr( 1 );
+			}
 
 			// Unprotect "some" of the protected elements at this point.
Index: /CKEditor/branches/features/v4-paste/_source/plugins/wysiwygarea/plugin.js
===================================================================
--- /CKEditor/branches/features/v4-paste/_source/plugins/wysiwygarea/plugin.js	(revision 7151)
+++ /CKEditor/branches/features/v4-paste/_source/plugins/wysiwygarea/plugin.js	(revision 7152)
@@ -47,9 +47,23 @@
 	}
 
+	function postFixPaste( range )
+	{
+		var walker = new CKEDITOR.dom.walker( range.clone() );
+
+		// Collect invalid structured and wrongly styled (Webkit only) elements for later fixing.
+		var next, invalids = [], extras = [], type = CKEDITOR.dom.walker.nodeType( CKEDITOR.NODE_ELEMENT );
+		walker.evaluator = type;
+		while( next = walker.next() )
+		{
+			if ( next.is( 'span' ) && next.hasClass( 'Apple-style-span' ) )
+				extras.push( next );
+		}
+
+		for ( var j = 0, extra; extra = extras[ j ], j < extras.length; j++ )
+			extra.remove( 1 );
+	}
+
 	function doInsertHtml( data )
 	{
-		if ( this.dataProcessor )
-			data = this.dataProcessor.toHtml( data );
-
 		if ( !data )
 			return;
@@ -62,71 +76,60 @@
 			return;
 
-		// Opera: force block splitting when pasted content contains block. (#7801)
-		if ( CKEDITOR.env.opera )
-		{
-			var path = new CKEDITOR.dom.elementPath( range.startContainer );
-			if ( path.block )
-			{
-				var nodes = CKEDITOR.htmlParser.fragment.fromHtml( data, false ).children;
-				for ( var i = 0, count = nodes.length; i < count; i++ )
-				{
-					if ( nodes[ i ]._.isBlockLike )
-					{
-						range.splitBlock( this.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
-						range.insertNode( range.document.createText( '' ) );
-						range.select();
-						break;
-					}
-				}
-			}
-		}
-
-		if ( CKEDITOR.env.ie )
-		{
-			var selIsLocked = selection.isLocked;
-
-			if ( selIsLocked )
-				selection.unlock();
-
-			var $sel = selection.getNative();
-
-			// Delete control selections to avoid IE bugs on pasteHTML.
-			if ( $sel.type == 'Control' )
-				$sel.clear();
-			else if ( selection.getType() == CKEDITOR.SELECTION_TEXT )
-			{
-				// Due to IE bugs on handling contenteditable=false blocks
-				// (#6005), we need to make some checks and eventually
-				// delete the selection first.
-
-				range = selection.getRanges()[ 0 ];
-				var endContainer = range && range.endContainer;
-
-				if ( endContainer &&
-						endContainer.type == CKEDITOR.NODE_ELEMENT &&
-						endContainer.getAttribute( 'contenteditable' ) == 'false' &&
-						range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) )
-				{
-					range.setEndAfter( range.endContainer );
-					range.deleteContents();
-				}
-			}
-
-			try
-			{
-				$sel.createRange().pasteHTML( data );
-			}
-			catch (e) {}
-
-			if ( selIsLocked )
-				this.getSelection().lock();
+		var selIsLocked = selection.isLocked;
+		selIsLocked && selection.unlock();
+
+		// Easy way of removing content from current selection.
+		if ( !range.collapsed )
+			this.document.$.execCommand( 'Delete', false, null );
+
+		data += '<span id="cke_caret">\ufeff</span>';
+
+		selection.reset();
+		range = selection.getRanges()[ 0 ];
+		var path = new CKEDITOR.dom.elementPath( range.startContainer );
+		var root = path.lastElement;
+		if ( !path.blockLimit.equals( root ) )
+		{
+			var parent;
+			while( !( parent = root.getParent() ).equals( path.blockLimit ) )
+				root = parent;
+
+			var marker = this.document.createText( '{cke_paste_marker}' );
+			range.insertNode( marker );
+			data = root.getOuterHtml().replace( '{cke_paste_marker}', data );
+			marker.remove();
 		}
 		else
-			this.document.$.execCommand( 'inserthtml', false, data );
+		{
+			root = CKEDITOR.dom.element.createFromHtml( '<span id="cke_paste_marker"></span>');
+			range.insertNode( root );
+		}
+
+		if ( this.dataProcessor )
+			data = this.dataProcessor.toHtml( data, false, false );
+
+		var fixRange = new CKEDITOR.dom.range( this.document );
+		fixRange.setStartBefore( root );
+		fixRange.setEndAfter( root );
+		var bm = fixRange.createBookmark();
+		root.replaceWithHtml( data );
+		fixRange.moveToBookmark( bm );
+
+		// Fixing schema-violated elements and redundant styles that may occur
+		// at start of pasted content.
+		postFixPaste( fixRange );
+
+		// Move selection to the end of pasted content.
+		var marker = this.document.getById( 'cke_caret' );
+		range.moveToPosition( marker, CKEDITOR.POSITION_BEFORE_START );
+		marker.remove();
+		range.select();
+
+		selIsLocked && this.getSelection().lock();
 
 		// Webkit does not scroll to the cursor position after pasting (#5558)
 		if ( CKEDITOR.env.webkit )
 		{
-			selection = this.getSelection();
+			selection.reset();
 			selection.scrollIntoView();
 		}
