Index: /CKEditor/trunk/_source/core/dom/node.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/node.js	(revision 3462)
+++ /CKEditor/trunk/_source/core/dom/node.js	(revision 3463)
@@ -287,5 +287,7 @@
 			while ( !node && ( parent = ( parent || this ).getParent() ) )
 			{
-				if ( guard && guard( parent ) === false )
+				// The guard check sends the "true" paramenter to indicate that
+				// we are moving "out" of the element.
+				if ( guard && guard( parent, true ) === false )
 					return null;
 
@@ -321,5 +323,7 @@
 			while ( !node && ( parent = ( parent || this ).getParent() ) )
 			{
-				if ( guard && guard( parent ) === false )
+				// The guard check sends the "true" paramenter to indicate that
+				// we are moving "out" of the element.
+				if ( guard && guard( parent, true ) === false )
 					return null;
 
Index: /CKEditor/trunk/_source/core/dom/range.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/range.js	(revision 3462)
+++ /CKEditor/trunk/_source/core/dom/range.js	(revision 3463)
@@ -1406,43 +1406,37 @@
 		},
 
+		// Calls to this function may produce changes to the DOM. The range may
+		// be updated to reflect such changes.
 		checkStartOfBlock : function()
 		{
 			var startContainer = this.startContainer,
-				startOffset = this.startOffset,
-				startNode,
-				startInclusive;
-
-			if ( startOffset )
-			{
-				// If the starting node is a text node, and non-empty before the offset,
-				// then we're surely not at the start of block.
-				if ( startContainer.type == CKEDITOR.NODE_TEXT )
-				{
-					var textBefore = CKEDITOR.tools.ltrim( startContainer.substring( 0, startOffset ) );
-					if ( textBefore.length )
-						return false;
-				}
-				else
-				{
-					startNode = startContainer.getChild( startOffset - 1 );
-					startInclusive = true;
-				}
+				startOffset = this.startOffset;
+
+			// If the starting node is a text node, and non-empty before the offset,
+			// then we're surely not at the start of block.
+			if ( startOffset && startContainer.type == CKEDITOR.NODE_TEXT )
+			{
+				var textBefore = CKEDITOR.tools.ltrim( startContainer.substring( 0, startOffset ) );
+				if ( textBefore.length )
+					return false;
 			}
 			
-			if ( !startNode )
-				startNode = startContainer;
-
-			var path	= new CKEDITOR.dom.elementPath( startNode ),
-				walker	= new CKEDITOR.dom.walker( startNode, ( path.block || path.blockLimit ) );
-
-			if ( ( path.block && startNode.equals( path.block ) ) 
-				|| ( !path.block && startNode.equals( path.blockLimit ) ) )
-			{
-				return true;
-			}
-
-			walker.startInclusive = startInclusive;
+			// Antecipate the trim() call here, so the walker will not make
+			// changes to the DOM, which would not get reflected into this
+			// range otherwise.
+			this.trim();
+
+			// We need to grab the block element holding the start boundary, so
+			// let's use an element path for it.
+			var path = new CKEDITOR.dom.elementPath( this.startContainer );
+			
+			// Creates a range starting at the block start until the range start.
+			var walkerRange = this.clone();
+			walkerRange.collapse( true );
+			walkerRange.setStartAt( path.block || path.blockLimit, CKEDITOR.POSITION_AFTER_START );
+			
+			var walker = new CKEDITOR.dom.walker( walkerRange );
 			walker.evaluator = getCheckStartEndBlockEvalFunction( true );
-			
+
 			return walker.checkBackward();
 		},
@@ -1451,7 +1445,5 @@
 		{
 			var endContainer = this.endContainer,
-				endOffset = this.endOffset,
-				startNode,
-				startInclusive;
+				endOffset = this.endOffset;
 
 			// If the ending node is a text node, and non-empty after the offset,
@@ -1463,25 +1455,22 @@
 					return false;
 			}
-			else
-			{
-				startNode = endContainer.getChild( endOffset );
-				startInclusive = !!startNode;
-			}
-
-			if ( !startNode )
-				startNode = endContainer;
-
-			var path	= new CKEDITOR.dom.elementPath( startNode ),
-				walker	= new CKEDITOR.dom.walker( startNode, ( path.block || path.blockLimit ) );
-
-			if ( ( path.block && startNode.equals( path.block ) ) 
-				|| ( !path.block && startNode.equals( path.blockLimit ) ) )
-			{
-				return true;
-			}
-
-			walker.startInclusive = startInclusive;
+
+			// Antecipate the trim() call here, so the walker will not make
+			// changes to the DOM, which would not get reflected into this
+			// range otherwise.
+			this.trim();
+
+			// We need to grab the block element holding the start boundary, so
+			// let's use an element path for it.
+			var path = new CKEDITOR.dom.elementPath( this.endContainer );
+			
+			// Creates a range starting at the block start until the range start.
+			var walkerRange = this.clone();
+			walkerRange.collapse( false );
+			walkerRange.setEndAt( path.block || path.blockLimit, CKEDITOR.POSITION_BEFORE_END );
+			
+			var walker = new CKEDITOR.dom.walker( walkerRange );
 			walker.evaluator = getCheckStartEndBlockEvalFunction( false );
-			
+
 			return walker.checkForward();
 		},
Index: /CKEditor/trunk/_source/core/dom/walker.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/walker.js	(revision 3462)
+++ /CKEditor/trunk/_source/core/dom/walker.js	(revision 3463)
@@ -9,48 +9,117 @@
 	function iterate( rtl, breakOnFalse )
 	{
+		// Return null if we have reached the end.
 		if ( this._.end )
 			return null;
 
 		var node,
+			range = this.range,
+			guard,
+			userGuard = this.guard,
 			type = this.type,
 			getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );
 
-		var guard = this.guard,
-			endNode = this.endNode;
-
-		if ( endNode )
-		{
-			if ( guard )
-			{
-				var originalGuard;
-				guard = function( node )
-				{
-					if ( node.equals( endNode ) )
-						return false;
-
-					return originalGuard( node );
-				};
-			}
-			else
-				guard = endNode;
-		}
+		// This is the first call. Initialize it.
+		if ( !this._.start )
+		{
+			this._.start = 1;
+			
+			// Trim text nodes and optmize the range boundaries. DOM changes
+			// may happen at this point.
+			range.trim();
+
+			// A collapsed range must return null at first call.
+			if ( range.collapsed )
+			{
+				this.end();
+				return null;
+			}
+		}
+
+		// Create the LTR guard function, if necessary.
+		if ( !rtl && !this._.guardLTR )
+		{
+			// Gets the node that stops the walker when going LTR.
+			var limitLTR = range.endContainer,
+				blockerLTR = limitLTR.getChild( range.endOffset );
+			
+			this._.guardLTR = function( node, movingOut )
+			{
+				return ( ( !movingOut || !limitLTR.equals( node ) )
+					&& ( !blockerLTR || !node.equals( blockerLTR ) ) 
+					&& ( node.type != CKEDITOR.NODE_ELEMENT || node.name != 'body' ) );
+			}
+		}
+		
+		// Create the RTL guard function, if necessary.
+		if ( rtl && !this._.guardRTL )
+		{
+			// Gets the node that stops the walker when going LTR.
+			var limitRTL = range.startContainer,
+				blockerRTL = ( range.startOffset > 0 ) && limitRTL.getChild( range.startOffset - 1 );
+			
+			this._.guardRTL = function( node, movingOut )
+			{
+				return ( ( !movingOut || !limitRTL.equals( node ) )
+					&& ( !blockerRTL || !node.equals( blockerRTL ) ) 
+					&& ( node.type != CKEDITOR.NODE_ELEMENT || node.name != 'body' ) );
+			}
+		}
+		
+		// Define which guard function to use.
+		stopGuard = rtl ? this._.guardRTL : this._.guardLTR;
+
+		// Make the user defined guard function participate in the process,
+		// otherwise simply use the boundary guard.
+		if ( userGuard )
+		{
+			guard = function( node, movingOut )
+			{
+				if ( stopGuard( node, movingOut ) === false )
+					return false;
+
+				return userGuard( node );
+			}
+		}
+		else
+			guard = stopGuard;
 
 		if ( this.current )
 			node = this.current[ getSourceNodeFn ]( false, type, guard );
-		else if ( this.startInclusive )
-		{
-			node = this.startNode;
-			if ( this.guard && this.guard( node ) === false )
-				node = null;
-		}
 		else
-			node = this.startNode[ getSourceNodeFn ]( true, type, guard );
+		{
+			// Get the first node to be returned.
+
+			if ( rtl )
+			{
+				node = range.endContainer;
+				
+				if ( range.endOffset > 0 )
+				{
+					node = node.getChild( range.endOffset - 1 );
+					if ( guard( node ) === false )
+						node = null;
+				}
+				else
+					node = node.getPreviousSourceNode( true, type, guard );
+			}
+			else
+			{
+				node = range.startContainer;
+				node = node.getChild( range.startOffset );
+
+				if ( node )
+				{
+					if ( guard( node ) === false )
+						node = null;
+				}
+				else
+					node = range.startContainer.getNextSourceNode( true, type, guard );
+			}
+		}
 
 		while ( node && !this._.end )
 		{
 			this.current = node;
-
-			if ( node == this.endNode && !this.endInclusive )
-				break;
 
 			if ( !this.evaluator || this.evaluator( node ) !== false )
@@ -66,57 +135,41 @@
 	}
 
-	function iterateToLast( rtl )
-	{
-		var node, last = null;
-
-		while ( node = iterate.call( this, rtl ) )
-			last = node;
-
-		return last;
-	}
+//	function iterateToLast( rtl )
+//	{
+//		var node, last = null;
+
+//		while ( node = iterate.call( this, rtl ) )
+//			last = node;
+
+//		return last;
+//	}
 
 	CKEDITOR.dom.walker = CKEDITOR.tools.createClass(
 	{
 		/**
-		 * Utility class to "walk" inside a DOM tree starting from a specific
-		 * node. Each step in the walk can be preciselly controlled.
+		 * Utility class to "walk" the DOM inside a range boundaries. If
+		 * necessary, partially included nodes (text nodes) are broken to
+		 * reflect the boundaries limits, so DOM and range changes may happen.
+		 * Outside changes to the range may break the walker.
+		 *
+		 * The walker may return nodes that are not totaly included into the
+		 * range boundaires. Let's take the following range representation,
+		 * where the square brackets indicate the boundaries:
+		 *
+		 * [&lt;p&gt;Some &lt;b&gt;sample] text&lt;/b&gt;
+		 *
+		 * While walking forward into the above range, the following nodes are
+		 * returned: &lt;p&gt;, "Some ", &lt;b&gt; and "sample". Going
+		 * backwards instead we have: "sample" and "Some ". So note that the
+		 * walker always returns nodes when "entering" them, but not when
+		 * "leaving" them. The guard function is instead called both when
+		 * entering and leaving nodes.
+		 *
 		 * @constructor
-		 * @param {CKEDITOR.dom.node} startNode The node from wich the walk
-		 *		will start.
-		 * @param {CKEDITOR.dom.node} [endNode] The last node to be considered
-		 *		in the walk. No more nodes are retrieved after touching or
-		 *		passing it.
+		 * @param {CKEDITOR.dom.range} range The range within which walk.
 		 */
-		$ : function( startNode, endNode )
-		{
-			/**
-			 * The node from which start walking.
-			 * @type {CKEDITOR.dom.node}
-			 */
-			this.startNode = startNode;
-
-			/**
-			 * The end boundary node of the walk.
-			 * @type {CKEDITOR.dom.node}
-			 */
-			this.endNode = endNode;
-
-			/**
-			 * Indicates that the start node is to be included in the walk.
-			 * @name CKEDITOR.pluginDefinition.prototype.startInclusive
-			 * @property
-			 * @type Boolean
-			 * @default false
-			 */
-			// this.startInclusive = false;
-
-			/**
-			 * Indicates that the end node is to be included in the walk.
-			 * @name CKEDITOR.pluginDefinition.prototype.endInclusive
-			 * @property
-			 * @type Boolean
-			 * @default false
-			 */
-			// this.endInclusive = false;
+		$ : function( range )
+		{
+			this.range = range;
 
 			/**
@@ -147,4 +200,30 @@
 		},
 
+//		statics :
+//		{
+//			/* Creates a CKEDITOR.dom.walker instance to walk inside DOM boundaries set by nodes.
+//			 * @param {CKEDITOR.dom.node} startNode The node from wich the walk
+//			 *		will start.
+//			 * @param {CKEDITOR.dom.node} [endNode] The last node to be considered
+//			 *		in the walk. No more nodes are retrieved after touching or
+//			 *		passing it. If not provided, the walker stops at the
+//			 *		&lt;body&gt; closing boundary.
+//			 * @returns {CKEDITOR.dom.walker} A DOM walker for the nodes between the
+//			 *		provided nodes.
+//			 */
+//			createOnNodes : function( startNode, endNode, startInclusive, endInclusive )
+//			{
+//				var range = new CKEDITOR.dom.range();
+//				range.setStartAt( startNode, startInclusive ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_END ) ;
+
+//				if ( endNode )
+//					range.setEndAt( endNode, endInclusive ? CKEDITOR.POSITION_AFTER_END : CKEDITOR.POSITION_BEFORE_START ) ;
+//				else
+//					range.setEndAt( startNode.getDocument().getBody(), CKEDITOR.POSITION_BEFORE_END ) ;
+
+//				return new CKEDITOR.dom.walker( range );
+//			}
+//		},
+
 		proto :
 		{
@@ -167,5 +246,5 @@
 				return iterate.call( this );
 			},
-
+			
 			/**
 			 * Retrieves the previous node (at left).
@@ -179,26 +258,4 @@
 
 			/**
-			 * Executes a full walk forward (to the right), until no more nodes
-			 * are available, returning the last valid node.
-			 * @returns {CKEDITOR.dom.node} The last node at the right or null
-			 *		if no valid nodes are available.
-			 */
-			lastForward : function()
-			{
-				return iterateToLast.call( this );
-			},
-
-			/**
-			 * Executes a full walk backwards (to the left), until no more nodes
-			 * are available, returning the last valid node.
-			 * @returns {CKEDITOR.dom.node} The last node at the left or null
-			 *		if no valid nodes are available.
-			 */
-			lastBackward : function()
-			{
-				return iterateToLast.call( this, true );
-			},
-
-			/**
 			 * Check all nodes at right, executing the evaluation fuction.
 			 * @returns {Boolean} "false" if the evaluator function returned
@@ -219,4 +276,29 @@
 				return iterate.call( this, true, true ) !== false;
 			}
+
+// The following features have been originally included in the implementation,
+// but they are not used anywhere in the code, so they got commented out.
+
+//			/**
+//			 * Executes a full walk forward (to the right), until no more nodes
+//			 * are available, returning the last valid node.
+//			 * @returns {CKEDITOR.dom.node} The last node at the right or null
+//			 *		if no valid nodes are available.
+//			 */
+//			lastForward : function()
+//			{
+//				return iterateToLast.call( this );
+//			},
+
+//			/**
+//			 * Executes a full walk backwards (to the left), until no more nodes
+//			 * are available, returning the last valid node.
+//			 * @returns {CKEDITOR.dom.node} The last node at the left or null
+//			 *		if no valid nodes are available.
+//			 */
+//			lastBackward : function()
+//			{
+//				return iterateToLast.call( this, true );
+//			}
 		}
 	});
Index: /CKEditor/trunk/_source/tests/core/dom/walker.html
===================================================================
--- /CKEditor/trunk/_source/tests/core/dom/walker.html	(revision 3463)
+++ /CKEditor/trunk/_source/tests/core/dom/walker.html	(revision 3463)
@@ -0,0 +1,339 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>CKEDITOR.dom.walker</title>
+	<link rel="stylesheet" type="text/css" href="../../test.css" />
+	<script type="text/javascript" src="../../../../ckeditor_source.js"></script> <!-- %REMOVE_LINE%
+	<script type="text/javascript" src="../../../ckeditor.js"></script>
+	%REMOVE_LINE% -->
+	<script type="text/javascript" src="../../test.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+var tc;
+
+CKEDITOR.test.addTestCase( tc = (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	var doc = new CKEDITOR.dom.document( document );
+	
+	function assertNodesList( wanted, nodes )
+	{
+		var simplifiedNodes = [];
+		
+		for ( var i = 0 ; i < nodes.length ; i++ )
+			simplifiedNodes.push( nodes[i].type == CKEDITOR.NODE_TEXT ? nodes[i].getText() : ( '<' + nodes[i].getName() + '>' ) );
+
+		assert.areSame( wanted.toString(), simplifiedNodes.toString() );
+	}
+
+	return {
+
+		test_collapsed : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( node.getFirst(), CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+			
+			assert.isNull( walker.next() );
+		},
+
+		test_next_1 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.next() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ '<p>', 'This is ', '<b>', 'a ', '<i>', 'simple', ' test' ], nodes );
+		},
+
+		test_next_2 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getFirst(), CKEDITOR.POSITION_AFTER_START );
+			range.setEnd( node.getChild( [0,1,1,0] ), 2 );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.next() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ 'This is ', '<b>', 'a ', '<i>', 'si' ], nodes );
+		},
+
+		test_next_3 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 1 ), CKEDITOR.POSITION_BEFORE_START );
+			range.setEndAt( node.getChild( 1 ), CKEDITOR.POSITION_AFTER_START );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.next() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ '<h1>' ], nodes );
+		},
+
+		test_next_4 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 0 ), CKEDITOR.POSITION_BEFORE_END );
+			range.setEndAt( node.getChild( 0 ), CKEDITOR.POSITION_AFTER_END );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.next() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [], nodes );
+		},
+
+		test_next_5 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 0 ), CKEDITOR.POSITION_BEFORE_END );
+			range.setEndAt( node.getChild( 1 ), CKEDITOR.POSITION_AFTER_START );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.next() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ '<h1>' ], nodes );
+		},
+
+		test_previous_1 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.previous() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ '<p>', ' test', '<b>', '<i>', 'simple', 'a ', 'This is ' ], nodes );
+		},
+
+		test_previous_2 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEnd( node.getChild( [0,0] ), 2 );
+			range.setEnd( node.getChild( [0,1,1,0] ), 2 );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.previous() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ 'si', 'a ', 'is is ' ], nodes );
+		},
+
+		test_previous_3 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 1 ), CKEDITOR.POSITION_BEFORE_START );
+			range.setEndAt( node.getChild( 1 ), CKEDITOR.POSITION_AFTER_START );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.previous() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ '' ], nodes );
+		},
+
+		test_previous_4 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 0 ), CKEDITOR.POSITION_BEFORE_END );
+			range.setEndAt( node.getChild( 0 ), CKEDITOR.POSITION_AFTER_END );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.previous() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ '<p>' ], nodes );
+		},
+
+		test_previous_5 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 0 ), CKEDITOR.POSITION_BEFORE_END );
+			range.setEndAt( node.getChild( 1 ), CKEDITOR.POSITION_AFTER_START );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [],
+				node;
+			while ( node = walker.previous() )
+			{
+				nodes.push( node );
+			}
+
+			assertNodesList( [ '<p>' ], nodes );
+		},
+
+		/**
+		 *  Test guard function is invoked on every move when iterating forward.
+		 */
+		test_guard_1 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+			var nodes = [],
+				node;
+			walker.guard = function( node ){
+				nodes.push( node );
+				return true;
+			};
+			while ( node = walker.next() )
+			{}
+
+			assertNodesList( [ '<p>', 'This is ', '<b>', 'a ', '<i>', 'simple', '<i>', '<b>',' test' , '<p>' ], nodes );
+		},
+
+		/**
+		 *  Test guard function is invoked on every move when iterating backward.
+		 */
+		test_guard_2 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+			var nodes = [],
+				node;
+			walker.guard = function( node ){
+				nodes.push( node );
+				return true;
+			};
+			while ( node = walker.previous() )
+			{}
+
+			assertNodesList( [ '<p>', ' test', '<b>', '<i>', 'simple', '<i>', 'a ', '<b>', 'This is ', '<p>' ], nodes );
+		},
+
+		/**
+		 *  Test evaluator function is invoked on every  step when iterating backward.
+		 */
+		test_evaluator_1 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+			
+			var walker = new CKEDITOR.dom.walker( range );
+			var nodes = [],
+				node;
+			walker.evaluator = function( node ){
+				nodes.push( node );
+				return true;
+			};
+			while ( node = walker.previous() )
+			{}
+
+			assertNodesList( [ '<p>', ' test', '<b>', '<i>', 'simple', 'a ', 'This is ' ], nodes );
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+	<div id="playground"></p>
+</body>
+</html>
