Index: /CKEditor/trunk/_source/core/dom/element.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/element.js	(revision 3548)
+++ /CKEditor/trunk/_source/core/dom/element.js	(revision 3549)
@@ -644,8 +644,15 @@
 		},
 
-		getLast : function()
+		/**
+		 * @param ignoreEmpty Skip empty text nodes.
+		 */
+		getLast : function( ignoreEmpty )
 		{
 			var $ = this.$.lastChild;
-			return $ ? new CKEDITOR.dom.node( $ ) : null;
+			if ( ignoreEmpty && $ && ( $.nodeType == CKEDITOR.NODE_TEXT )
+					&& !CKEDITOR.tools.trim( $.nodeValue ) )
+				return new CKEDITOR.dom.node( $ ).getPrevious( true );
+			else
+				return $ ? new CKEDITOR.dom.node( $ ) : null;
 		},
 
Index: /CKEditor/trunk/_source/core/dom/node.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/node.js	(revision 3548)
+++ /CKEditor/trunk/_source/core/dom/node.js	(revision 3549)
@@ -260,14 +260,4 @@
 		},
 
-		/**
-		 * Gets the node following this node (next sibling).
-		 * @returns {CKEDITOR.dom.node} The next node.
-		 */
-		getNext : function()
-		{
-			var next = this.$.nextSibling;
-			return next ? new CKEDITOR.dom.node( next ) : null;
-		},
-
 		getNextSourceNode : function( startFromSibling, nodeType, guard )
 		{
@@ -361,7 +351,11 @@
 		},
 
-		getPrevious : function()
+		getPrevious : function( ignoreSpaces )
 		{
 			var previous = this.$.previousSibling;
+			while ( ignoreSpaces && previous && ( previous.nodeType == CKEDITOR.NODE_TEXT )
+					&& !CKEDITOR.tools.trim( previous.nodeValue ) )
+				previous = previous.previousSibling;
+
 			return previous ? new CKEDITOR.dom.node( previous ) : null;
 		},
@@ -369,4 +363,5 @@
 		/**
 		 * Gets the node that follows this element in its parent's child list.
+		 * @param {Boolean} ignoreSpaces Whether should ignore empty text nodes.
 		 * @returns {CKEDITOR.dom.node} The next node or null if not
 		 *		available.
@@ -376,8 +371,12 @@
 		 * alert( first.getName() );  // "i"
 		 */
-		getNext : function()
-		{
-			var $ = this.$.nextSibling;
-			return $ ? new CKEDITOR.dom.node( $ ) : null;
+		getNext : function( ignoreSpaces )
+		{
+			var next = this.$.nextSibling;
+			while ( ignoreSpaces && next && ( next.nodeType == CKEDITOR.NODE_TEXT )
+				  && !CKEDITOR.tools.trim( next.nodeValue ) )
+				next = next.nextSibling;
+			
+			return next ? new CKEDITOR.dom.node( next ) : null;
 		},
 
Index: /CKEditor/trunk/_source/core/dom/range.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/range.js	(revision 3548)
+++ /CKEditor/trunk/_source/core/dom/range.js	(revision 3549)
@@ -1,3 +1,3 @@
-﻿/*
+/*
 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
@@ -32,4 +32,6 @@
 	var execContentsAction = function( range, action, docFrag )
 	{
+		range.optimizeBookmark();
+		
 		var startNode	= range.startContainer;
 		var endNode		= range.endContainer;
@@ -608,17 +610,28 @@
 		},
 
-		getCommonAncestor : function( includeSelf )
-		{
-			var start = this.startContainer;
-			var end = this.endContainer;
+		/**
+		 * Find the node which fully contains the range.
+		 * @param includeSelf
+		 * @param {Boolean} ignoreTextNode Whether ignore CKEDITOR.NODE_TEXT type.
+		 */
+		getCommonAncestor : function( includeSelf , ignoreTextNode )
+		{
+			var start = this.startContainer,
+				end = this.endContainer,
+				ancestor;
 
 			if ( start.equals( end ) )
 			{
-				if ( includeSelf && start.type == CKEDITOR.NODE_ELEMENT && this.startOffset == this.endOffset - 1 )
-					return start.getChild( this.startOffset );
-				return start;
-			}
-
-			return start.getCommonAncestor( end );
+				if ( includeSelf
+						&& start.type == CKEDITOR.NODE_ELEMENT
+						&& this.startOffset == this.endOffset - 1 )
+					ancestor = start.getChild( this.startOffset );
+				else
+					ancestor = start;
+			}
+			else
+				ancestor = start.getCommonAncestor( end );
+
+			return ignoreTextNode && !ancestor.is ? ancestor.getParent() : ancestor;
 		},
 
@@ -652,4 +665,20 @@
 					this.setEndAfter( container );
 			}
+		},
+
+		/**
+		 * Move the range out of bookmark nodes if they're been the container.
+		 */
+		optimizeBookmark: function()
+		{
+			var startNode = this.startContainer,
+				endNode = this.endContainer;
+
+			if ( startNode.is && startNode.is( 'span' )
+				&& startNode.hasAttribute( '_fck_bookmark' ) )
+				this.setStartAt( startNode, CKEDITOR.POSITION_BEFORE_START );
+			if ( endNode && endNode.is && endNode.is( 'span' )
+				&& endNode.hasAttribute( '_fck_bookmark' ) )
+				this.setEndAt( endNode,  CKEDITOR.POSITION_AFTER_END );
 		},
 
@@ -1137,4 +1166,5 @@
 		insertNode : function( node )
 		{
+			this.optimizeBookmark();
 			this.trim( false, true );
 
@@ -1327,5 +1357,4 @@
 
 			var elementPath = null;
-
 			// Do nothing if the boundaries are in different block limits.
 			if ( !startBlockLimit.equals( endBlockLimit ) )
Index: /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js	(revision 3548)
+++ /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js	(revision 3549)
@@ -11,4 +11,9 @@
 (function()
 {
+	/**
+	 * List of elements in which has no way to move editing focus outside.
+	 */
+	var nonExitableElementNames = { table:1,pre:1 };
+
 	function onInsertHtml( evt )
 	{
@@ -72,28 +77,15 @@
 				clone = !i && element || element.clone( true );
 
-				var toSplit;
-
-				// If the new node is a block element, split the current block (if any).
+				// If we're inserting a block at dtd-violated positoin, split
+				// the parent blocks until we reach blockLimit.
+				var parent, dtd;
 				if ( this.config.enterMode != CKEDITOR.ENTER_BR && isBlock )
-				{
-					var startPath = new CKEDITOR.dom.elementPath( range.startContainer ),
-						j = 0,
-						parent;
-
-					while( ( parent = startPath.elements[ j++ ] ) && parent != startPath.blockLimit )
-					{
-						var parentName = parent.getName(),
-							parentDtd = CKEDITOR.dtd[ parentName ];
-
-						if ( parentDtd && !parentDtd[ elementName ] )
-							toSplit = parent;
-					}
-				}
+					while( ( parent = range.getCommonAncestor( false, true ) )
+							&& ( dtd = CKEDITOR.dtd[ parent.getName() ] )
+							&& !( dtd && dtd [ elementName ] ) )
+						range.splitBlock();
 
 				// Insert the new node.
 				range.insertNode( clone );
-
-				if ( toSplit )
-					clone.breakParent( toSplit );
 
 				// Save the last element reference so we can make the
@@ -113,4 +105,53 @@
 			if ( selIsLocked )
 				this.getSelection().lock();
+		}
+	}
+	
+	/**
+	 *  Auto-fixing block-less content by wrapping paragraph, prevent 
+	 *  non-exitable-block by padding extra br.
+	 */
+	function onSelectionChangeFixBody( evt )
+	{
+		var editor = evt.editor,
+			path = evt.data.path,
+			blockLimit = path.blockLimit,
+			body = editor.document.getBody(),
+			enterMode = editor.config.enterMode;
+
+		// When enterMode set to block, we'll establing new paragraph if the
+		// current range is block-less within body.
+		if ( enterMode != CKEDITOR.ENTER_BR
+			 && blockLimit.getName() == 'body'
+			 && !path.block )
+		{
+			var selection = evt.data.selection,
+				range = evt.data.selection.getRanges()[0],
+				bms = selection.createBookmarks(),
+				fixedBlock = range.fixBlock( true,
+					editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p'  );
+
+			// For IE, we'll be removing any bogus br ( introduce by fixing body )
+			// right now to prevent it introducing visual line break.
+			if ( CKEDITOR.env.ie )
+			{
+				var brNodeList = fixedBlock.getElementsByTag( 'br' ), brNode;
+				for ( var i = 0 ; i < brNodeList.count() ; i++ )
+					if( ( brNode = brNodeList.getItem( i ) ) && brNode.hasAttribute( '_fck_bookmark' ) )
+						brNode.remove();
+			}
+
+			selection.selectBookmarks( bms );
+		}
+
+		// Inserting the padding-br before body if it's preceded by an
+		// unexitable block.
+		var lastNode = body.getLast( true );
+		if ( lastNode.getName && ( lastNode.getName() in nonExitableElementNames ) )
+		{
+			var paddingBlock = editor.document.createElement(
+					( CKEDITOR.env.ie && enterMode != CKEDITOR.ENTER_BR ) ?
+						'<br _cke_bogus="true" />' : 'br' );
+			body.append( paddingBlock );
 		}
 	}
@@ -450,4 +491,6 @@
 					editor.on( 'insertHtml', onInsertHtml, null, null, 20 );
 					editor.on( 'insertElement', onInsertElement, null, null, 20 );
+					// Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189)
+					editor.on( 'selectionChange', onSelectionChangeFixBody, null, null, 1 );
 				});
 		}
