Index: /CKEditor/trunk/_source/core/dom/range.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/range.js	(revision 7623)
+++ /CKEditor/trunk/_source/core/dom/range.js	(revision 7624)
@@ -1871,5 +1871,5 @@
 
 			var walker = new CKEDITOR.dom.walker( walkerRange );
-			walker.evaluator = getCheckStartEndBlockEvalFunction( false );
+			walker.evaluator = getCheckStartEndBlockEvalFunction();
 
 			return walker.checkForward();
@@ -1877,7 +1877,45 @@
 
 		/**
-		 * Check if elements at which the range boundaries anchor are read-only,
-		 * with respect to "contenteditable" attribute.
+		 * Traverse with {@link CKEDITOR.dom.walker} to retrieve the previous element before the range start.
+		 * @param {Function} evaluator Function used as the walker's evaluator.
+		 * @param {Function} [guard] Function used as the walker's guard.
+		 * @param {CKEDITOR.dom.element} [boundary] A range ancestor element in which the traversal is limited,
+		 * default to the root editable if not defined.
+		 *
+		 * @return {CKEDITOR.dom.element|null} The returned node from the traversal.
 		 */
+		getPreviousNode : function( evaluator, guard, boundary ) {
+
+			var walkerRange = this.clone();
+			walkerRange.collapse( 1 );
+			walkerRange.setStartAt( boundary || this.document.getBody(), CKEDITOR.POSITION_AFTER_START );
+
+			var walker = new CKEDITOR.dom.walker( walkerRange );
+			walker.evaluator = evaluator;
+			walker.guard = guard;
+			return walker.previous();
+		},
+
+		/**
+		 * Traverse with {@link CKEDITOR.dom.walker} to retrieve the next element before the range start.
+		 * @param {Function} evaluator Function used as the walker's evaluator.
+		 * @param {Function} [guard] Function used as the walker's guard.
+		 * @param {CKEDITOR.dom.element} [boundary] A range ancestor element in which the traversal is limited,
+		 * default to the root editable if not defined.
+		 *
+		 * @return {CKEDITOR.dom.element|null} The returned node from the traversal.
+		 */
+		getNextNode: function( evaluator, guard, boundary )
+		{
+			var walkerRange = this.clone();
+			walkerRange.collapse();
+			walkerRange.setEndAt( boundary || this.document.getBody(), CKEDITOR.POSITION_BEFORE_END );
+
+			var walker = new CKEDITOR.dom.walker( walkerRange );
+			walker.evaluator = evaluator;
+			walker.guard = guard;
+			return walker.next();
+		},
+
 		checkReadOnly : ( function()
 		{
Index: /CKEditor/trunk/_source/core/dom/walker.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/walker.js	(revision 7623)
+++ /CKEditor/trunk/_source/core/dom/walker.js	(revision 7624)
@@ -429,11 +429,23 @@
 		return function( node )
 		{
-			// Nodes that take no spaces in wysiwyg:
-			// 1. White-spaces but not including NBSP;
-			// 2. Empty inline elements, e.g. <b></b> we're checking here
-			// 'offsetHeight' instead of 'offsetWidth' for properly excluding
-			// all sorts of empty paragraph, e.g. <br />.
-			var isInvisible = whitespace( node ) || node.is && !node.$.offsetHeight;
-			return !! ( isReject ^ isInvisible );
+			var invisible;
+
+			if ( whitespace( node ) )
+				invisible = 1;
+			else
+			{
+				// Visibility should be checked on element.
+				if ( node.type == CKEDITOR.NODE_TEXT )
+					node = node.getParent();
+
+				// Nodes that take no spaces in wysiwyg:
+				// 1. White-spaces but not including NBSP;
+				// 2. Empty inline elements, e.g. <b></b> we're checking here
+				// 'offsetHeight' instead of 'offsetWidth' for properly excluding
+				// all sorts of empty paragraph, e.g. <br />.
+				invisible = !node.$.offsetHeight;
+			}
+
+			return !! ( isReject ^ invisible );
 		};
 	};
Index: /CKEditor/trunk/_source/plugins/selection/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 7623)
+++ /CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 7624)
@@ -73,21 +73,30 @@
 	function rangeRequiresFix( range )
 	{
-		function isInlineCt( node )
-		{
-			return node && node.type == CKEDITOR.NODE_ELEMENT
-					&& node.getName() in CKEDITOR.dtd.$removeEmpty;
+		function isTextCt( node, isAtEnd )
+		{
+			if ( !node || node.type == CKEDITOR.NODE_TEXT )
+				return;
+
+			var testRng = range.clone();
+			return testRng[ 'moveToElementEdit' + ( isAtEnd ? 'End' : 'Start' ) ]( node );
 		}
 
-		var start = range.startContainer,
-			offset = range.startOffset;
-
-		if ( start.type == CKEDITOR.NODE_TEXT )
-			return false;
-
-		// 1. Empty inline element. <span>^</span>
-		// 2. Empty block. <p>^</p> (#7222)
-		// 3. Adjoin to inline element. <p><strong>text</strong>^</p>
-		return !CKEDITOR.tools.trim( start.getHtml() ) ? isInlineCt( start ) || start.isBlockBoundary()
-				: isInlineCt( start.getChild( offset - 1 ) ) || isInlineCt( start.getChild( offset ) );
+		var ct = range.startContainer;
+
+		var previous = range.getPreviousNode( isVisible, null, ct ),
+			next = range.getNextNode( isVisible, null, ct );
+
+		// Any adjacent text container may absorb the cursor, e.g.
+		// <p><strong>text</strong>^foo</p>
+		// <p>foo^<strong>text</strong></p>
+		// <div>^<p>foo</p></div>
+		if ( isTextCt( previous ) || isTextCt( next, 1 ) )
+			return true;
+
+		// Empty block/inline element is also affected. <span>^</span>, <p>^</p> (#7222)
+		if ( !( previous || next ) && !( ct.isBlockBoundary() && ct.getBogus() ) )
+			return true;
+
+		return false;
 	}
 
@@ -1760,9 +1769,7 @@
 		}
 	};
-})();
-
-( function()
-{
+
 	var notWhitespaces = CKEDITOR.dom.walker.whitespaces( true ),
+			isVisible = CKEDITOR.dom.walker.invisible( 1 );
 			fillerTextRegex = /\ufeff|\u00a0/,
 			nonCells = { table:1,tbody:1,tr:1 };
