Index: /CKEditor/branches/features/pasting/_source/core/htmlparser.js
===================================================================
--- /CKEditor/branches/features/pasting/_source/core/htmlparser.js	(revision 4226)
+++ /CKEditor/branches/features/pasting/_source/core/htmlparser.js	(revision 4227)
@@ -173,5 +173,5 @@
 				{
 					tagName = tagName.toLowerCase();
-					var attribs = {},
+					var attribs,
 						attribMatch,
 						attribsPart = parts[ 4 ],
@@ -180,4 +180,5 @@
 					if ( attribsPart )
 					{
+						attribs = {};
 						while ( ( attribMatch = attribsRegex.exec( attribsPart ) ) )
 						{
Index: /CKEditor/branches/features/pasting/_source/core/htmlparser/element.js
===================================================================
--- /CKEditor/branches/features/pasting/_source/core/htmlparser/element.js	(revision 4226)
+++ /CKEditor/branches/features/pasting/_source/core/htmlparser/element.js	(revision 4227)
@@ -114,5 +114,5 @@
 			{
 				var writer = new CKEDITOR.htmlParser.basicWriter();
-				CKEDITOR.htmlParser.fragment.prototype.writeHtml.call( element, writer, filter );
+				CKEDITOR.htmlParser.fragment.prototype.writeChildrenHtml.call( element, writer, filter );
 				element.children = new CKEDITOR.htmlParser.fragment.fromHtml( writer.getHtml() ).children;
 				isChildrenFiltered = 1;
@@ -140,5 +140,5 @@
 					if ( !writeName )
 					{
-						this.writeChildrenHtml( writer, isChildrenFiltered ? null : filter );
+						this.writeChildrenHtml.call( element, writer, isChildrenFiltered ? null : filter );
 						return;
 					}
@@ -195,5 +195,5 @@
 			if ( !element.isEmpty )
 			{
-				this.writeChildrenHtml( writer, isChildrenFiltered ? null : filter );
+				this.writeChildrenHtml.call( element, writer, isChildrenFiltered ? null : filter );
 				// Close the element.
 				writer.closeTag( writeName );
@@ -204,5 +204,5 @@
 		{
 			// Send children.
-			CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( this, arguments );
+			CKEDITOR.htmlParser.fragment.prototype.writeChildrenHtml.apply( this, arguments );
 
 		}
Index: /CKEditor/branches/features/pasting/_source/core/htmlparser/fragment.js
===================================================================
--- /CKEditor/branches/features/pasting/_source/core/htmlparser/fragment.js	(revision 4226)
+++ /CKEditor/branches/features/pasting/_source/core/htmlparser/fragment.js	(revision 4227)
@@ -426,9 +426,27 @@
 		 * alert( writer.getHtml() );  "&lt;p&gt;&lt;b&gt;Example&lt;/b&gt;&lt;/p&gt;"
 		 */
-		writeHtml : function( writer, filter )
+		writeHtml : function( writer, filter, skipSelf )
+		{
+			var isChildrenFiltered;
+			this.filterChildren = function()
+			{
+				var writer = new CKEDITOR.htmlParser.basicWriter();
+				this.writeChildrenHtml.call( this, writer, filter, true );
+				this.children = new CKEDITOR.htmlParser.fragment.fromHtml( writer.getHtml() ).children;
+				isChildrenFiltered = 1;
+			};
+
+			if ( !filter.onElement( this ) )
+				return;
+
+			this.writeChildrenHtml( writer, isChildrenFiltered ? null : filter );
+		},
+
+		writeChildrenHtml : function( writer, filter )
 		{
 			for ( var i = 0, len = this.children.length ; i < len ; i++ )
 				this.children[i].writeHtml( writer, filter );
 		}
+
 	};
 })();
Index: /CKEditor/branches/features/pasting/_source/plugins/clipboard/plugin.js
===================================================================
--- /CKEditor/branches/features/pasting/_source/plugins/clipboard/plugin.js	(revision 4226)
+++ /CKEditor/branches/features/pasting/_source/plugins/clipboard/plugin.js	(revision 4227)
@@ -243,5 +243,19 @@
 				CKEDITOR.pasteProcessor.prototype =
 				{
-					toHtml : CKEDITOR.htmlDataProcessor.prototype.toHtml
+					toHtml : function( data )
+					{
+						var oldDtd = CKEDITOR.dtd.ul;
+						CKEDITOR.dtd.ul = CKEDITOR.dtd.ol =
+						    CKEDITOR.tools.extend( CKEDITOR.tools.clone( oldDtd ), { ol : 1, ul : 1 } );
+
+						var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data, false ),
+							writer = new CKEDITOR.htmlParser.basicWriter();
+
+						CKEDITOR.dtd.ul = CKEDITOR.dtd.ol = oldDtd;
+
+						fragment.writeHtml( writer, this.dataFilter );
+						// Go through the default processor at last.
+						return this.editor.dataProcessor.toHtml( writer.getHtml( true ) );
+					}
 				};
 
Index: /CKEditor/branches/features/pasting/_source/plugins/fakeobjects/plugin.js
===================================================================
--- /CKEditor/branches/features/pasting/_source/plugins/fakeobjects/plugin.js	(revision 4226)
+++ /CKEditor/branches/features/pasting/_source/plugins/fakeobjects/plugin.js	(revision 4227)
@@ -12,5 +12,6 @@
 			$ : function( element )
 			{
-				var realHtml = element.attributes._cke_realelement,
+				var attributes = element.attributes,
+					realHtml = attributes && attributes._cke_realelement,
 					realFragment = realHtml && new CKEDITOR.htmlParser.fragment.fromHtml( decodeURIComponent( realHtml ) ),
 					realElement = realFragment && realFragment.children[ 0 ];
Index: /CKEditor/branches/features/pasting/_source/plugins/pastefromword/plugin.js
===================================================================
--- /CKEditor/branches/features/pasting/_source/plugins/pastefromword/plugin.js	(revision 4226)
+++ /CKEditor/branches/features/pasting/_source/plugins/pastefromword/plugin.js	(revision 4227)
@@ -3,308 +3,562 @@
 For licensing, see LICENSE.html or http://ckeditor.com/license
 */
-
-CKEDITOR.plugins.add( 'pastefromword',
+( function()
 {
-	init : function( editor )
+	CKEDITOR.plugins.add( 'pastefromword',
 	{
-		// Register the command.
-		editor.addCommand( 'pastefromword', new CKEDITOR.dialogCommand( 'pastefromword' ) );
-		// Register the dialog.
-		CKEDITOR.dialog.add( 'pastefromword', this.path + 'dialogs/pastefromword.js' );
-
-		// Register the toolbar button.
-		editor.ui.addButton( 'PasteFromWord',
+		init : function( editor )
+		{
+			// Register the command.
+			editor.addCommand( 'pastefromword', new CKEDITOR.dialogCommand( 'pastefromword' ) );
+			// Register the dialog.
+			CKEDITOR.dialog.add( 'pastefromword', this.path + 'dialogs/pastefromword.js' );
+
+			// Register the toolbar button.
+			editor.ui.addButton( 'PasteFromWord',
+				{
+					label : editor.lang.pastefromword.toolbar,
+					command : 'pastefromword'
+				} );
+
+			var config = editor.config,
+				ignoreFontFace = config.pasteFromWordIgnoreFontFace,
+				removeStyleAttr = config.pasteFromWordRemoveStyle;
+
+			editor.on( 'paste', function( evt )
 			{
-				label : editor.lang.pastefromword.toolbar,
-				command : 'pastefromword'
+				var mswordHtml;
+				// MS-WORD format sniffing.
+				if ( ( mswordHtml = evt.data[ 'html' ] )
+					 && /(class=\"?Mso|style=\"[^\"]*\bmso\-|w:WordDocument)/.test( mswordHtml ) )
+				{
+					// 1. Pre fixing downlevel-revealed IE conditional comments for the parser.
+					//    e.g. <!--[if !vml]--><img ... /><!--[endif]-->
+					// 2. Join consequent IE comments into one for easy handling.
+					if( !CKEDITOR.env.ie )
+						evt.data[ 'html' ] =
+							mswordHtml.replace( /(<!--\[if[^<]*?\])-->([\S\s]*?)<!--(\[endif\]-->)/gi, '$1$2$3' )
+									  .replace( /(\[endif\])--(>\s*<)!--(\[if)/gi, '$1$2$3' );
+
+					var filter = editor.pasteProcessor.dataFilter;
+					// These rules will have higher priorities than default ones.
+					filter.addRules( CKEDITOR.plugins.pastefromword.getRules( editor ), 5 );
+				}
 			} );
-		
-		var config = editor.config,
-			keepHeadingStructure = config.pasteFromWordKeepsStructure,
-			ignoreFontFace = config.pasteFromWordIgnoreFontFace,
-			removeStyleAttr = config.pasteFromWordRemoveStyle;
-
-		editor.on( 'paste', function( evt )
+
+		}
+	} );
+
+	CKEDITOR.plugins.pastefromword =
+	{
+		/**
+		 * @deprecated Leave it here for reference.
+		 */
+		cleanWord : function( editor, html, ignoreFont, removeStyles )
 		{
-			var mswordHtml;
-			// MS-WORD format sniffing.
-			if ( ( mswordHtml = evt.data[ 'html' ] )
-				 && /(class=\"?Mso|style=\"[^\"]*\bmso\-|w:WordDocument)/.test( mswordHtml ) )
+			// Remove comments [SF BUG-1481861].
+			html = html.replace(/<\!--[\s\S]*?-->/g, '' ) ;
+
+			html = html.replace(/<o:p>\s*<\/o:p>/g, '') ;
+			html = html.replace(/<o:p>[\s\S]*?<\/o:p>/g, '&nbsp;') ;
+
+			// Remove mso-xxx styles.
+			html = html.replace( /\s*mso-[^:]+:[^;"]+;?/gi, '' ) ;
+
+			// Remove margin styles.
+			html = html.replace( /\s*MARGIN: 0(?:cm|in) 0(?:cm|in) 0pt\s*;/gi, '' ) ;
+			html = html.replace( /\s*MARGIN: 0(?:cm|in) 0(?:cm|in) 0pt\s*"/gi, "\"" ) ;
+
+			html = html.replace( /\s*TEXT-INDENT: 0cm\s*;/gi, '' ) ;
+			html = html.replace( /\s*TEXT-INDENT: 0cm\s*"/gi, "\"" ) ;
+
+			html = html.replace( /\s*TEXT-ALIGN: [^\s;]+;?"/gi, "\"" ) ;
+
+			html = html.replace( /\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"" ) ;
+
+			html = html.replace( /\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"" ) ;
+
+			html = html.replace( /\s*tab-stops:[^;"]*;?/gi, '' ) ;
+			html = html.replace( /\s*tab-stops:[^"]*/gi, '' ) ;
+
+			// Remove FONT face attributes.
+			if ( ignoreFont )
 			{
-				var onlyChildOf = function( element )
+				html = html.replace( /\s*face="[^"]*"/gi, '' ) ;
+				html = html.replace( /\s*face=[^ >]*/gi, '' ) ;
+
+				html = html.replace( /\s*FONT-FAMILY:[^;"]*;?/gi, '' ) ;
+			}
+
+			// Remove Class attributes
+			html = html.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3") ;
+
+			// Remove styles.
+			if ( removeStyles )
+				html = html.replace( /<(\w[^>]*) style="([^\"]*)"([^>]*)/gi, "<$1$3" ) ;
+
+			// Remove style, meta and link tags
+			html = html.replace( /<STYLE[^>]*>[\s\S]*?<\/STYLE[^>]*>/gi, '' ) ;
+			html = html.replace( /<(?:META|LINK)[^>]*>\s*/gi, '' ) ;
+
+			// Remove empty styles.
+			html =  html.replace( /\s*style="\s*"/gi, '' ) ;
+
+			html = html.replace( /<SPAN\s*[^>]*>\s*&nbsp;\s*<\/SPAN>/gi, '&nbsp;' ) ;
+
+			html = html.replace( /<SPAN\s*[^>]*><\/SPAN>/gi, '' ) ;
+
+			// Remove Lang attributes
+			html = html.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3") ;
+
+			html = html.replace( /<SPAN\s*>([\s\S]*?)<\/SPAN>/gi, '$1' ) ;
+
+			html = html.replace( /<FONT\s*>([\s\S]*?)<\/FONT>/gi, '$1' ) ;
+
+			// Remove XML elements and declarations
+			html = html.replace(/<\\?\?xml[^>]*>/gi, '' ) ;
+
+			// Remove w: tags with contents.
+			html = html.replace( /<w:[^>]*>[\s\S]*?<\/w:[^>]*>/gi, '' ) ;
+
+			// Remove Tags with XML namespace declarations: <o:p><\/o:p>
+			html = html.replace(/<\/?\w+:[^>]*>/gi, '' ) ;
+
+			html = html.replace( /<(U|I|STRIKE)>&nbsp;<\/\1>/g, '&nbsp;' ) ;
+
+			html = html.replace( /<H\d>\s*<\/H\d>/gi, '' ) ;
+
+			// Remove "display:none" tags.
+			html = html.replace( /<(\w+)[^>]*\sstyle="[^"]*DISPLAY\s?:\s?none[\s\S]*?<\/\1>/ig, '' ) ;
+
+			// Remove language tags
+			html = html.replace( /<(\w[^>]*) language=([^ |>]*)([^>]*)/gi, "<$1$3") ;
+
+			// Remove onmouseover and onmouseout events (from MS Word comments effect)
+			html = html.replace( /<(\w[^>]*) onmouseover="([^\"]*)"([^>]*)/gi, "<$1$3") ;
+			html = html.replace( /<(\w[^>]*) onmouseout="([^\"]*)"([^>]*)/gi, "<$1$3") ;
+
+			if ( editor.config.pasteFromWordKeepsStructure )
+			{
+				// The original <Hn> tag send from Word is something like this: <Hn style="margin-top:0px;margin-bottom:0px">
+				html = html.replace( /<H(\d)([^>]*)>/gi, '<h$1>' ) ;
+
+				// Word likes to insert extra <font> tags, when using MSIE. (Wierd).
+				html = html.replace( /<(H\d)><FONT[^>]*>([\s\S]*?)<\/FONT><\/\1>/gi, '<$1>$2<\/$1>' );
+				html = html.replace( /<(H\d)><EM>([\s\S]*?)<\/EM><\/\1>/gi, '<$1>$2<\/$1>' );
+			}
+			else
+			{
+				html = html.replace( /<H1([^>]*)>/gi, '<div$1><b><font size="6">' ) ;
+				html = html.replace( /<H2([^>]*)>/gi, '<div$1><b><font size="5">' ) ;
+				html = html.replace( /<H3([^>]*)>/gi, '<div$1><b><font size="4">' ) ;
+				html = html.replace( /<H4([^>]*)>/gi, '<div$1><b><font size="3">' ) ;
+				html = html.replace( /<H5([^>]*)>/gi, '<div$1><b><font size="2">' ) ;
+				html = html.replace( /<H6([^>]*)>/gi, '<div$1><b><font size="1">' ) ;
+
+				html = html.replace( /<\/H\d>/gi, '<\/font><\/b><\/div>' ) ;
+
+				// Transform <P> to <DIV>
+				var re = new RegExp( '(<P)([^>]*>[\\s\\S]*?)(<\/P>)', 'gi' ) ;	// Different because of a IE 5.0 error
+				html = html.replace( re, '<div$2<\/div>' ) ;
+
+				// Remove empty tags (three times, just to be sure).
+				// This also removes any empty anchor
+				html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
+				html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
+				html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
+			}
+
+			return html ;
+		},
+
+		utils :
+		{
+			// Create a <cke:listbullet> which indicate an list item type.
+			createListBulletMarker : function ( type )
+			{
+				var marker = new CKEDITOR.htmlParser.element( 'cke:listbullet' ),
+					// We took the decimal as default because we
+					// use 'ol' as root list.
+					defaultListType = 'decimal';
+
+				// TODO: Support more list type mapping rules. 
+				if( !isNaN( type[ 1 ] ) && type[ 2 ] == '.' )
+					type = 'decimal';
+				else if ( type[ 1 ].search( /[l·]/ ) != -1 )
+					type = 'disc';
+				else
+					type = defaultListType;
+
+				// Represent list type as CSS style.
+				if( type != defaultListType )
+					marker.attributes = { style : 'list-style-type:' + type };
+
+				return marker;
+			}
+
+		},
+
+		filters : {
+				/**
+				 * A simple filter which always rejecting.
+				 */
+				falsyFilter  : function( value )
+				{
+					return false;
+				},
+
+				/**
+				 * A filter dedicated on the 'style' attribute for dropping/replacing style rules.
+				 * @param styles {Array} A triple in form of [ styleNameRegexp, styleValueRegexp, newStyleValue ] where the last two are optional.
+				 */
+				stylesFilter : function( styles )
+				{
+					return function( styleText, element )
+					{
+						 var rules = [];
+						 styleText.replace( /\s*([^ :;]+?)\s*:\s*([^;"]+?)\s*(?=;|$)/g,
+							 function( match, name, value )
+							 {
+								 name = name.toLowerCase();
+								 var namePattern,
+									 valuePattern,
+									 newValue;
+								 for( var i = 0 ; i < styles.length && styles[ i ] ; i++ )
+								 {
+									namePattern = styles[ i ][ 0 ];
+									valuePattern = styles[ i ][ 1 ];
+									newValue = styles[ i ][ 2 ];
+
+									if ( name.match( namePattern )
+										 && ( !valuePattern || value.match( valuePattern ) ) )
+									{
+										if( typeof newValue == 'function' )
+											newValue = newValue( value, element );
+										if( typeof newValue == 'string' )
+											rules.push( [ name, newValue ] );
+										return;
+									}
+								 }
+								 rules.push( [ name, value ] );
+
+							 } );
+
+						 for ( var i = 0 ; i < rules.length ; i++ )
+							 rules[ i ] = rules[ i ].join( ':' );
+						 return rules.length ?
+						         ( rules.join( ';' ).replace( /\s+/g, '' ) + ';' )
+						         // Remove attribute if there's no styles.
+								 : false;
+					 };
+				},
+
+				listFilter : function( element )
 				{
 					var children = element.children,
-						count = children.length,
-						firstChild = count && children[ 0 ];
-					return firstChild;
-				};
-
-				var falsyFilter = function()
-					 {
-						return false;
-					 },
-					 dropStyles = function( styles )
-					 {
-						 return function( styleText )
-						 {
-							 var rules = [];
-							 styleText.replace( /(?:"| |;|^ )\s*([^ :]+?)\s*:\s*([^;"]+?)\s*(?=;|"|$)/g,
-								 function( match, name, value )
-								 {
-									 name = name.toLowerCase();
-									 var namePattern,
-										 valuePattern;
-									 for( var i = 0 ; i < styles.length ; i++ )
-									 {
-										namePattern = styles[ i ][ 0 ],
-										valuePattern = styles[ i ][ 1 ];
-
-										if ( !( name.match( namePattern ) && ( !valuePattern || value.match( valuePattern ) ) ) )
-											rules.push( [ name, value ] );
-									 }
-								 } );
-
-							 for ( var i = 0 ; i < rules.length ; i++ )
-								 rules[ i ] = rules[ i ].join( ':' );
-							 return rules && ( rules.join( ';' ).replace( /\s+/g, '' ) + ';' );
-						 };
-					 };
-
-				var filter = editor.pasteProcessor.dataFilter;
-				filter.addRules(
-				{
-					elementNames :
-					[
-						// Remove style, meta and link elements.
-						[ /style|meta|link/, '' ]
-					],
-
-					elements :
-					{
-						$ : function( element )
-						{
-
-							var tagName = element.name;
-
-							var match, level;
-							// Processing headings.
-							if ( ( match = tagName.match( /h(\d)/i ) ) && ( level = match[ 1 ] ) )
+						length = children.length,
+						child, previousChild;
+					for( var i = 0 ; i < length; i++ )
+					{
+						child = children[ i ];
+
+						// Wrap nested list root with the previous list item.
+						if ( child.name && child.name in { ul : 1, ol : 1 } )
+						{
+							children.splice( i, 1 );
+							previousChild.children.push( child );
+						}
+						previousChild = child;
+					}
+				}
+
+			},
+
+		getRules : function( editor )
+		{
+			var falsyFilter = this.filters.falsyFilter,
+				stylesFilter = this.filters.stylesFilter,
+				listFilter = this.filters.listFilter,
+				createListBulletMarker = this.utils.createListBulletMarker,
+				config = editor.config,
+				ignoreFontFace = config.pasteFromWordIgnoreFontFace,
+				removeStyleAttr = config.pasteFromWordRemoveStyle;
+
+			return {
+
+				elementNames :
+				[
+					// Remove style, meta and link elements.
+					[ /style|meta|link/, '' ]
+				],
+
+				elements :
+				{
+					$ : function( element )
+					{
+
+						var tagName = element.name || '';
+
+						var match, level;
+						// Processing headings.
+						if ( ( match = tagName.match( /h(\d)/i ) ) && ( level = match[ 1 ] ) )
+						{
+							element.filterChildren();
+							var child = element.onlyChild();
+
+							// Remove empty headings.
+							if( child && child.value
+								&& !CKEDITOR.tools.trim( child.value ) )
+								return false;
+							// The original <Hn> tag send from Word is something like this: <Hn style="margin-top:0px;margin-bottom:0px">
+							delete element.attributes;
+
+							// Word likes to insert extra <font> tags, when using MSIE. (Wierd).
+							if ( child && /em|font/.exec( child.name ) )
+								element.children = child.children;
+						}
+						// Remove inline elements which contain only empty spaces.
+						else if( tagName.match( /^(:?b|u|i|strike|span)$/ ) )
+						{
+							element.filterChildren();
+							var child = element.onlyChild();
+							if ( child && /(:?\s|&nbsp;)+/.exec( child.value ) )
+								delete element.name;
+						}
+						// Remove dummy inline wrappers.
+						else if( tagName.match( /span|font/ ) )
+						{
+							if( !element.attributes )
+								delete element.name;
+						}
+						// Remove namespaced element while preserving the content.
+						else if( tagName.indexOf( ':' ) != -1
+								 && tagName.indexOf( 'cke' ) == -1 )
+						{
+							delete element.name;
+						}
+						// Any dtd-valid element which could contain a list.
+						else if( !tagName && element.children
+								 || tagName in CKEDITOR.dtd.parentOf( 'ol' ) )
+						{
+							element.filterChildren();
+
+							var children = element.children, child,
+								listItem,   // The current processing cke:li element.
+								listItemIndent, // Indent attribute represent the level of it.
+								lastListItem, // The previous one just been added to the list.
+								list, parentList, // Current staging list and it's parent list if any.  
+								indent;
+
+							for( var i = 0 ; i < children.length; i++ )
 							{
-								element.filterChildren();
-								var child = onlyChildOf( element );
-
-								// Remove empty headings.
-								if( child && child.value
-									&& !CKEDITOR.tools.trim( child.value ) )
-									return false;
-
-								// The original <Hn> tag send from Word is something like this: <Hn style="margin-top:0px;margin-bottom:0px">
-								delete element.attributes;
-
-								if ( keepHeadingStructure )
+								child = children[ i ];
+
+								if ( 'cke:li' == child.name )
 								{
-									// Word likes to insert extra <font> tags, when using MSIE. (Wierd).
-									if ( child && /em|font/.exec( child.name ) )
-										element.children = child.children;
+									child.name = 'li';
+									
+									listItem = child;
+									listItemIndent = listItem.attributes.indent,
+									delete listItem.attributes.indent;
+
+									if ( !list )
+									{
+										parentList = list = new CKEDITOR.htmlParser.element( 'ol' );
+										list.add( listItem );
+										children[ i ] = list;
+									}
+									else
+									{
+										if( listItemIndent > indent )
+										{
+											parentList = list;
+											list = new CKEDITOR.htmlParser.element( 'ol' );
+											list.add( listItem );
+											lastListItem.add( list );
+										}
+										else if( listItemIndent < indent )
+										{
+											list = parentList;
+											list.add( listItem );
+										}
+										else
+											list.add( listItem );
+
+										children.splice( i-- , 1 );
+									}
+
+									lastListItem = listItem;
+									indent = listItemIndent;
 								}
 								else
+									list = null;
+							}
+
+						}
+					},
+
+					'ul' : listFilter,
+					'ol' : listFilter,
+					'p' : function( element )
+					{
+						element.filterChildren();
+
+						var attrs = element.attributes,
+							children = element.children,
+							firstChild = children && children[ 0 ];
+
+						// <cke:listbullet> been the first child of any paragraph
+						// indicate a list item.
+						if( 'cke:listbullet' == firstChild.name )
+						{
+							element.name = 'cke:li';
+							attrs.style = stylesFilter(
+							[
+								[ 'text-indent' ],
+								[ 'margin-left', null, function( value )
 								{
-									// Transform headings to divs.
-									element.name = 'div';
-									var bold = new CKEDITOR.htmlParser.element( 'b' ),
-										font = new CKEDITOR.htmlParser.element( 'font', { size : Math.abs( 7 - level ) } );
-									font.children = element.children;
-									bold.children  = [ font ];
-									element.children = [ bold ];
-								}
-							}
-							// Remove inline elements which contain only empty spaces.
-							else if( tagName.match( /^(:?b|u|i|strike|span)$/ ) )
-							{
-								element.filterChildren();
-								var child = onlyChildOf( element );
-								if ( child && /(:?\s|&nbsp;)+/.exec( child.value ) )
-									delete element.name;
-							}
-							// Remove dummy inline wrappers.
-							else if( tagName.match( /span|font/ ) )
-							{
-								if( !element.attributes )
-									delete element.name;
-							}
-							// Remove namespaced element while preserving the content.
-							else if( tagName.indexOf( ':' ) != -1 )
-							{
-								delete element.name;
-							}
+									// Resolve indent level from 'margin-left' style.
+									attrs.indent = parseInt( value );
+								} ]
+							] )( attrs.style, element ) || '' ;
+
+							// Inherit list-type-style from bullet. 
+							var listBulletAttrs = firstChild.attributes,
+								listBulletStyle = listBulletAttrs && listBulletAttrs.style;
+							if( listBulletStyle )
+								attrs.style = listBulletStyle;
+							children.splice( 0, 1 );
 						}
 					},
-
-					attributeNames :
+					'span' : function( element )
+					{
+						element.filterChildren();
+
+						var attrs = element.attributes,
+							styles = attrs && attrs.style;
+						if( styles )
+						{
+							var marker;
+							stylesFilter(
+							[
+								[ 'mso-list', 'Ignore', function( value, element )
+								{
+
+									var listType = element.firstTextChild().value.match( /([^\s])([.)]?)/ );
+									marker = createListBulletMarker( listType );
+								} ]
+							] )( styles, element );
+
+							if( marker )
+								return marker;
+						}
+
+						var onlyChild = element.onlyChild();
+						if( onlyChild && 'cke:listbullet' == onlyChild.name )
+							return onlyChild;
+					}
+				},
+
+				attributeNames :
+				[
+					// Remove onmouseover and onmouseout events (from MS Word comments effect)
+					[ /^onmouse(:?out|over)/, '' ],
+					// Remove lang/language attributes.
+					[ /^lang/, '' ],
+					ignoreFontFace ? [ 'face', '' ] : null
+				],
+
+				attributes :
+				{
+					// Remove mso-xxx styles.
+					// Remove margin styles.
+					'style' : stylesFilter(
 					[
-						// Remove onmouseover and onmouseout events (from MS Word comments effect)
-						[ /^onmouse(:?out|over)/, '' ],
-						// Remove lang/language attributes.
-						[ /^lang/, '' ],
-						removeStyleAttr ? [ 'style', '' ] :
-						ignoreFontFace ? [ 'face', '' ] : null
-					],
-
-					attributes :
-					{
-						// Remove mso-xxx styles.
-						// Remove margin styles.
-						'style' : dropStyles(
-						[
-							[ /^mso-/ ],
-							[ 'margin', /0(?:cm|in) 0(?:cm|in) 0pt/ ],
-							[ 'text-indent', '0cm' ],
-							[ 'page-break-before' ],
-							[ 'tab-stops' ],
-							[ 'display', 'none' ],
-							ignoreFontFace ? [ 'font-family' ] : null
-						] ),
-						
-						'class' : falsyFilter,
-
-						// Remove align="left" attribute.
-						'align' : function( value )
-						{
-							return value == 'left ' ? false : value;
-						}
-					},
-					// Remove comments [SF BUG-1481861].
-					comment : falsyFilter
-				}, 5 );
-
-			}
-		} );
-
+						[ /mso-/ ],
+						[ 'margin', /0(?:cm|in) 0(?:cm|in) 0pt/ ],
+						[ 'text-indent', '0cm' ],
+						[ 'page-break-before' ],
+						[ 'tab-stops' ],
+						[ 'display', 'none' ],
+						[ 'text-align', 'left' ],
+						ignoreFontFace ? [ 'font-family' ] : null,
+					] ),
+
+					'class' : falsyFilter,
+
+					// Remove align="left" attribute.
+					'align' : function( value )
+					{
+						return value == 'left' ? false : value;
+					}
+				},
+				comment : function( value )
+				{
+					var imageSource = value.match( /<img.*?>/ ),
+						listInfo = value.match( /^\[if !supportLists\]([\s\S]*?)\[endif\]$/ );
+
+					// Image 'src' attribute might be embedded within vml.
+					if( imageSource )
+					{
+						var image = CKEDITOR.htmlParser.fragment.fromHtml( imageSource ).children[ 0 ],
+							attrs = image.attributes;
+						delete attrs[ 'v:shapes'];
+
+						// Try to reveal the real image source from vml elements.
+						var imageData = value.match( /<v:imagedata[^>]*o:href=['"](.*?)['"]/ ),
+							imageSrc = imageData && imageData[ 1 ];
+						imageSrc && ( attrs.src = imageSrc );
+						return image;
+					}
+					// Seek for list bullet style indicator.
+					else if ( listInfo )
+					{
+						var listSymbol = listInfo[ 1 ],
+							listType = listSymbol.match( />([^\s])([.)]?)</ );
+
+						return createListBulletMarker( listType );
+					}
+					return false;
+				}
+			};
+		}
 	}
-} );
-
-CKEDITOR.plugins.pastefromword =
-{
+
+	CKEDITOR.htmlParser.element.prototype.onlyChild = function()
+	{
+		var children = this.children,
+			count = children.length,
+			firstChild = count && children[ 0 ];
+		return firstChild || null;
+	};
+
+	CKEDITOR.htmlParser.element.prototype.firstTextChild = function()
+	{
+		var child;
+		for( var i = 0 ; i < this.children.length ; i++ )
+		{
+			child = this.children[ i ];
+			if( child.value )
+				return child;
+		}
+	};
+
 	/**
-	 * @depprecated Leave it here for reference.
+	 * Return the DTD-valid parent tag names of the specified one.
+	 * @param tagName
 	 */
-	cleanWord : function( editor, html, ignoreFont, removeStyles )
+	CKEDITOR.dtd.parentOf = function( tagName )
 	{
-		// Remove comments [SF BUG-1481861].
-		html = html.replace(/<\!--[\s\S]*?-->/g, '' ) ;
-
-		html = html.replace(/<o:p>\s*<\/o:p>/g, '') ;
-		html = html.replace(/<o:p>[\s\S]*?<\/o:p>/g, '&nbsp;') ;
-
-		// Remove mso-xxx styles.
-		html = html.replace( /\s*mso-[^:]+:[^;"]+;?/gi, '' ) ;
-
-		// Remove margin styles.
-		html = html.replace( /\s*MARGIN: 0(?:cm|in) 0(?:cm|in) 0pt\s*;/gi, '' ) ;
-		html = html.replace( /\s*MARGIN: 0(?:cm|in) 0(?:cm|in) 0pt\s*"/gi, "\"" ) ;
-
-		html = html.replace( /\s*TEXT-INDENT: 0cm\s*;/gi, '' ) ;
-		html = html.replace( /\s*TEXT-INDENT: 0cm\s*"/gi, "\"" ) ;
-
-		html = html.replace( /\s*TEXT-ALIGN: [^\s;]+;?"/gi, "\"" ) ;
-
-		html = html.replace( /\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"" ) ;
-
-		html = html.replace( /\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"" ) ;
-
-		html = html.replace( /\s*tab-stops:[^;"]*;?/gi, '' ) ;
-		html = html.replace( /\s*tab-stops:[^"]*/gi, '' ) ;
-
-		// Remove FONT face attributes.
-		if ( ignoreFont )
+		var result = {};
+		for( var tag in this )
 		{
-			html = html.replace( /\s*face="[^"]*"/gi, '' ) ;
-			html = html.replace( /\s*face=[^ >]*/gi, '' ) ;
-
-			html = html.replace( /\s*FONT-FAMILY:[^;"]*;?/gi, '' ) ;
+			if( tag.indexOf( '$' ) == -1 && this[ tag ][ tagName ] )
+				result[ tag ] = 1;
 		}
-
-		// Remove Class attributes
-		html = html.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3") ;
-
-		// Remove styles.
-		if ( removeStyles )
-			html = html.replace( /<(\w[^>]*) style="([^\"]*)"([^>]*)/gi, "<$1$3" ) ;
-
-		// Remove style, meta and link tags
-		html = html.replace( /<STYLE[^>]*>[\s\S]*?<\/STYLE[^>]*>/gi, '' ) ;
-		html = html.replace( /<(?:META|LINK)[^>]*>\s*/gi, '' ) ;
-
-		// Remove empty styles.
-		html =  html.replace( /\s*style="\s*"/gi, '' ) ;
-
-		html = html.replace( /<SPAN\s*[^>]*>\s*&nbsp;\s*<\/SPAN>/gi, '&nbsp;' ) ;
-
-		html = html.replace( /<SPAN\s*[^>]*><\/SPAN>/gi, '' ) ;
-
-		// Remove Lang attributes
-		html = html.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3") ;
-
-		html = html.replace( /<SPAN\s*>([\s\S]*?)<\/SPAN>/gi, '$1' ) ;
-
-		html = html.replace( /<FONT\s*>([\s\S]*?)<\/FONT>/gi, '$1' ) ;
-
-		// Remove XML elements and declarations
-		html = html.replace(/<\\?\?xml[^>]*>/gi, '' ) ;
-
-		// Remove w: tags with contents.
-		html = html.replace( /<w:[^>]*>[\s\S]*?<\/w:[^>]*>/gi, '' ) ;
-
-		// Remove Tags with XML namespace declarations: <o:p><\/o:p>
-		html = html.replace(/<\/?\w+:[^>]*>/gi, '' ) ;
-
-		html = html.replace( /<(U|I|STRIKE)>&nbsp;<\/\1>/g, '&nbsp;' ) ;
-
-		html = html.replace( /<H\d>\s*<\/H\d>/gi, '' ) ;
-
-		// Remove "display:none" tags.
-		html = html.replace( /<(\w+)[^>]*\sstyle="[^"]*DISPLAY\s?:\s?none[\s\S]*?<\/\1>/ig, '' ) ;
-
-		// Remove language tags
-		html = html.replace( /<(\w[^>]*) language=([^ |>]*)([^>]*)/gi, "<$1$3") ;
-
-		// Remove onmouseover and onmouseout events (from MS Word comments effect)
-		html = html.replace( /<(\w[^>]*) onmouseover="([^\"]*)"([^>]*)/gi, "<$1$3") ;
-		html = html.replace( /<(\w[^>]*) onmouseout="([^\"]*)"([^>]*)/gi, "<$1$3") ;
-
-		if ( editor.config.pasteFromWordKeepsStructure )
-		{
-			// The original <Hn> tag send from Word is something like this: <Hn style="margin-top:0px;margin-bottom:0px">
-			html = html.replace( /<H(\d)([^>]*)>/gi, '<h$1>' ) ;
-
-			// Word likes to insert extra <font> tags, when using MSIE. (Wierd).
-			html = html.replace( /<(H\d)><FONT[^>]*>([\s\S]*?)<\/FONT><\/\1>/gi, '<$1>$2<\/$1>' );
-			html = html.replace( /<(H\d)><EM>([\s\S]*?)<\/EM><\/\1>/gi, '<$1>$2<\/$1>' );
-		}
-		else
-		{
-			html = html.replace( /<H1([^>]*)>/gi, '<div$1><b><font size="6">' ) ;
-			html = html.replace( /<H2([^>]*)>/gi, '<div$1><b><font size="5">' ) ;
-			html = html.replace( /<H3([^>]*)>/gi, '<div$1><b><font size="4">' ) ;
-			html = html.replace( /<H4([^>]*)>/gi, '<div$1><b><font size="3">' ) ;
-			html = html.replace( /<H5([^>]*)>/gi, '<div$1><b><font size="2">' ) ;
-			html = html.replace( /<H6([^>]*)>/gi, '<div$1><b><font size="1">' ) ;
-
-			html = html.replace( /<\/H\d>/gi, '<\/font><\/b><\/div>' ) ;
-
-			// Transform <P> to <DIV>
-			var re = new RegExp( '(<P)([^>]*>[\\s\\S]*?)(<\/P>)', 'gi' ) ;	// Different because of a IE 5.0 error
-			html = html.replace( re, '<div$2<\/div>' ) ;
-
-			// Remove empty tags (three times, just to be sure).
-			// This also removes any empty anchor
-			html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
-			html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
-			html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
-		}
-
-		return html ;
-	}
-}
+		return result;
+	};
+
+} )();
+
 
 /**
