Index: CKEditor/trunk/CHANGES.html
===================================================================
--- CKEditor/trunk/CHANGES.html	(revision 6336)
+++ CKEditor/trunk/CHANGES.html	(revision 6337)
@@ -99,4 +99,5 @@
 		<li><a href="http://dev.ckeditor.com/ticket/6728">#6728</a> :  [BIDI] Change direction doesn't work with list nested inside blockquote.</li>
 		<li><a href="http://dev.ckeditor.com/ticket/6432">#6432</a> :  Insert table over fully selected list result in JavaScript error.</li>
+		<li><a href="http://dev.ckeditor.com/ticket/6438">#6438</a> :  [IE] Performance enhancement when typing inside an element with many child nodes.</li>
 		<li>Updated the following language files:<ul>
 			<li><a href="http://dev.ckeditor.com/ticket/6981">#6981</a> : English (GB);</li>
Index: CKEditor/trunk/_source/plugins/selection/plugin.js
===================================================================
--- CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 6336)
+++ CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 6337)
@@ -557,4 +557,6 @@
 				( function()
 				{
+					function getNodeIndex( node ) { return new CKEDITOR.dom.node( node ).getIndex(); }
+
 					// Finds the container and offset for a specific boundary
 					// of an IE range.
@@ -567,74 +569,96 @@
 						// Gets the element that encloses the range entirely.
 						var parent = range.parentElement();
-						var siblings = parent.childNodes;
-
-						var testRange;
-
-						for ( var i = 0 ; i < siblings.length ; i++ )
-						{
-							var child = siblings[ i ];
-							if ( child.nodeType == 1 )
-							{
-								testRange = range.duplicate();
-
-								testRange.moveToElementText( child );
-
-								var comparisonStart = testRange.compareEndPoints( 'StartToStart', range ),
-									comparisonEnd = testRange.compareEndPoints( 'EndToStart', range );
-
-								testRange.collapse();
-
-								if ( comparisonStart > 0 )
-									break;
-								// When selection stay at the side of certain self-closing elements, e.g. BR,
-								// our comparison will never shows an equality. (#4824)
-								else if ( !comparisonStart
-									|| comparisonEnd == 1 && comparisonStart == -1 )
-									return { container : parent, offset : i };
-								else if ( !comparisonEnd )
-									return { container : parent, offset : i + 1 };
-
-								testRange = null;
+
+						// Empty parent element, e.g. <i>^</i>
+						if ( !parent.hasChildNodes() )
+							return  { container : parent, offset : 0 };
+
+						var siblings = parent.children,
+							child,
+							testRange = range.duplicate(),
+							startIndex = 0,
+							endIndex = siblings.length - 1,
+							index = -1,
+							position,
+							distance;
+
+						// Binary search over all element childs to test the range to see whether
+						// range is right on the boundary of one element.
+						while ( startIndex <= endIndex )
+						{
+							index = Math.floor( ( startIndex + endIndex ) / 2 );
+							child = siblings[ index ];
+							testRange.moveToElementText( child );
+							position = testRange.compareEndPoints( 'StartToStart', range );
+
+							if ( position > 0 )
+								endIndex = index - 1;
+							else if ( position < 0 )
+								startIndex = index + 1;
+							else
+								return { container : parent, offset : getNodeIndex( child ) };
+						}
+
+						// All childs are text nodes.
+						if ( index == -1 )
+						{
+							// Adapt test range to embrace the entire parent contents.
+							testRange.moveToElementText( parent );
+							testRange.setEndPoint( 'StartToStart', range );
+
+							// IE report line break as CRLF with range.text but
+							// only LF with textnode.nodeValue, normalize them to avoid
+							// breaking character counting logic below. (#3949)
+							distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
+
+							siblings = parent.childNodes;
+
+							// Actual range anchor right beside test range at the inner boundary of text node.
+							if ( !distance )
+							{
+								child = siblings[ siblings.length - 1 ];
+								return  { container : child, offset : child.nodeValue.length };
 							}
-						}
-
-						if ( !testRange )
-						{
-							testRange = range.duplicate();
-							testRange.moveToElementText( parent );
-							testRange.collapse( false );
-						}
-
-						testRange.setEndPoint( 'StartToStart', range );
-						// IE report line break as CRLF with range.text but
-						// only LF with textnode.nodeValue, normalize them to avoid
-						// breaking character counting logic below. (#3949)
-						var distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
-
-						try
-						{
+
+							// Start the measuring until distance overflows, meanwhile count the text nodes.
+							var i = siblings.length;
 							while ( distance > 0 )
 								distance -= siblings[ --i ].nodeValue.length;
+
+							return  { container : siblings[ i ], offset : -distance };
 						}
-						// Measurement in IE could be somtimes wrong because of <select> element. (#4611)
-						catch( e )
-						{
-							distance = 0;
-						}
-
-
-						if ( distance === 0 )
-						{
-							return {
-								container : parent,
-								offset : i
-							};
-						}
+						// Test range was one offset beyond OR behind the anchored text node.
 						else
 						{
-							return {
-								container : siblings[ i ],
-								offset : -distance
-							};
+							// Adapt one side of test range to the actual range
+							// for measuring the offset between them.
+							testRange.collapse( position > 0 ? true : false );
+							testRange.setEndPoint( position > 0 ? 'StartToStart' : 'EndToStart', range );
+
+							// IE report line break as CRLF with range.text but
+							// only LF with textnode.nodeValue, normalize them to avoid
+							// breaking character counting logic below. (#3949)
+							distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
+
+							// Actual range anchor right beside test range at the inner boundary of text node.
+							if ( !distance )
+								return { container : parent, offset : getNodeIndex( child ) + ( position > 0 ? -1 : 1 ) };
+
+							// Start the measuring until distance overflows, meanwhile count the text nodes.
+							while ( distance > 0 )
+							{
+								child = child[ position > 0 ? 'previousSibling' : 'nextSibling' ];
+								try
+								{
+									distance -= child.nodeValue.length;
+								}
+								// Measurement in IE could be somtimes wrong because of <select> element. (#4611)
+								catch( e )
+								{
+									return { container : parent, offset : getNodeIndex( child ) };
+								}
+							}
+
+							return { container : child, offset : position > 0 ? -distance : child.nodeValue.length + distance };
 						}
 					};
