Index: CKEditor/branches/features/paste/_source/core/dtd.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/dtd.js	(revision 4747)
+++ CKEditor/branches/features/paste/_source/core/dtd.js	(revision 4762)
@@ -59,6 +59,5 @@
 		V = {html:1};
 
-	var block = {address:1,blockquote:1,center:1,dir:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,isindex:1,menu:1,noframes:1,ol:1,p:1,pre:1,table:1,ul:1},
-		nonEmptyInline = { abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1 };
+	var block = {address:1,blockquote:1,center:1,dir:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,isindex:1,menu:1,noframes:1,ol:1,p:1,pre:1,table:1,ul:1};
 
 	return /** @lends CKEDITOR.dtd */ {
@@ -75,11 +74,4 @@
 		 */
 		$block : block,
-
-		/**
-		 * List of non-empty inline elements, like "b" or "a".
-		 * @type Object
-		 * @example
-		 */
-		$nonEmptyInline : nonEmptyInline,
 
 		/**
Index: CKEditor/branches/features/paste/_source/core/htmlparser/filter.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/htmlparser/filter.js	(revision 4747)
+++ CKEditor/branches/features/paste/_source/core/htmlparser/filter.js	(revision 4762)
@@ -46,4 +46,7 @@
 				// Add the comment.
 				this._.comment = transformNamedItem( this._.comment, rules.comment, priority ) || this._.comment;
+
+				// Add root fragment.
+				this._.root = transformNamedItem( this._.root, rules.root, priority ) || this._.root;
 			},
 
@@ -68,4 +71,10 @@
 				var textFilter = this._.comment;
 				return textFilter ? textFilter.filter( commentText ) : commentText;
+			},
+
+			onFragment : function( element )
+			{
+				var rootFilter = this._.root;
+				return rootFilter ? rootFilter.filter( element ) : element;
 			},
 
Index: CKEditor/branches/features/paste/_source/core/htmlparser/fragment.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/htmlparser/fragment.js	(revision 4747)
+++ CKEditor/branches/features/paste/_source/core/htmlparser/fragment.js	(revision 4762)
@@ -450,6 +450,6 @@
 			};
 
-			if ( !filter.onElement( this ) )
-				return;
+			// Filtering the root fragment before anything else.
+			!this.name && filter && filter.onFragment( this );
 
 			this.writeChildrenHtml( writer, isChildrenFiltered ? null : filter );
Index: CKEditor/branches/features/paste/_source/plugins/clipboard/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/clipboard/plugin.js	(revision 4747)
+++ CKEditor/branches/features/paste/_source/plugins/clipboard/plugin.js	(revision 4762)
@@ -252,6 +252,4 @@
 						else if ( data[ 'text' ] )
 							editor.insertText( data[ 'text' ] );
-
-						editor.fire( 'saveSnapshot' ); // Save after inserted.
 
 					}, null, null, 1000 );
Index: CKEditor/branches/features/paste/_source/plugins/htmldataprocessor/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/htmldataprocessor/plugin.js	(revision 4747)
+++ CKEditor/branches/features/paste/_source/plugins/htmldataprocessor/plugin.js	(revision 4762)
@@ -84,32 +84,6 @@
 			// Event attributes (onXYZ) must not be directly set. They can become
 			// active in the editing area (IE|WebKit).
-			[ ( /^on/ ), '_cke_pa_on' ],
-			// Remove bogus attributes.
-			[ ( /^cke:.*/ ), '' ]
-		],
-		attributes :
-		{
-			// Remove empty style attribute.
-			'style' : function( value )
-			{
-				if( !value )
-					return false;
-			}
-		},
-		elements :
-		{
-			'span' : function( element )
-			{
-				var attrs = element.attributes;
-				for( var attr in attrs )
-				{
-					if( attrs.hasOwnProperty( attr ) )
-					{
-						return;
-					}
-				}
-				delete element.name;
-			}
-		}
+			[ ( /^on/ ), '_cke_pa_on' ]
+		]
 	};
 
Index: CKEditor/branches/features/paste/_source/plugins/pastefromword/filter/default.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/pastefromword/filter/default.js	(revision 4747)
+++ CKEditor/branches/features/paste/_source/plugins/pastefromword/filter/default.js	(revision 4762)
@@ -328,4 +328,77 @@
 
 				/**
+				 *  Try to collect all list items among the children and establish one
+				 *  or more HTML list structures for them.
+				 * @param element
+				 */
+				assembleList : function( element )
+				{
+					var children = element.children, child,
+							listItem,   // The current processing cke:li element.
+							listItemAttrs,
+							listType,   // Determine the root type of the list.
+							listItemIndent, // Indent level of current list item.
+							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++ )
+					{
+						child = children[ i ];
+
+						if ( 'cke:li' == child.name )
+						{
+							child.name = 'li';
+							listItem = child;
+							listItemAttrs = listItem.attributes;
+							listType = listItem.attributes[ 'cke:listtype' ];
+							// The indent attribute might not present.
+							listItemIndent = parseInt( listItemAttrs[ 'cke:indent' ] ) || 0;
+
+							// Ignore the 'list-style-type' attribute if it's matched with
+							// the list root element's default style type.
+							listItemAttrs.style && ( listItemAttrs.style =
+							        CKEDITOR.plugins.pastefromword.filters.stylesFilter(
+									[
+										[ 'list-style-type', listType == 'ol' ? 'decimal' : 'disc' ]
+									] )( listItemAttrs.style )
+									|| '' );
+
+							if ( !list )
+							{
+								parentList = list = new CKEDITOR.htmlParser.element( listType );
+								list.add( listItem );
+								children[ i ] = list;
+							}
+							else
+							{
+								if ( listItemIndent > indent )
+								{
+									parentList = list;
+									list = new CKEDITOR.htmlParser.element( listType );
+									list.add( listItem );
+									lastListItem.add( list );
+								}
+								else if ( listItemIndent < indent )
+								{
+									list = parentList;
+									parentList = list.parent ? list.parent.parent : list;
+									list.add( listItem );
+								}
+								else
+									list.add( listItem );
+
+								children.splice( i--, 1 );
+							}
+
+							lastListItem = listItem;
+							indent = listItemIndent;
+						}
+						else
+							list = null;
+					}
+				},
+			
+				/**
 				 * A simple filter which always rejecting.
 				 */
@@ -340,6 +413,7 @@
 				 *  newStyleValue/newStyleGenerator, newStyleName ] where only the first
 				 *  parameter is mandatory.
+				 * @param whitelist {Boolean} Whether the {@param styles} will be considered as a white-list.
 				 */
-				stylesFilter : function( styles )
+				stylesFilter : function( styles, whitelist )
 				{
 					return function( styleText, element )
@@ -374,4 +448,6 @@
 											{
 												name = newName || name;
+												whitelist && ( newValue = newValue || value );
+
 												if( typeof newValue == 'function' )
 													newValue = newValue( value, element );
@@ -382,5 +458,6 @@
 										}
 									 }
-									 rules.push( [ name, value ] );
+									 
+									 !whitelist && rules.push( [ name, value ] );
 
 								 });
@@ -467,4 +544,5 @@
 				createListBulletMarker = this.utils.createListBulletMarker,
 				flattenList = filters.flattenList,
+				assembleList = filters.assembleList,
 				isListBulletIndicator = this.utils.isListBulletIndicator,
 				containsNothingButSpaces = this.utils.isContainingOnlySpaces,
@@ -472,5 +550,6 @@
 				convertToPx = this.utils.convertToPx,
 				listDtdParents = this.utils.listDtdParents,
-				ignoreFontFace = config.pasteFromWordIgnoreFontFace;
+				removeFontStyles = config.pasteFromWordRemoveFontStyles !== false,
+				removeStyles = config.pasteFromWordRemoveStyles !== false;
 
 			return {
@@ -482,4 +561,10 @@
 				],
 
+				root : function( element )
+				{
+					element.filterChildren();
+					assembleList( element );
+				},
+				
 				elements :
 				{
@@ -518,11 +603,12 @@
 						}
 						// Remove inline elements which contain only empty spaces.
-						else if ( tagName in dtd.$nonEmptyInline )
+						else if ( tagName in dtd.$inline )
 						{
 							element.filterChildren();
-							if ( containsNothingButSpaces(element) )
+							if ( containsNothingButSpaces( element ) )
 								delete element.name;
 						}
-						// Remove ms-office namespaced element, with it's content preserved.
+						// Remove element with ms-office namespace,
+						// with it's content preserved, e.g. 'o:p'. 
 						else if ( tagName.indexOf( ':' ) != -1
 								 && tagName.indexOf( 'cke' ) == -1 )
@@ -543,71 +629,11 @@
 
 						// Assembling list items into a whole list.
-						if ( !tagName || tagName in listDtdParents )
+						if ( tagName in listDtdParents )
 						{
 							element.filterChildren();
-
-							var children = element.children, child,
-								listItem,   // The current processing cke:li element.
-								listItemAttrs,
-								listType,   // Determine the root type of the list.
-								listItemIndent, // Indent level of current list item.
-								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++ )
-							{
-								child = children[ i ];
-
-								if ( 'cke:li' == child.name )
-								{
-									child.name = 'li';
-									listItem = child;
-									listItemAttrs = listItem.attributes;
-									listType = listItem.attributes[ 'cke:listtype' ];
-									// The indent attribute might not present.
-									listItemIndent = parseInt( listItemAttrs[ 'cke:indent' ] ) || 0;
-
-									// Ignore the 'list-style-type' attribute if it's matched with
-									// the list root element's default style type.
-									listItemAttrs.style && ( listItemAttrs.style = stylesFilter(
-										[ [ 'list-style-type', listType == 'ol'? 'decimal' : 'disc' ] ] )( listItemAttrs.style )
-										|| '' );
-
-									if ( !list )
-									{
-										parentList = list = new CKEDITOR.htmlParser.element( listType );
-										list.add( listItem );
-										children[ i ] = list;
-									}
-									else
-									{
-										if ( listItemIndent > indent )
-										{
-											parentList = list;
-											list = new CKEDITOR.htmlParser.element( listType  );
-											list.add( listItem );
-											lastListItem.add( list );
-										}
-										else if ( listItemIndent < indent )
-										{
-											list = parentList;
-											parentList = list.parent ? list.parent.parent : list;
-											list.add( listItem );
-										}
-										else
-											list.add( listItem );
-
-										children.splice( i-- , 1 );
-									}
-
-									lastListItem = listItem;
-									indent = listItemIndent;
-								}
-								else
-									list = null;
-							}
+							assembleList( element );
 						}
 					},
+
 					// We'll drop any style sheet, but Firefox conclude
 					// certain styles in a single style element, which are
@@ -676,4 +702,5 @@
 						return false;
 					},
+
 					'p' : function( element )
 					{
@@ -760,4 +787,5 @@
 								delete attrs.size;
 							}
+
 							element.name = 'span';
 							element.addStyle( styleText );
@@ -810,10 +838,11 @@
 										// Drop 'inline-height' style which make lines overlapping.
 										[ 'line-height' ],
-										!ignoreFontFace ? [ /^font-family$/, null, styleMigrateFilter( config[ 'font_style' ], 'family' ) ] : null,
-										!ignoreFontFace ? [ /^font-size$/, null, styleMigrateFilter( config[ 'fontSize_style' ], 'size' ) ] : null,
-										[ /^color$/, null, styleMigrateFilter( config[ 'colorButton_foreStyle' ], 'color' ) ],
-										[ /^background-color$/, null, styleMigrateFilter( config[ 'colorButton_backStyle' ], 'color' ) ]
+										[ /^font-family$/, null, !removeFontStyles ? styleMigrateFilter( config[ 'font_style' ], 'family' ) : null ] ,
+										[ /^font-size$/, null, !removeFontStyles ? styleMigrateFilter( config[ 'fontSize_style' ], 'size' ) : null ] ,
+										[ /^color$/, null, !removeFontStyles ? styleMigrateFilter( config[ 'colorButton_foreStyle' ], 'color' ) : null ] ,
+										[ /^background-color$/, null, !removeFontStyles ? styleMigrateFilter( config[ 'colorButton_backStyle' ], 'color' ) : null ]
 									] )( styleText, element ) || '';
 						}
+
 					},
 
@@ -853,4 +882,23 @@
 				{
 					'style' : stylesFilter(
+					removeStyles ?
+					// Provide a white-list of styles that we preserve, those should
+					// be the ones that could later be altered with editor tools.
+					[
+						[ /^border.*|margin.*|vertical-align|float$/ , null,
+							function( value, element )
+							{
+								if( element.name == 'img' )
+									return value;
+							} ],
+
+						[ /^width|height$/, null,
+							function( value, element )
+							{
+								if( element.name in { table : 1, td : 1, th : 1, img : 1 } )
+									return value;
+							} ]
+					] :
+					// Otherwise provide a black-list of styles that we remove.
 					[
 						[ /^mso-/ ],
@@ -869,6 +917,7 @@
 						[ 'tab-stops' ],
 						[ 'display', 'none' ],
-						ignoreFontFace ? [ /font-?/ ] : null,
-					] ),
+						removeFontStyles ? [ /font-?/ ] : null,
+					], removeStyles ),
+
 					// Prefer width styles over 'width' attributes.
 					'width' : function( value, element )
@@ -896,5 +945,5 @@
 
 					// Deprecate 'valign' attribute in favor of 'vertical-align'.
-					'valign' : function( value, element )
+					'valign' : removeStyles ? falsyFilter : function( value, element )
 					{
 						element.addStyle( 'vertical-align', value );
@@ -935,10 +984,10 @@
 
 	// The paste processor here is just a reduced copy of html data processor.
-	CKEDITOR.pasteProcessor = function()
+	var pasteProcessor = function()
 	{
 		this.dataFilter = new CKEDITOR.htmlParser.filter();
 	};
 
-	CKEDITOR.pasteProcessor.prototype =
+	pasteProcessor.prototype =
 	{
 		toHtml : function( data )
@@ -960,21 +1009,40 @@
 			data = data.replace( /(<!--\[if[^<]*?\])-->([\S\s]*?)<!--(\[endif\]-->)/gi, '$1$2$3' );
 
-		var pasteProcessor = new CKEDITOR.pasteProcessor(),
-			dataFilter = pasteProcessor.dataFilter;
+		var dataProcessor = new pasteProcessor(),
+			dataFilter = dataProcessor.dataFilter;
 
 		// These rules will have higher priorities than default ones.
 		dataFilter.addRules( CKEDITOR.plugins.pastefromword.getRules( editor ) );
+
+		// Allow extending data filter rules. 
 		editor.fire( 'beforeCleanWord', { filter : dataFilter } );
-		return pasteProcessor.toHtml( data, false );
+
+		data = dataProcessor.toHtml( data, false );
+
+		/* Below post processing those things that are unable to delivered by filter rules. */
+
+		// Remove 'cke' namespaced attribute used in filter rules as marker.
+		data = data.replace( /cke:.*?".*?"/g, '' );
+
+		// Remove empty style attribute.
+		data = data.replace( /style=""/g, '' );
+
+		// Remove the dummy spans ( having no inline style ).
+		data = data.replace( /<span>/g, '' );
+
+		return data;
 	};
 })();
 
 /**
- * Whether the ignore all font-related format from MS-Word.
- * @name CKEDITOR.config.pasteFromWordIgnoreFontFace
+ * Whether the ignore all font-related format styles, including:
+ * - font size;
+ * - font family;
+ * - font fore/background color;
+ * @name CKEDITOR.config.pasteFromWordRemoveFontStyles
  * @type Boolean
  * @default true
  * @example
- * config.pasteFromWordIgnoreFontFace = false;
+ * config.pasteFromWordRemoveFontStyles = false;
  */
 
@@ -987,2 +1055,13 @@
  * config.pasteFromWordNumberedHeadingToList = true;
  */
+
+/**
+ * Whether remove element styles that can't be managed with editor, note that this
+ * this doesn't handle the font-specific styles, which depends on
+ * how {@link CKEDITOR.config.pasteFromWordRemoveFontStyles} is configured. 
+ * @name CKEDITOR.config.pasteFromWordRemoveStyles
+ * @type Boolean
+ * @default true
+ * @example
+ * config.pasteFromWordRemoveStyles = false;
+ */
Index: CKEditor/branches/features/paste/_source/plugins/pastetext/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/pastetext/plugin.js	(revision 4747)
+++ CKEditor/branches/features/paste/_source/plugins/pastetext/plugin.js	(revision 4762)
@@ -125,4 +125,6 @@
 	CKEDITOR.editor.prototype.insertText = function( text )
 	{
+		this.fire( 'saveSnapshot' );
+
 		var mode = this.getSelection().getStartElement().hasAscendant( 'pre', true ) ? CKEDITOR.ENTER_BR : this.config.enterMode,
 			isEnterBrMode = mode == CKEDITOR.ENTER_BR,
@@ -154,4 +156,6 @@
 		line = text.substring( startIndex, text.length );
 		line.length && doInsertText( doc, line );
+
+		this.fire( 'saveSnapshot' );
 	};
 })();
