Index: CKEditor/branches/features/pasting/_source/core/dtd.js
===================================================================
--- CKEditor/branches/features/pasting/_source/core/dtd.js	(revision 4277)
+++ CKEditor/branches/features/pasting/_source/core/dtd.js	(revision 4280)
@@ -54,5 +54,6 @@
 		Q = {li: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};
+	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 };
 
     return /** @lends CKEDITOR.dtd */ {
@@ -66,4 +67,11 @@
 		 */
 		$block : block,
+
+	    /**
+	     * List of non-empty inline elements, like "b" or "a".
+	     * @type Object
+	     * @example
+	     */
+	    $nonEmptyInline : nonEmptyInline,
 
 		$body : X({script:1}, block),
Index: CKEditor/branches/features/pasting/_source/plugins/htmldataprocessor/plugin.js
===================================================================
--- CKEditor/branches/features/pasting/_source/plugins/htmldataprocessor/plugin.js	(revision 4277)
+++ CKEditor/branches/features/pasting/_source/plugins/htmldataprocessor/plugin.js	(revision 4280)
@@ -78,5 +78,7 @@
 			// Event attributes (onXYZ) must not be directly set. They can become
 			// active in the editing area (IE|WebKit).
-			[ ( /^on/ ), '_cke_pa_on' ]
+			[ ( /^on/ ), '_cke_pa_on' ],
+			// Bogus attributes.  
+			[ /^cke:/, '' ]
 		],
 		elements :
Index: CKEditor/branches/features/pasting/_source/plugins/pastefromword/plugin.js
===================================================================
--- CKEditor/branches/features/pasting/_source/plugins/pastefromword/plugin.js	(revision 4277)
+++ CKEditor/branches/features/pasting/_source/plugins/pastefromword/plugin.js	(revision 4280)
@@ -50,4 +50,9 @@
 	CKEDITOR.plugins.pastefromword =
 	{
+		_ :
+		{
+			cachedRules : null
+		},
+
 		utils :
 		{
@@ -106,4 +111,11 @@
 				if( /mso-list:\s*Ignore/i.test( styleText ) )
 					return true;
+			},
+
+			isContainingOnlySpaces : function( element )
+			{
+				var text;
+				return ( ( text = element.onlyChild() )
+					    && /^(:?\s|&nbsp;)+$/.exec( text.value ) );
 			},
 
@@ -142,5 +154,6 @@
 		},
 
-		filters : {
+		filters :
+		{
 				/**
 				 * A simple filter which always rejecting.
@@ -258,5 +271,11 @@
 					if( element.name.indexOf( 'cke:' ) == -1 )
 						return false;
-				}
+				},
+
+				/**
+				 * A filter which will be used to apply inline css style according the stylesheet
+				 * definition rules, is generated lazily when filtering.  
+				 */
+				applyStyleFilter : null
 
 			},
@@ -264,5 +283,11 @@
 		getRules : function( editor )
 		{
-			var filters = this.filters,
+			var cached;
+			if( cached = this._.cachedRules )
+				return cached;
+
+			var dtd = CKEDITOR.dtd,
+				listDtdParents = dtd.parentOf( 'ol' ),
+				filters = this.filters,
 				falsyFilter = filters.falsyFilter,
 				stylesFilter = filters.stylesFilter,
@@ -272,6 +297,6 @@
 				createListBulletMarker = this.utils.createListBulletMarker,
 				isListBulletIndicator = this.utils.isListBulletIndicator,
-				resolveList = this.utils.resolveList,
-				listDtdParents = CKEDITOR.dtd.parentOf( 'ol' ),
+				containsNothingButSpaces = this.utils.isContainingOnlySpaces,
+				resolveListItem = this.utils.resolveList,
 				config = editor.config,
 				ignoreFontFace = config.pasteFromWordIgnoreFontFace;
@@ -291,30 +316,35 @@
 						var tagName = element.name || '';
 
-						// Resolve inline css style for Firefox.
+						// Firefox: adding inline style. 
 						var applyStyleFilter;
 						if( CKEDITOR.env.gecko && ( applyStyleFilter = filters.applyStyleFilter ) )
 							applyStyleFilter( element );
 
-
+						// IE leave empty spaces at the beginning of body. 
+						if ( !tagName )
+						{
+							var textNode = element.firstTextChild();
+							if ( textNode && textNode.value.match( /^(:?\s|&nbsp;)+$/ ) )
+								element.children.splice( 0, 1 );
+						}
 						// Processing headings.
-						if ( tagName.match( /h\d/ ) )
+						else if ( tagName.match( /h\d/ ) )
 						{
 							element.filterChildren();
-							// Heading might be a list.
-							if( resolveList( element ) )
+							// Is the heading actually a list item?
+							if( resolveListItem( element ) )
 								return;
 
-							// Migrate heading formatting to editor configured ones.
+							// Adapt heading styles to editor's convention.
 							elementMigrateFilter( config[ 'format_' + tagName ] )( element );
 						}
 						// Remove inline elements which contain only empty spaces.
-						else if( tagName.match( /^(:?b|u|i|strike|span)$/ ) )
+						else if( tagName in dtd.$nonEmptyInline )
 						{
 							element.filterChildren();
-							var child = element.onlyChild();
-							if ( child && /^(:?\s|&nbsp;)+$/.exec( child.value ) )
+							if( containsNothingButSpaces( element ) )
 								delete element.name;
 						}
-						// Remove ms-office namespaced element while preserving the content.
+						// Remove ms-office namespaced element, with it's content preserved.
 						else if( tagName.indexOf( ':' ) != -1
 								 && tagName.indexOf( 'cke' ) == -1 )
@@ -322,5 +352,5 @@
 							element.filterChildren();
 
-							// Restore img element from vml.
+							// Restore image real link from vml.
 							if( tagName == 'v:imagedata' )
 							{
@@ -329,23 +359,11 @@
 									element.attributes.src = href;
 								element.name = 'img';
+								return;
 							}
-							else
-								delete element.name;
-						}
-						else if ( !tagName )
-						{
-							// Trim empty spaces at the beginning of document for IE. 
-							if( CKEDITOR.env.ie )
-							{
-								var firstTextChild = element.firstTextChild();
-								if ( firstTextChild
-									 && firstTextChild.value.match( /^(:?\s|&nbsp;)+$/ ) )
-									element.children.splice( 0, 1 );
-							}
-						}
-
-						// Any dtd-valid element which could contain a list.
-						if( !tagName && element.children
-								 || tagName in listDtdParents )
+							delete element.name;
+						}
+
+						// Assembling list items into a whole list.
+						if( !tagName || tagName in listDtdParents )
 						{
 							element.filterChildren();
@@ -411,12 +429,8 @@
 									list = null;
 							}
-
-							// Filter childrens again for cleaning up
-							// the list attributes.
-							element.filterChildren();
 						}
 					},
-					// We would like drop any style sheet, but Firefox conclude
-					// certain styles in it, so we're required to change them into
+					// We'll drop any style sheet, but Firefox conclude
+					// certain styles in it, so they're required to be changed into
 					// inline ones.
 					'style' : function( element )
@@ -424,26 +438,29 @@
 						if( CKEDITOR.env.gecko && !filters.applyStyleFilter )
 						{
+							// Grab only the style definition section.
 							var styleDefSection = element.onlyChild().value.match( /\/\* Style Definitions \*\/([\s\S]*?)\/\*/ ),
 								styleDefText = styleDefSection && styleDefSection[ 1 ],
-								rules = {};
+								rules = {}; // Storing the parsed result.   
 
 							if( styleDefText )
 							{
 								styleDefText.replace(/[\n\r]/g,'') // remove line-breaks.
-											// Extract selectors and rules.
-											.replace( /(.+?)\s*\{(.+?)\}/g,
+											// Extract selectors and style properties.
+											.replace( /(.+?)\{(.+?)\}/g,
 								function( rule, selectors, styleBlock )
 								{
 									selectors = selectors.split( ',' );
-									var length = selectors.length,
-										selector;
+									var length = selectors.length, selector;
 									for ( var i = 0; i < length; i++ )
 									{
+										// Assume MS-Word mostly generate only simple
+										// selector( [Type selector][Class selector]).
 										CKEDITOR.tools.trim( selectors[ i ] )
-													  .replace( /^(\w+?)(\.[\w-]+)?$/g,
+													  .replace( /^(\w+)(\.[\w-]+)?$/g,
 										function( match, tagName, className )
 										{
 											tagName = tagName || '*';
 											className = className.substring( 1, className.length );
+
 											if( !rules[ tagName ] )
 												rules[ tagName ] = {};
@@ -479,26 +496,26 @@
 						var attrs = element.attributes,
 							parent = element.parent,
-							children = element.children,
-							firstChild = children && children[ 0 ];
+							children = element.children;
 
 						// Drop the single wrapper paragraph within table cell
-						// while preserve the styles.
+						// with all attributes preserved to cell.
 						if( /td|th/.test( parent.name )
 							&& parent.onlyChild() )
 						{
-							if( attrs && attrs.style )
-								parent.addStyle( attrs.style  );
-
+							CKEDITOR.tools.extend( parent.attributes, attrs );
+							attrs && parent.addStyle( attrs.style  );
 							delete element.name;
 							return;
 						}
 
-						// Paragraph might be a list.
-						if( resolveList( element ) )
+						// Is the paragraph actually a list item?
+						if( resolveListItem( element ) )
 							return;
 
-						// Migrate paragraph formatting based on editor's enter-mode.
+						// Adapt paragraph formatting to editor's convention
+						// according to enter-mode.
 						if( config.enterMode == CKEDITOR.ENTER_BR )
 						{
+							// We suffer from attribute/style lost in this situation.   
 							delete element.name;
 							element.add( new CKEDITOR.htmlParser.element( 'br' ) );
@@ -519,18 +536,21 @@
 
 						element.filterChildren();
-						// Merge nested <font> tags.
-						var parent = element.parent;
-						if( 'font' == parent.name )
+
+						var attrs = element.attributes,
+							parent = element.parent;
+						
+						if( 'font' == parent.name )     // Merge nested <font> tags.
 						{
 							CKEDITOR.tools.extend( parent.attributes,
 									element.attributes );
+							attrs && parent.addStyle( attrs.style );
 							delete element.name;
 							return;
 						}
-						// Convert the topmost into a span with font-styles.
+						// Convert the merged into a span with all attributes preserved.
 						else
 						{
-							var attrs = element.attributes,
-								styleText = '';
+							var styleText = attrs.style || '';
+							// IE's having those deprecated attributes, normalize them.
 							if ( attrs.color )
 							{
@@ -552,8 +572,6 @@
 								delete attrs.size;
 							}
-
 							element.name = 'span';
 							element.addStyle( styleText );
-
 						}
 					},
@@ -574,10 +592,11 @@
 						// Update the src attribute of image element with href.
 						var children = element.children,
-							firstChild = children && children[ 0 ],
-							secondChild;
-						if( firstChild
-							&& 'cke:imagesource' == firstChild.name )
-						{
-							secondChild = children[ 1 ];
+							attrs = element.attributes,
+							styleText = attrs && attrs.style,
+							firstChild = children && children[ 0 ];
+
+						if( firstChild && firstChild.name == 'cke:imagesource' )
+						{
+							var secondChild = children[ 1 ];
 							if ( 'img' == secondChild.name )
 								secondChild.attributes.src = firstChild.attributes.src;
@@ -586,9 +605,8 @@
 						}
 
-						// Migrate font related styles.
-						var attrs = element.attributes,
-							styleText = attrs && attrs.style;
+						// Assume MS-Word mostly carry font related styles on <span>,
+						// adapting them to editor's convention.
 						if( styleText )
-						attrs.style = stylesFilter(
+							attrs.style = stylesFilter(
 									[
 										[ /^font-family$/, null, styleMigrateFilter( config[ 'font_style' ], 'family' ) ],
@@ -606,13 +624,6 @@
 					'sup' : elementMigrateFilter( config[ 'coreStyles_superscript' ] ),
 					'sub' : elementMigrateFilter( config[ 'coreStyles_subscript' ] ),
-					'v:imagedata' : function( element )
-					{
-						var href = element.attributes['o:href'];
-						if( href )
-							element.attributes.src = href;
-						element.name = 'img';
-					},
-					// Editor doesn't support anchor with content currently(#3582),
-					// drop such anchors.
+					// Editor doesn't support anchor with content currently (#3582),
+					// drop such anchors with content preserved.
 					'a' : function( element )
 					{
@@ -636,8 +647,4 @@
 				attributes :
 				{
-					'cke:listtype' : bogusAttrFilter,
-					'cke:indent' : bogusAttrFilter,
-					// Remove mso-xxx styles.
-					// Remove margin styles.
 					'style' : stylesFilter(
 					[
@@ -675,16 +682,18 @@
 						ignoreFontFace ? [ /font-?/ ] : null,
 					] ),
+					// Prefer width styles over 'width' attributes.
 					'width' : function( value, element )
 					{
-						// Prefer width style over attribute on table cell.
-						if( element.name in { td : 1, th : 1 } )
+						if( element.name in dtd.$tableContent )
 							return false;
 					},
-					
-					'class' : function( value )
-					{
-						if( value.match( /^(:?Mso|Spell|ListParagraph)/i ) )
+					// Prefer border styles over table 'border' attributes.
+					'border' : function( value, element )
+					{
+						if( element.name in dtd.$tableContent )
 							return false;
 					},
+
+					'class' : falsyFilter,
 
 					// MS-Word always generate both 'text-align' along with
@@ -693,19 +702,13 @@
 					'align' : falsyFilter,
 					'bgcolor' : falsyFilter,
+
 					// Deprecate 'valign' attribute in favor of 'vertical-align'.
 					'valign' : function( value, element )
 					{
-						// TODO: The style chang doesn't work now because of filtering system. 
 						if( value != 'top' )
 							element.addStyle( 'vertical-align', value );
 						return false;
-					},
-
-					// Avoid table 'border' attribute in favor of cell border styles.
-					'border' : function( value, element )
-					{
-						if( element.name == 'table' )
-							return false;
 					}
+
 				},
 
@@ -726,9 +729,8 @@
 						return new CKEDITOR.htmlParser.element( 'cke:imagesource', { src : imageSource[ 1 ] } );
 					// Seek for list bullet style indicator.
-					else if ( listInfo )
+					if ( listInfo )
 					{
 						var listSymbol = listInfo[ 1 ],
 							listType = listSymbol.match( />([^\s])([.)]?)</ );
-
 						return createListBulletMarker( listType );
 					}
@@ -737,5 +739,5 @@
 			};
 		}
-	}
+	};
 
 	var fragmentPrototype = CKEDITOR.htmlParser.fragment.prototype,
@@ -765,4 +767,15 @@
 		}
 		return childs;
+	};
+
+	fragmentPrototype.firstTextChild = elementPrototype.firstTextChild = function()
+	{
+		var child;
+		for( var i = 0 ; i < this.children.length ; i++ )
+		{
+			child = this.children[ i ];
+			if( child.value )
+				return child;
+		}
 	};
 
@@ -798,15 +811,4 @@
 	}
 
-	fragmentPrototype.firstTextChild = elementPrototype.firstTextChild = function()
-	{
-		var child;
-		for( var i = 0 ; i < this.children.length ; i++ )
-		{
-			child = this.children[ i ];
-			if( child.value )
-				return child;
-		}
-	};
-
 	/**
 	 * Return the DTD-valid parent tag names of the specified one.
