Index: CKEditor/branches/features/paste/_source/core/dtd.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/dtd.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/core/dtd.js	(revision 4674)
@@ -59,5 +59,6 @@
 		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};
+	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 */ {
@@ -74,4 +75,12 @@
 		 */
 		$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/comment.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/htmlparser/comment.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/core/htmlparser/comment.js	(revision 4674)
@@ -1,3 +1,3 @@
-﻿/*
+/*
 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
@@ -50,4 +50,5 @@
 			if ( typeof comment != 'string' )
 			{
+				comment.parent = this.parent;
 				comment.writeHtml( writer, filter );
 				return;
Index: CKEditor/branches/features/paste/_source/core/htmlparser/element.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/htmlparser/element.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/core/htmlparser/element.js	(revision 4674)
@@ -1,3 +1,3 @@
-﻿/*
+/*
 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
@@ -102,16 +102,25 @@
 			var attributes = this.attributes;
 
-			// The "_cke_replacedata" indicates that this element is replacing
-			// a data snippet, which should be outputted as is.
-			if ( attributes._cke_replacedata )
-			{
-				writer.write( attributes._cke_replacedata );
-				return;
-			}
-
 			// Ignore cke: prefixes when writing HTML.
 			var element = this,
 				writeName = element.name,
-				a, value;
+				a, newAttrName, value;
+
+			var isChildrenFiltered;
+
+			/**
+			 * Providing an option for bottom-up filtering order ( element
+			 * children to be pre-filtered before the element itself ).
+			 */
+			element.filterChildren = function()
+			{
+				if( !isChildrenFiltered )
+				{
+					var writer = new CKEDITOR.htmlParser.basicWriter();
+					CKEDITOR.htmlParser.fragment.prototype.writeChildrenHtml.call( element, writer, filter );
+					element.children = new CKEDITOR.htmlParser.fragment.fromHtml( writer.getHtml() ).children;
+					isChildrenFiltered = 1;
+				}
+			};
 
 			if ( filter )
@@ -126,4 +135,6 @@
 					if ( !( element = filter.onElement( element ) ) )
 						return;
+
+					element.parent = this.parent;
 
 					if ( element.name == writeName )
@@ -139,7 +150,10 @@
 
 					writeName = element.name;
-					if ( !writeName )	// Send children.
+
+					// This indicate that the element has been dropped by
+					// filter but not the children.
+					if ( !writeName )
 					{
-						CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments );
+						this.writeChildrenHtml.call( element, writer, isChildrenFiltered ? null : filter );
 						return;
 					}
@@ -154,39 +168,53 @@
 			writer.openTag( writeName, attributes );
 
-			if ( writer.sortAttributes )
-			{
-				// Copy all attributes to an array.
-				var attribsArray = [];
+			// Copy all attributes to an array.
+			var attribsArray = [];
+			// Iterate over the attributes twice since filters may alter
+			// other attributes.
+			for( var i = 0 ; i < 2; i++ )
+			{
 				for ( a in attributes )
 				{
+					newAttrName = a;
 					value = attributes[ a ];
-
-					if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) )
-						continue;
-
-					attribsArray.push( [ a, value ] );
+					if( i == 1 )
+						attribsArray.push( [ a, value ] );
+					else if ( filter )
+					{
+						while ( true )
+						{
+							if ( !( newAttrName = filter.onAttributeName( a ) ) )
+							{
+								delete attributes[ a ];
+								break;
+							}
+							else if( newAttrName != a )
+							{
+								delete attributes[ a ];
+								a = newAttrName; 
+								continue;
+							}
+							else
+								break;
+						}
+						if( newAttrName )
+						{
+							if( ( value = filter.onAttribute( element, newAttrName, value ) ) === false )
+								delete attributes[ newAttrName ];
+							else
+								attributes [ newAttrName ] = value;
+						}
+					}
 				}
-
-				// Sort the attributes by name.
+			}
+			// Sort the attributes by name.
+			if ( writer.sortAttributes )
 				attribsArray.sort( sortAttribs );
 
-				// Send the attributes.
-				for ( var i = 0, len = attribsArray.length ; i < len ; i++ )
-				{
-					var attrib = attribsArray[ i ];
-					writer.attribute( attrib[0], attrib[1] );
-				}
-			}
-			else
-			{
-				for ( a in attributes )
-				{
-					value = attributes[ a ];
-
-					if ( filter && ( !( a = filter.onAttributeName( a ) ) || ( value = filter.onAttribute( element, a, value ) ) === false ) )
-						continue;
-
-					writer.attribute( a, value );
-				}
+			// Send the attributes.
+			for ( i = 0, len = attribsArray.length ; i < len ; i++ )
+			{
+				var attrib = attribsArray[ i ];
+				writer.attribute( attrib[0], attrib[1] );
 			}
 
@@ -196,10 +224,15 @@
 			if ( !element.isEmpty )
 			{
-				// Send children.
-				CKEDITOR.htmlParser.fragment.prototype.writeHtml.apply( element, arguments );
-
+				this.writeChildrenHtml.call( element, writer, isChildrenFiltered ? null : filter );
 				// Close the element.
 				writer.closeTag( writeName );
 			}
+		},
+
+		writeChildrenHtml : function( writer, filter )
+		{
+			// Send children.
+			CKEDITOR.htmlParser.fragment.prototype.writeChildrenHtml.apply( this, arguments );
+
 		}
 	};
Index: CKEditor/branches/features/paste/_source/core/htmlparser/filter.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/htmlparser/filter.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/core/htmlparser/filter.js	(revision 4674)
@@ -1,2 +1,4 @@
+
+
 /*
 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
@@ -75,8 +77,8 @@
 				// well as those set to the generic $ name. So, add both to an
 				// array and process them in a small loop.
-				var filters = [ this._.elements[ element.name ], this._.elements.$ ],
+				var filters = [ this._.elements[ '^' ], this._.elements[ element.name ], this._.elements.$ ],
 					filter, ret;
 
-				for ( var i = 0 ; i < 2 ; i++ )
+				for ( var i = 0 ; i < 3 ; i++ )
 				{
 					filter = filters[ i ];
@@ -90,4 +92,8 @@
 						if ( ret && ret != element )
 							return this.onNode( ret );
+
+						// The none-root element has been dismissed by one of the filters.
+						if( element.parent && !element.name )
+							break;
 					}
 				}
@@ -122,4 +128,12 @@
 
 				return value;
+			},
+
+			clone : function()
+			{
+				var clone = new CKEDITOR.htmlParser.filter();
+				// Shallow copy all the rules.
+				clone._ = CKEDITOR.tools.clone( this._ );
+				return clone;
 			}
 		}
@@ -155,6 +169,9 @@
 			{
 				var item = items[ j ];
-				item.pri = priority;
-				list.splice( i, 0, item );
+				if( item )
+				{
+					item.pri = priority;
+					list.splice( i, 0, item );
+				}
 			}
 		}
Index: CKEditor/branches/features/paste/_source/core/htmlparser/fragment.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/htmlparser/fragment.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/core/htmlparser/fragment.js	(revision 4674)
@@ -357,4 +357,5 @@
 		parser.onComment = function( comment )
 		{
+			checkPending();
 			currentNode.add( new CKEDITOR.htmlParser.comment( comment ) );
 		};
@@ -438,9 +439,28 @@
 		 * alert( writer.getHtml() );  "&lt;p&gt;&lt;b&gt;Example&lt;/b&gt;&lt;/p&gt;"
 		 */
-		writeHtml : function( writer, filter )
-		{
-			for ( var i = 0, len = this.children.length ; i < len ; i++ )
+		writeHtml : function( writer, filter, skipSelf )
+		{
+			var isChildrenFiltered;
+			this.filterChildren = function()
+			{
+				var writer = new CKEDITOR.htmlParser.basicWriter();
+				this.writeChildrenHtml.call( this, writer, filter, true );
+				var html = writer.getHtml();
+				this.children = new CKEDITOR.htmlParser.fragment.fromHtml( html ).children;
+				isChildrenFiltered = 1;
+			};
+
+			if ( !filter.onElement( this ) )
+				return;
+
+			this.writeChildrenHtml( writer, isChildrenFiltered ? null : filter );
+		},
+
+		writeChildrenHtml : function( writer, filter )
+		{
+			for ( var i = 0 ; i < this.children.length ; i++ )
 				this.children[i].writeHtml( writer, filter );
 		}
+
 	};
 })();
Index: CKEditor/branches/features/paste/_source/core/scriptloader.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/scriptloader.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/core/scriptloader.js	(revision 4674)
@@ -1,3 +1,3 @@
-﻿/*
+/*
 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
@@ -52,5 +52,5 @@
 		 *     });
 		 */
-		load : function( scriptUrl, callback, scope, noCheck )
+		load : function( scriptUrl, callback, scope, noCheck, showBusy )
 		{
 			var isString = ( typeof scriptUrl == 'string' );
@@ -88,5 +88,8 @@
 
 				if ( --scriptCount <= 0 )
+				{
+					showBusy && CKEDITOR.document.getDocumentElement().removeStyle( 'cursor' );
 					doCallback( success );
+				}
 			};
 
@@ -168,4 +171,5 @@
 			};
 
+			showBusy && CKEDITOR.document.getDocumentElement().setStyle( 'cursor', 'wait' );
 			for ( var i = 0 ; i < scriptCount ; i++ )
 			{
Index: CKEditor/branches/features/paste/_source/core/tools.js
===================================================================
--- CKEditor/branches/features/paste/_source/core/tools.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/core/tools.js	(revision 4674)
@@ -1,3 +1,3 @@
-﻿/*
+/*
 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
@@ -64,15 +64,4 @@
 			var clone;
 
-			// Array.
-			if ( obj && ( obj instanceof Array ) )
-			{
-				clone = [];
-
-				for ( var i = 0 ; i < obj.length ; i++ )
-					clone[ i ] = this.clone( obj[ i ] );
-
-				return clone;
-			}
-
 			// "Static" types.
 			if ( obj === null
@@ -81,5 +70,6 @@
 				|| ( obj instanceof Number )
 				|| ( obj instanceof Boolean )
-				|| ( obj instanceof Date ) )
+				|| ( obj instanceof Date )
+				|| ( obj instanceof RegExp) )
 			{
 				return obj;
@@ -586,5 +576,20 @@
 		{
 			return new Array( times + 1 ).join( str );
-		}
+		},
+
+		tryThese : function()
+		{
+		    var returnValue;
+		    for ( var i = 0, length = arguments.length; i < length; i++ )
+		    {
+		      var lambda = arguments[i];
+		      try
+		      {
+		        returnValue = lambda();
+		        break;
+		      } catch (e) { }
+		    }
+		    return returnValue;
+		 }
 	};
 })();
Index: CKEditor/branches/features/paste/_source/lang/en.js
===================================================================
--- CKEditor/branches/features/paste/_source/lang/en.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/lang/en.js	(revision 4674)
@@ -514,9 +514,7 @@
 	pastefromword :
 	{
+		confirmCleanup : 'Your pasted content including formattings from MS-Word application, do you want to adapt it to the editor\'s format?',
 		toolbar : 'Paste from Word',
-		title : 'Paste from Word',
-		advice : 'Please paste inside the following box using the keyboard (<strong>Ctrl+V</strong>) and hit <strong>OK</strong>.',
-		ignoreFontFace : 'Ignore Font Face definitions',
-		removeStyle : 'Remove Styles definitions'
+		title : 'Paste from Word'
 	},
 
Index: CKEditor/branches/features/paste/_source/plugins/clipboard/dialogs/paste.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/clipboard/dialogs/paste.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/clipboard/dialogs/paste.js	(revision 4674)
@@ -119,5 +119,5 @@
 
 			setTimeout( function(){
-				editor.insertHtml( html );
+				editor.fire( 'paste', { 'html' : html } );
 			}, 0 );
 
Index: CKEditor/branches/features/paste/_source/plugins/clipboard/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/clipboard/plugin.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/clipboard/plugin.js	(revision 4674)
@@ -86,8 +86,8 @@
 					editor.focus();
 
-					if ( !editor.fire( 'beforePaste' )
-						&& !execIECommand( editor, 'paste' ) )
-					{
-							editor.openDialog( 'paste' );
+					if ( !execIECommand( editor, 'paste' ) )
+					{
+						editor.fire( 'pasteDialog' );
+						return false;
 					}
 				}
@@ -99,5 +99,5 @@
 					try
 					{
-						if ( !editor.fire( 'beforePaste' )
+						if ( !editor.document.getBody().fire( 'beforepaste' )
 							&& !editor.document.$.execCommand( 'Paste', false, null ) )
 						{
@@ -107,6 +107,9 @@
 					catch ( e )
 					{
-						// Open the paste dialog.
-						editor.openDialog( 'paste' );
+						setTimeout( function()
+						{
+							editor.fire( 'pasteDialog' );
+						}, 0 );
+						return false;
 					}
 				}
@@ -122,14 +125,16 @@
 			case CKEDITOR.SHIFT + 45 :		// SHIFT+INS
 
-				var editor = this;
+				var editor = this,
+					body = editor.document.getBody();
+
 				editor.fire( 'saveSnapshot' );		// Save before paste
 
-				if ( editor.fire( 'beforePaste' ) )
+				// Simulate 'beforepaste' event for all none-IEs.
+				if ( !CKEDITOR.env.ie && body.fire( 'beforepaste' ) )
 					event.cancel();
-
-				setTimeout( function()
-					{
-						editor.fire( 'saveSnapshot' );		// Save after paste
-					}, 0 );
+				// Simulate 'paste' event for Opera/Firefox2.
+				else if( CKEDITOR.env.opera
+						 || CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 )
+					body.fire( 'paste' );
 				return;
 
@@ -148,9 +153,138 @@
 	};
 
+	// Allow to peek clipboard content by redirecting the
+	// pasting content into a temporary bin and grab the content of it.
+	function getClipboardData( evt, mode, callback ) {
+
+		var doc = this.document;
+
+		// Avoid recursions on 'paste' event for IE.
+		if( CKEDITOR.env.ie && doc.getById( 'cke_pastebin' ) )
+			return;
+
+		var sel = this.getSelection(),
+			range = new CKEDITOR.dom.range( doc );
+
+		// Create container to paste into
+		var pastebin = new CKEDITOR.dom.element( mode == 'text' ? 'textarea' : 'div', doc );
+		pastebin.setAttribute( 'id', 'cke_pastebin' );
+
+		// IE6/7 require the bin to at least contain one piece of text otherwise the
+		// paste is treated as unauthorized.
+		if( mode != 'text' && CKEDITOR.env.ie )
+			pastebin.append( new CKEDITOR.dom.text( '\u00A0', doc ) );
+
+		doc.getBody().append( pastebin );
+
+
+		// It's definitely a better user experience if we make the paste-bin pretty unnoticed
+		// by pulling it off the screen, while this hack will make the paste-bin a control type element
+		// and that become a selection plain later. 
+		if( !CKEDITOR.env.ie )
+		{
+			pastebin.setStyles( {
+				position : 'absolute',
+				left : '-1000px',
+				// Position the bin exactly at the position of the selected element
+				// to avoid any subsequent document scroll.
+				top : sel.getStartElement().getDocumentPosition().y + 'px',
+				width : '1px',
+				height : '1px',
+				overflow : 'hidden'
+			} );
+		}
+
+		var bms = sel.createBookmarks();
+
+		// Turn off design mode temporarily before give focus to the paste bin.
+		if ( mode == 'text' )
+		{
+			doc.$.designMode = 'off';
+			pastebin.$.focus();
+		}
+		else
+		{
+			range.setStartAt( pastebin, CKEDITOR.POSITION_AFTER_START );
+			range.setEndAt( pastebin, CKEDITOR.POSITION_BEFORE_END );
+			range.select( true );
+		}
+
+		// Wait a while and grab the pasted contents
+		window.setTimeout( function() {
+
+			mode == 'text' && ( doc.$.designMode = 'on' );
+			pastebin.remove();
+
+			// Grab the HTML contents
+			// We need to look for a apple style wrapper on webkit it also adds a div wrapper if you copy/paste the body of the editor.
+			// Remove hidden div and restore selection
+			var bogusSpan;
+			pastebin = ( CKEDITOR.env.webkit
+					 && ( bogusSpan = pastebin.getFirst() )
+					 && ( bogusSpan.is && bogusSpan.hasClass( 'Apple-style-span' ) ) ?
+					  bogusSpan : pastebin );
+
+			sel.selectBookmarks( bms );
+			callback( pastebin[ 'get' + ( mode == 'text' ? 'Value' : 'Html' ) ]() );
+
+		}, 0 );
+	};
+
+
 	// Register the plugin.
 	CKEDITOR.plugins.add( 'clipboard',
 		{
+			requires : [ 'htmldataprocessor' ],
 			init : function( editor )
 			{
+				// The paste processor here is just a reduced copy of html data processor.
+				CKEDITOR.pasteProcessor = function( editor )
+				{
+					this.editor = editor;
+					this.dataFilter = new CKEDITOR.htmlParser.filter();
+				};
+				CKEDITOR.pasteProcessor.prototype =
+				{
+					toHtml : function( data )
+					{
+						var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data, false ),
+							writer = new CKEDITOR.htmlParser.basicWriter();
+
+						fragment.writeHtml( writer, this.dataFilter );
+						return writer.getHtml( true );
+					}
+				};
+
+				// The very first handler which initialize the processor.
+				editor.on( 'paste', function( evt )
+				{
+					// The processor is a transient instance life cycled to the
+					// 'paste' event since the processing rules will be added
+					// on demand accordingly to clipboard data flavor.
+					evt.data.processor = new CKEDITOR.pasteProcessor( editor );
+					
+				}, null, null, 1 );
+
+				// The very last handler which insert final data into the editor at the end of the chain.
+				editor.on( 'paste', function( evt )
+				{
+					var data = evt.data,
+						processor = data.processor;
+
+					if ( data[ 'html' ] )
+						editor.insertHtml( processor.toHtml( data[ 'html' ], false ) );
+					else if ( data[ 'text' ] )
+						editor.insertText( data[ 'text' ] );
+
+					editor.fire( 'saveSnapshot' ); // Save after inserted.
+
+				}, null, null, 1000 );
+
+				editor.on( 'pasteDialog', function( evt )
+				{
+					// Open default paste dialog. 
+					editor.openDialog( 'paste' );
+				} );
+
 				function addButtonCommand( buttonName, commandName, command, ctxMenuOrder )
 				{
@@ -185,4 +319,30 @@
 				editor.on( 'key', onKey, editor );
 
+				if( editor.config.autoDetectPaste )
+				{
+					var mode = editor.config.forcePasteAsPlainText ? 'text' : 'html';
+					editor.on( 'contentDom', function()
+					{
+						var body = editor.document.getBody();
+						body.on( ( mode == 'text' && !CKEDITOR.env.ie ) ?
+						          'beforepaste' : 'beforepaste',
+								function( evt )
+								{
+									getClipboardData.call( editor, evt, mode, function ( data )
+									{
+										// The very last guard to make sure the
+										// paste has really happened.
+										if ( !data )
+											return;
+
+										var dataTransfer = {};
+										dataTransfer[ mode ] = data;
+										editor.fire( 'paste', dataTransfer );
+									} );
+								} );
+
+					} );
+				}
+
 				// If the "contextmenu" plugin is loaded, register the listeners.
 				if ( editor.contextMenu )
@@ -206,3 +366,15 @@
 			}
 		});
+
+
 })();
+
+/**
+ * Whether to automatically choose the right format when pasting based on the
+ * detection of content text OR just leave it to the browser's default paste behavior.
+ * @type Boolean
+ * @default true
+ * @example
+ * config.autoDetectPaste = false;
+ */
+CKEDITOR.config.autoDetectPaste = true;
Index: CKEditor/branches/features/paste/_source/plugins/dialog/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/dialog/plugin.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/dialog/plugin.js	(revision 4674)
@@ -669,4 +669,5 @@
 					this.fireOnce( 'load', {} );
 					this.fire( 'show', {} );
+					this._.editor.fire( 'dialogShow', this );
 
 					// Save the initial values of the dialog.
@@ -732,4 +733,5 @@
 		{
 			this.fire( 'hide', {} );
+			this._.editor.fire( 'dialogHide', this );
 
 			// Remove the dialog's element from the root document.
Index: CKEditor/branches/features/paste/_source/plugins/fakeobjects/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/fakeobjects/plugin.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/fakeobjects/plugin.js	(revision 4674)
@@ -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/paste/_source/plugins/htmldataprocessor/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/htmldataprocessor/plugin.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/htmldataprocessor/plugin.js	(revision 4674)
@@ -1,3 +1,3 @@
-﻿/*
+/*
 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
@@ -84,6 +84,32 @@
 			// 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' ],
+			// 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;
+			}
+		}
 	};
 
Index: CKEditor/branches/features/paste/_source/plugins/pagebreak/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/pagebreak/plugin.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/pagebreak/plugin.js	(revision 4674)
@@ -56,5 +56,6 @@
 						div : function( element )
 						{
-							var style = element.attributes.style,
+							var attributes = element.attributes
+								style = attributes && element.attributes.style,
 								child = style && element.children.length == 1 && element.children[ 0 ],
 								childStyle = child && ( child.name == 'span' ) && child.attributes.style;
Index: CKEditor/branches/features/paste/_source/plugins/pastefromword/dialogs/pastefromword.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/pastefromword/dialogs/pastefromword.js	(revision 4673)
+++ 	(revision )
@@ -1,306 +1,0 @@
-/*
-Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
-For licensing, see LICENSE.html or http://ckeditor.com/license
-*/
-
-CKEDITOR.dialog.add( 'pastefromword', function( editor )
-{
-	return {
-		title : editor.lang.pastefromword.title,
-		minWidth : CKEDITOR.env.ie && CKEDITOR.env.quirks ? 370 : 350,
-		minHeight : CKEDITOR.env.ie && CKEDITOR.env.quirks ? 270 : 260,
-		htmlToLoad : '<!doctype html><script type="text/javascript">'
-				+ 'window.onload = function()'
-				+ '{'
-					+ 'if ( ' + CKEDITOR.env.ie + ' ) '
-						+ 'document.body.contentEditable = "true";'
-					+ 'else '
-						+ 'document.designMode = "on";'
-					+ 'var iframe = new window.parent.CKEDITOR.dom.element( frameElement );'
-					+ 'var dialog = iframe.getCustomData( "dialog" );'
-		      + ''
-					+ 'iframe.getFrameDocument().on( "keydown", function( e )\
-						{\
-							if ( e.data.getKeystroke() == 27 )\
-								dialog.hide();\
-						});'
-					+ 'dialog.fire( "iframeAdded", { iframe : iframe } );'
-				+ '};'
-				+ '</script><style>body { margin: 3px; height: 95%; } </style><body></body>',
-		cleanWord : function( editor, html, ignoreFont, removeStyles )
-		{
-			// 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 )
-			{
-				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 ;
-		},
-		onShow : function()
-		{
-			// To avoid JAWS putting virtual cursor back to the editor document,
-			// disable main document 'contentEditable' during dialog opening.
-			if ( CKEDITOR.env.ie )
-				this.getParentEditor().document.getBody().$.contentEditable = 'false';
-
-			// FIREFOX BUG: Force the browser to render the dialog to make the to-be-
-			// inserted iframe editable. (#3366)
-			this.parts.dialog.$.offsetHeight;
-
-			var container = this.getContentElement( 'general', 'editing_area' ).getElement(),
-				iframe = CKEDITOR.dom.element.createFromHtml( '<iframe src="javascript:void(0)" frameborder="0" allowtransparency="1"></iframe>' );
-
-			var lang = this.getParentEditor().lang;
-
-			iframe.setStyles(
-				{
-					width : '346px',
-					height : '152px',
-					'background-color' : 'white',
-					border : '1px solid black'
-				} );
-			iframe.setCustomData( 'dialog', this );
-
-			var accTitle = lang.editorTitle.replace( '%1', lang.pastefromword.title );
-
-			if ( CKEDITOR.env.ie )
-				container.setHtml( '<legend style="position:absolute;top:-1000000px;left:-1000000px;">'
-						+ CKEDITOR.tools.htmlEncode( accTitle )
-						+ '</legend>' );
-			else
-			{
-				container.setHtml( '' );
-				container.setAttributes(
-					{
-						role : 'region',
-						title : accTitle
-					} );
-				iframe.setAttributes(
-					{
-						role : 'region',
-						title : ' '
-					} );
-			}
-			container.append( iframe );
-			if ( CKEDITOR.env.ie )
-				container.setStyle( 'height', ( iframe.$.offsetHeight + 2 ) + 'px' );
-
-			if ( CKEDITOR.env.isCustomDomain() )
-			{
-				CKEDITOR._cke_htmlToLoad = this.definition.htmlToLoad;
-				iframe.setAttribute( 'src',
-					'javascript:void( (function(){' +
-						   'document.open();' +
-						   'document.domain="' + document.domain + '";' +
-						   'document.write( window.parent.CKEDITOR._cke_htmlToLoad );' +
-						   'delete window.parent.CKEDITOR._cke_htmlToLoad;' +
-						   'document.close();' +
-					'})() )' );
-			}
-			else
-			{
-				var doc = iframe.$.contentWindow.document;
-				doc.open();
-				doc.write( this.definition.htmlToLoad );
-				doc.close();
-			}
-		},
-		onOk : function()
-		{
-			var container = this.getContentElement( 'general', 'editing_area' ).getElement(),
-				iframe = container.getElementsByTag( 'iframe' ).getItem( 0 ),
-				editor = this.getParentEditor(),
-				html = this.definition.cleanWord( editor, iframe.$.contentWindow.document.body.innerHTML,
-						this.getValueOf( 'general', 'ignoreFontFace' ),
-						this.getValueOf( 'general', 'removeStyle' ) );
-
-				// Insertion should happen after main document design mode turned on.
-				setTimeout( function(){
-					editor.insertHtml( html );
-				}, 0 );
-		},
-		onHide : function()
-		{
-			if ( CKEDITOR.env.ie )
-				this.getParentEditor().document.getBody().$.contentEditable = 'true';
-		},
-		onLoad : function()
-		{
-			if ( ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) && editor.lang.dir == 'rtl' )
-				this.parts.contents.setStyle( 'overflow', 'hidden' );
-		},
-		contents :
-		[
-			{
-				id : 'general',
-				label : editor.lang.pastefromword.title,
-				elements :
-				[
-					{
-						type : 'html',
-						style : 'white-space:normal;width:346px;display:block',
-						onShow : function()
-						{
-							/*
-							 * SAFARI BUG: The advice label would overflow if the table layout
-							 * isn't fixed.
-							 */
-							if ( CKEDITOR.env.webkit )
-								this.getElement().getAscendant( 'table' ).setStyle( 'table-layout', 'fixed' );
-						},
-						html : editor.lang.pastefromword.advice
-					},
-					{
-						type : 'html',
-						id : 'editing_area',
-						style : 'width: 100%; height: 100%;',
-						html : '<fieldset></fieldset>',
-						focus : function()
-						{
-							var div = this.getElement();
-							var iframe = div.getElementsByTag( 'iframe' );
-							if ( iframe.count() < 1 )
-								return;
-							iframe = iframe.getItem( 0 );
-
-							// #3291 : JAWS needs the 500ms delay to detect that the editor iframe
-							// iframe is no longer editable. So that it will put the focus into the
-							// Paste from Word dialog's editable area instead.
-							setTimeout( function()
-							{
-								iframe.$.contentWindow.focus();
-							}, 500 );
-						}
-					},
-					{
-						type : 'vbox',
-						padding : 0,
-						children :
-						[
-							{
-								type : 'checkbox',
-								id : 'ignoreFontFace',
-								label : editor.lang.pastefromword.ignoreFontFace,
-								'default' : editor.config.pasteFromWordIgnoreFontFace
-							},
-							{
-								type : 'checkbox',
-								id : 'removeStyle',
-								label : editor.lang.pastefromword.removeStyle,
-								'default' : editor.config.pasteFromWordRemoveStyle
-							}
-						]
-					}
-				]
-			}
-		]
-	};
-} );
Index: CKEditor/branches/features/paste/_source/plugins/pastefromword/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/pastefromword/plugin.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/pastefromword/plugin.js	(revision 4674)
@@ -3,52 +3,109 @@
 For licensing, see LICENSE.html or http://ckeditor.com/license
 */
+( function()
+{
+	CKEDITOR.plugins.add( 'pastefromword',
+	{
+		init : function( editor )
+		{
 
-CKEDITOR.plugins.add( 'pastefromword',
-{
-	init : function( editor )
-	{
-		// Register the command.
-		editor.addCommand( 'pastefromword', new CKEDITOR.dialogCommand( 'pastefromword' ) );
+			// Flag indicate this command is actually been asked instead of a generic
+			// pasting.
+			var forceFromWord = 0,
+				resetFromWord = function()
+				{
+					setTimeout( function()
+					{
+						forceFromWord = 0;
+					}, 0 );
+				};
 
-		// Register the toolbar button.
-		editor.ui.addButton( 'PasteFromWord',
+			// Features bring by this command beside the normal process:
+			// 1. No more bothering of user about the clean-up.
+			// 2. Perform the clean-up even if content is not from MS-Word.
+			// (e.g. from a MS-Word similar application.)
+			editor.addCommand( 'pastefromword',
 			{
-				label : editor.lang.pastefromword.toolbar,
-				command : 'pastefromword'
+				exec : function ()
+				{
+					forceFromWord = 1;
+					editor.fire( 'pasteDialog' );
+					editor.on( 'dialogHide', function ( evt )
+					{
+						evt.removeListener();
+						resetFromWord();
+					} );
+				}
 			} );
 
-		// 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'
+				} );
+
+			editor.on( 'paste', function( evt )
+			{
+				var data = evt.data,
+					isLazyLoad,
+					mswordHtml;
+				// MS-WORD format sniffing.
+				if ( ( mswordHtml = data[ 'html' ] )
+					 && ( forceFromWord || /(class=\"?Mso|style=\"[^\"]*\bmso\-|w:WordDocument)/.test( mswordHtml ) )
+					 && ( !editor.config.pasteFromWordPromptCleanup
+						  || ( forceFromWord || confirm( editor.lang.pastefromword.confirmCleanup )  ) ) )
+				{
+					if( isLazyLoad = this.loadFilterRules( function()
+					{
+						// Re-continue the event with the original data.
+						if( isLazyLoad )
+							editor.fire( 'paste', data );
+						else
+						{
+							// Firefox will be confused by those downlevel-revealed IE conditional
+							// comments, fixing them first( convert it to upperlevel-revealed one ).
+							// e.g. <![if !vml]>...<![endif]>
+							if( CKEDITOR.env.gecko )
+							{
+								data[ 'html' ] =
+									mswordHtml.replace( /(<!--\[if[^<]*?\])-->([\S\s]*?)<!--(\[endif\]-->)/gi, '$1$2$3' );
+							}
+
+							var filter = data.processor.dataFilter;
+							// These rules will have higher priorities than default ones.
+							filter.addRules( CKEDITOR.plugins.pastefromword.getRules( editor ), 5 );
+						}
+					} ) )
+					{
+						// The filtering rules are to be loaded, it's safe to just cancel
+						// this event.  
+						evt.cancel();
+					}
+				}
+			}, this );
+		},
+
+		loadFilterRules : function( callback )
+		{
+			var isLoaded = typeof CKEDITOR.plugins.pastefromword != 'undefined';
+
+			isLoaded ?
+				callback() :
+				// Load with busy indicator.
+				CKEDITOR.scriptLoader.load( this.path + 'rules.js',
+						callback, null, false, true );
+
+			return !isLoaded;
+		}
+	} );
+} )();
 
 /**
- * Whether the "Ignore font face definitions" checkbox is enabled by default in
- * the Paste from Word dialog.
+ * Whether prompt the user about the clean-up of content from MS-Word.
+ * @name CKEDITOR.config.pasteFromWordPromptCleanup
  * @type Boolean
  * @default true
  * @example
- * config.pasteFromWordIgnoreFontFace = false;
+ * config.pasteFromWordPromptCleanup = true;
  */
-CKEDITOR.config.pasteFromWordIgnoreFontFace = true;
-
-/**
- * Whether the "Remove styles definitions" checkbox is enabled by default in
- * the Paste from Word dialog.
- * @type Boolean
- * @default false
- * @example
- * config.pasteFromWordRemoveStyle = true;
- */
-CKEDITOR.config.pasteFromWordRemoveStyle = false;
-
-/**
- * Whether to keep structure markup (&lt;h1&gt;, &lt;h2&gt;, etc.) or replace
- * it with elements that create more similar pasting results when pasting
- * content from Microsoft Word into the Paste from Word dialog.
- * @type Boolean
- * @default false
- * @example
- * config.pasteFromWordKeepsStructure = true;
- */
-CKEDITOR.config.pasteFromWordKeepsStructure = false;
Index: CKEditor/branches/features/paste/_source/plugins/pastefromword/rules.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/pastefromword/rules.js	(revision 4674)
+++ CKEditor/branches/features/paste/_source/plugins/pastefromword/rules.js	(revision 4674)
@@ -0,0 +1,931 @@
+( function()
+{
+	var fragmentPrototype = CKEDITOR.htmlParser.fragment.prototype,
+		elementPrototype = CKEDITOR.htmlParser.element.prototype;
+
+	fragmentPrototype.onlyChild = elementPrototype.onlyChild = function()
+	{
+		var children = this.children,
+			count = children.length,
+			firstChild = ( count == 1 ) && children[ 0 ];
+		return firstChild || null;
+	};
+
+	elementPrototype.removeAnyChildWithName = function( tagName )
+	{
+		var children = this.children,
+			childs = [],
+			child;
+
+		for ( var i = 0; i < children.length; i++ )
+		{
+			child = children[ i ];
+			if( !child.name )
+				continue;
+
+			if( child.name == tagName )
+			{
+				childs.push( child );
+				children.splice( i--, 1 );
+			}
+			childs = childs.concat( child.removeAnyChildWithName( tagName ) );
+		}
+		return childs;
+	};
+
+	elementPrototype.getAncestor = function( tagNameRegex )
+	{
+		var parent = this.parent;
+		while( parent && !( parent.name && parent.name.match( tagNameRegex ) ) )
+			parent = parent.parent;
+		return parent;
+	};
+
+	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;
+			else if( child.name )
+			{
+				child = child.firstTextChild();
+				if( child )
+					return child;
+				else
+					continue;
+			}
+		}
+	};
+
+	// Adding a (set) of styles to the element's attributes.
+	elementPrototype.addStyle = function( name, value, isPrepend )
+	{
+		var styleText, addingStyleText = '';
+		// name/value pair.
+		if ( typeof value == 'string' )
+			addingStyleText += name + ':' + value + ';';
+		else
+		{
+			// style literal.
+			if( typeof name == 'object' )
+			{
+				for( var style in name )
+				{
+					if( name.hasOwnProperty( style) )
+						addingStyleText += style + ':' + name[ style ] + ';';
+				}
+				// Avoid CKPackager produce buggy output (#4695)
+				// TODO: Remove after CKPackager get fixed.
+				;
+			}
+			// raw style text form.
+			else
+				addingStyleText += name;
+			isPrepend = value;
+		}
+
+		if( !this.attributes )
+			this.attributes = {};
+
+		styleText = this.attributes.style || '';
+
+		styleText = ( isPrepend ?
+		              [ addingStyleText, styleText ]
+					  : [ styleText, addingStyleText ] ).join( ';' );
+
+		this.attributes.style = styleText.replace( /^;|;(?=;)/, '' );
+	};
+
+	/**
+	 * Return the DTD-valid parent tag names of the specified one.
+	 * @param tagName
+	 */
+	CKEDITOR.dtd.parentOf = function( tagName )
+	{
+		var result = {};
+		for( var tag in this )
+		{
+			if( tag.indexOf( '$' ) == -1 && this[ tag ][ tagName ] )
+				result[ tag ] = 1;
+		}
+		return result;
+	};
+
+	var cssLengthRelativeUnit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz){1}?/i;
+
+	CKEDITOR.plugins.pastefromword =
+	{
+		utils :
+		{
+			// Create a <cke:listbullet> which indicate an list item type.
+			createListBulletMarker : function ( bulletStyle, bulletText )
+			{
+				var marker = new CKEDITOR.htmlParser.element( 'cke:listbullet' ),
+					listType;
+
+				// TODO: Support more list style type from MS-Word.
+				if( !bulletStyle )
+				{
+					bulletStyle = 'decimal';
+					listType = 'ol';
+				}
+				else if ( bulletStyle[ 2 ] )
+				{
+					if ( !isNaN( bulletStyle[ 1 ] ) )
+						bulletStyle = 'decimal';
+					// No way to distinguish between Roman numerals and Alphas,
+					// detect them as a whole.
+					else if ( /^[a-z]+$/.test( bulletStyle[ 1 ] ) )
+						bulletStyle = 'lower-alpha';
+					else if ( /^[A-Z]+$/.test( bulletStyle[ 1 ] ) )
+						bulletStyle = 'upper-alpha';
+					// Simply use decimal for the rest forms of unrepresentable
+					// numerals, e.g. Chinese...
+					else
+						bulletStyle = 'decimal';
+
+					listType = 'ol';
+				}
+				else
+				{
+					if ( /[l\u00B7\u2002]/.test( bulletStyle[ 1 ] ) ) //l·•
+						bulletStyle = 'disc';
+					else if ( /[\u006F\u00D8]/.test( bulletStyle[ 1 ] ) )  //oØ
+						bulletStyle = 'circle';
+					else if ( /[\u006E\u25C6]/.test( bulletStyle[ 1 ] ) ) //n◆
+						bulletStyle = 'square';
+					else
+						bulletStyle = 'disc';
+
+					listType = 'ul';
+				}
+
+				// Represent list type as CSS style.
+				marker.attributes =
+				{
+					'cke:listtype' : listType,
+					'style' : 'list-style-type:' + bulletStyle + ';'
+				};
+				marker.add( new CKEDITOR.htmlParser.text( bulletText ) );
+				return marker;
+			},
+
+			isListBulletIndicator : function( element )
+			{
+				var styleText = element.attributes && element.attributes.style;
+				if( /mso-list\s*:\s*Ignore/i.test( styleText ) )
+					return true;
+			},
+
+			isContainingOnlySpaces : function( element )
+			{
+				var text;
+				return ( ( text = element.onlyChild() )
+					    && /^(:?\s|&nbsp;)+$/.test( text.value ) );
+			},
+
+			resolveList : function( element )
+			{
+				// <cke:listbullet> indicate a list item.
+				var children = element.children,
+					attrs = element.attributes,
+					listMarker;
+				if( ( listMarker = element.removeAnyChildWithName( 'cke:listbullet' ) )
+					  && listMarker.length
+					  && ( listMarker = listMarker[ 0 ] ) )
+				{
+					element.name = 'cke:li';
+
+					if( attrs.style )
+					{
+						attrs.style = CKEDITOR.plugins.pastefromword.filters.stylesFilter(
+						[
+							// Text-indent is not representing list item level any more.
+							[ 'text-indent' ],
+							[ 'line-height' ],
+							// Resolve indent level from 'margin-left' value.
+							[ /^margin(:?-left)?$/, null, function( value )
+							{
+								// Be able to deal with component/short-hand form style.
+								var values = value.split( ' ' );
+								value = values[ 3 ] || values[ 1 ] || values [ 0 ];
+								attrs[ 'cke:indent' ] = parseInt( value );
+							} ]
+						] )( attrs.style, element ) || '' ;
+					}
+
+					// Inherit list-type-style from bullet.
+					var listBulletAttrs = listMarker.attributes,
+						listBulletStyle = listBulletAttrs.style;
+
+					element.addStyle( listBulletStyle );
+					CKEDITOR.tools.extend( attrs, listBulletAttrs );
+					return true;
+				}
+			},
+
+			convertToPx : function( cssLength )
+			{
+				// Convert to 'px' in ignorance of DPI.
+				if( cssLengthRelativeUnit.test( cssLength ) )
+				{
+					var val,
+						calculator = CKEDITOR.dom.element.createFromHtml(
+										'<div style="position:absolute;left:-9999px;' +
+										'top:-9999px;margin:0px;padding:0px;border:0px;' +
+										'width:' + cssLength + '" ' +
+										'></div>' );
+					CKEDITOR.document.getBody().append( calculator );
+					val = calculator.$.clientWidth;
+					calculator.remove();
+					return val + 'px';
+				}
+				return cssLength;
+			},
+
+			listDtdParents : CKEDITOR.dtd.parentOf( 'ol' )
+		},
+
+		filters :
+		{
+				// Transform a normal list into flat list items only presentation.
+				// E.g. <ul><li>level1<ol><li>level2</li></ol></li> =>
+				// <cke:li cke:listtype="ul" cke:indent="1">level1</cke:li>
+				// <cke:li cke:listtype="ol" cke:indent="2">level2</cke:li>
+				flattenList : function( element )
+				{
+					var	attrs = element.attributes,
+						parent = element.parent;
+
+					var listStyleType,
+						indentLevel = 1;
+
+					// Resolve how many level nested.
+					while( parent )
+					{
+						parent.attributes && parent.attributes[ 'cke:list'] && indentLevel++;
+						parent = parent.parent;
+					}
+
+					// All list items are of the same type.
+					switch( attrs.type )
+					{
+						case 'a' :
+							listStyleType = 'lower-alpha';
+							break;
+						// TODO: Support more list style type from MS-Word.
+					}
+
+					var children = element.children,
+						child;
+
+					for ( var i = 0; i < children.length; i++ )
+					{
+						child = children[ i ];
+						var attributes = child.attributes;
+
+						if( child.name in CKEDITOR.dtd.$listItem )
+						{
+							var listItemChildren = child.children,
+								count = listItemChildren.length,
+								last = listItemChildren[ count - 1 ];
+
+							// Move out nested list.
+							if( last.name in CKEDITOR.dtd.$list )
+							{
+								listItemChildren.length--;
+								children.splice( i + 1, 0, last );
+								last.parent = element;
+							}
+
+							child.name = 'cke:li';
+							attributes[ 'cke:indent' ] = indentLevel;
+							attributes[ 'cke:listtype' ] = element.name;
+							listStyleType && child.addStyle( 'list-style-type', listStyleType, true );
+						}
+					}
+
+
+					delete element.name;
+					// We're loosing tag name here, signalize this element as a list.
+					attrs[ 'cke:list' ] = 1;
+				},
+
+				/**
+				 * A simple filter which always rejecting.
+				 */
+				falsyFilter  : function( value )
+				{
+					return false;
+				},
+
+				/**
+				 * A filter dedicated on the 'style' attribute filtering, e.g. dropping/replacing style properties.
+				 * @param styles {Array} in form of [ styleNameRegexp, styleValueRegexp,
+				 *  newStyleValue/newStyleGenerator, newStyleName ] where only the first
+				 *  parameter is mandatory.
+				 */
+				stylesFilter : function( styles )
+				{
+					return function( styleText, element )
+					{
+						 var rules = [];
+						// html-encoded quote might be introduced by 'font-family'
+						// from MS-Word which confused the following regexp. e.g.
+						//'font-family: &quot;Lucida, Console&quot;'
+						 styleText.replace( /&quot;/g, '"' )
+								  .replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g,
+							 function( match, name, value )
+							 {
+								 name = name.toLowerCase();
+								 name == 'font-family' && ( value = value.replace( /["']/g, '' ) );
+
+								 var namePattern,
+									 valuePattern,
+									 newValue,
+									 newName;
+								 for( var i = 0 ; i < styles.length; i++ )
+								 {
+									if( styles[ i ] )
+									{
+										namePattern = styles[ i ][ 0 ];
+										valuePattern = styles[ i ][ 1 ];
+										newValue = styles[ i ][ 2 ];
+										newName = styles[ i ][ 3 ];
+
+										if ( name.match( namePattern )
+											 && ( !valuePattern || value.match( valuePattern ) ) )
+										{
+											name = newName || name;
+											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( ';' ) + ';' ) : false;
+					 };
+				},
+
+				/**
+				 * Migrate the element by decorate styles on it.
+				 * @param styleDefiniton
+				 * @param variables
+				 */
+				elementMigrateFilter : function ( styleDefiniton, variables )
+				{
+					return function( element )
+					{
+						var styleDef =
+								variables ?
+									new CKEDITOR.style( styleDefiniton, variables )._.definition
+									: styleDefiniton;
+						element.name = styleDef.element;
+						CKEDITOR.tools.extend( element.attributes, CKEDITOR.tools.clone( styleDef.attributes ) );
+						element.addStyle( CKEDITOR.style.getStyleText( styleDef ) );
+					}
+				},
+
+				/**
+				 * Migrate styles by creating a new nested stylish element.
+				 * @param styleDefinition
+				 */
+				styleMigrateFilter : function( styleDefinition, variableName )
+				{
+
+					var elementMigrateFilter = this.elementMigrateFilter;
+					return function( value, element )
+					{
+						// Build an stylish element first.
+						var styleElement = new CKEDITOR.htmlParser.element( null, {} ),
+							variables = {};
+
+						variables[ variableName ] = value;
+						elementMigrateFilter( styleDefinition, variables )( styleElement );
+						// Place the new element inside the existing span.
+						styleElement.children = element.children;
+						element.children = [ styleElement ];
+					};
+				},
+
+				/**
+				 * A filter which remove cke-namespaced-attribute on
+				 * all none-cke-namespaced elements.
+				 * @param value
+				 * @param element
+				 */
+				bogusAttrFilter : function( value, element )
+				{
+					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
+
+			},
+
+		getRules : function( editor )
+		{
+			var dtd = CKEDITOR.dtd,
+				blockLike = CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ),
+				config = editor.config,
+				filters = this.filters,
+				falsyFilter = filters.falsyFilter,
+				stylesFilter = filters.stylesFilter,
+				elementMigrateFilter = filters.elementMigrateFilter,
+				styleMigrateFilter = CKEDITOR.tools.bind( this.filters.styleMigrateFilter, this.filters ),
+				bogusAttrFilter = filters.bogusAttrFilter,
+				createListBulletMarker = this.utils.createListBulletMarker,
+				flattenList = filters.flattenList,
+				isListBulletIndicator = this.utils.isListBulletIndicator,
+				containsNothingButSpaces = this.utils.isContainingOnlySpaces,
+				resolveListItem = this.utils.resolveList,
+				convertToPx = this.utils.convertToPx,
+				listDtdParents = this.utils.listDtdParents,
+				ignoreFontFace = config.pasteFromWordIgnoreFontFace;
+
+			return {
+
+				elementNames :
+				[
+					// Remove script, meta and link elements.
+					[ /meta|link|script/, '' ]
+				],
+
+				elements :
+				{
+					'^' : function( element )
+					{
+						// Transform CSS style declaration to inline style.
+						var applyStyleFilter;
+						if ( CKEDITOR.env.gecko && ( applyStyleFilter = filters.applyStyleFilter ) )
+							applyStyleFilter( element );
+					},
+
+					$ : function( element )
+					{
+						var tagName = element.name || '',
+							attrs = element.attributes;
+
+						// Convert length unit of width/height on blocks to
+						// a more editor-friendly way (px).
+						if( tagName in blockLike
+							&& attrs.style )
+							attrs.style = stylesFilter(
+										[ [ /^width|height$/, null, convertToPx ] ] )( attrs.style ) || '';
+
+						// Processing headings.
+						if ( tagName.match( /h\d/ ) )
+						{
+							element.filterChildren();
+							// Is the heading actually a list item?
+							if( resolveListItem( element ) )
+								return;
+
+							// Adapt heading styles to editor's convention.
+							elementMigrateFilter( config[ 'format_' + tagName ] )( element );
+						}
+						// Remove inline elements which contain only empty spaces.
+						else if( tagName in dtd.$nonEmptyInline )
+						{
+							element.filterChildren();
+							if ( containsNothingButSpaces(element) )
+								delete element.name;
+						}
+						// Remove ms-office namespaced element, with it's content preserved.
+						else if( tagName.indexOf( ':' ) != -1
+								 && tagName.indexOf( 'cke' ) == -1 )
+						{
+							element.filterChildren();
+
+							// Restore image real link from vml.
+							if( tagName == 'v:imagedata' )
+							{
+								var href = element.attributes[ 'o:href' ];
+								if ( href )
+									element.attributes.src = href;
+								element.name = 'img';
+								return;
+							}
+							delete element.name;
+						}
+
+						// Assembling list items into a whole list.
+						if( !tagName || 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 = 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;
+							}
+						}
+					},
+					// We'll drop any style sheet, but Firefox conclude
+					// certain styles in a single style element, which are
+					// required to be changed into inline ones.
+					'style' : function( element )
+					{
+						if( CKEDITOR.env.gecko )
+						{
+							// Grab only the style definition section.
+							var styleDefSection = element.onlyChild().value.match( /\/\* Style Definitions \*\/([\s\S]*?)\/\*/ ),
+								styleDefText = styleDefSection && styleDefSection[ 1 ],
+								rules = {}; // Storing the parsed result.
+
+							if( styleDefText )
+							{
+								styleDefText.replace(/[\n\r]/g,'') // remove line-breaks.
+											// Extract selectors and style properties.
+											.replace( /(.+?)\{(.+?)\}/g,
+								function( rule, selectors, styleBlock )
+								{
+									selectors = selectors.split( ',' );
+									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,
+										function( match, tagName, className )
+										{
+											tagName = tagName || '*';
+											className = className.substring( 1, className.length );
+
+											// Reject MS-Word Normal styles.
+											if( className.match( /MsoNormal/ ) )
+												return;
+
+											if( !rules[ tagName ] )
+												rules[ tagName ] = {};
+											if( className )
+												rules[ tagName ][ className ] = styleBlock;
+											else
+												rules[ tagName ] = styleBlock;
+										} );
+									}
+								} );
+
+								filters.applyStyleFilter = function( element )
+								{
+									var name = rules[ '*' ] ? '*' : element.name,
+										className = element.attributes && element.attributes[ 'class' ],
+										style;
+									if( name in rules )
+									{
+										style = rules[ name ];
+										if( typeof style == 'object' )
+											style = style[ className ];
+										// Maintain style rules priorities.
+										style && element.addStyle( style, true );
+									}
+								};
+							}
+						}
+						return false;
+					},
+					'p' : function( element )
+					{
+						element.filterChildren();
+
+						var attrs = element.attributes,
+							parent = element.parent,
+							children = element.children;
+
+						// Is the paragraph actually a list item?
+						if( resolveListItem( element ) )
+							return;
+
+						// 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' ) );
+						}
+						else
+							elementMigrateFilter( config[ 'format_' + ( config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ] )( element );
+					},
+
+					'td' : function ( element )
+					{
+						// 'td' in 'thead' is actually <th>.
+						if ( element.getAncestor( 'thead') )
+							element.name = 'th';
+					},
+
+					// MS-Word sometimes present list as a mixing of normal list
+					// and pseudo-list, normalize the previous ones into pseudo form.
+					'ol' : flattenList,
+					'ul' : flattenList,
+					'dl' : flattenList,
+
+					'font' : function( element )
+					{
+						// IE/Safari: drop the font tag if it comes from list bullet text.
+						if ( !CKEDITOR.env.gecko && isListBulletIndicator( element.parent ) )
+						{
+							delete element.name;
+							return;
+						}
+
+						element.filterChildren();
+
+						var attrs = element.attributes,
+							styleText = attrs.style,
+							parent = element.parent;
+
+						if( 'font' == parent.name )     // Merge nested <font> tags.
+						{
+							CKEDITOR.tools.extend( parent.attributes,
+									element.attributes );
+							styleText && parent.addStyle( styleText );
+							delete element.name;
+							return;
+						}
+						// Convert the merged into a span with all attributes preserved.
+						else
+						{
+							styleText = styleText || '';
+							// IE's having those deprecated attributes, normalize them.
+							if ( attrs.color )
+							{
+								attrs.color != '#000000' && ( styleText += 'color:' + attrs.color + ';' );
+								delete attrs.color;
+							}
+							if ( attrs.face )
+							{
+								styleText += 'font-family:' + attrs.face + ';';
+								delete attrs.face;
+							}
+							// TODO: Mapping size in ranges of xx-small,
+							// x-small, small, medium, large, x-large, xx-large.
+							if ( attrs.size )
+							{
+								styleText += 'font-size:' +
+								             ( attrs.size > 3 ? 'large'
+										             : ( attrs.size < 3 ? 'small' : 'medium' ) ) + ';';
+								delete attrs.size;
+							}
+							element.name = 'span';
+							element.addStyle( styleText );
+						}
+					},
+
+					'span' : function( element )
+					{
+						// IE/Safari: remove the span if it comes from list bullet text.
+						if ( !CKEDITOR.env.gecko && isListBulletIndicator( element.parent ) )
+							return false;
+
+						element.filterChildren();
+						if( containsNothingButSpaces( element ) )
+						{
+							delete element.name;
+							return;
+						}
+
+						// For IE/Safari: List item bullet type is supposed to be indicated by
+						// the text of a span with style 'mso-list : Ignore'.
+						if ( !CKEDITOR.env.gecko && isListBulletIndicator( element ) )
+						{
+							var listSymbol = element.firstTextChild().value,
+								listType = listSymbol.match( /^([^\s]+?)([.)]?)$/ );
+							return createListBulletMarker( listType, listSymbol );
+						}
+
+						// Update the src attribute of image element with href.
+						var children = element.children,
+							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;
+							children.splice( 0, 1 );
+							delete element.name;
+						}
+
+						// Assume MS-Word mostly carry font related styles on <span>,
+						// adapting them to editor's convention.
+						if( styleText )
+							attrs.style = stylesFilter(
+									[
+										// 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' ) ]
+									] )( styleText, element ) || '';
+					},
+
+					// Migrate basic style formats to editor configured ones.
+					'b' : elementMigrateFilter( config[ 'coreStyles_bold' ] ),
+					'i' : elementMigrateFilter( config[ 'coreStyles_italic' ] ),
+					'u' : elementMigrateFilter( config[ 'coreStyles_underline' ] ),
+					's' : elementMigrateFilter( config[ 'coreStyles_strike' ] ),
+					'sup' : elementMigrateFilter( config[ 'coreStyles_superscript' ] ),
+					'sub' : elementMigrateFilter( config[ 'coreStyles_subscript' ] ),
+					// Editor doesn't support anchor with content currently (#3582),
+					// drop such anchors with content preserved.
+					'a' : function( element )
+					{
+						var attrs = element.attributes;
+						if( attrs && !attrs.href && attrs.name )
+							delete element.name;
+					},
+					'cke:listbullet' : function( element )
+					{
+						if ( element.getAncestor( /h\d/ ) && !config.pasteFromWordNumberedHeadingToList )
+							delete element.name;
+					}
+				},
+
+				attributeNames :
+				[
+					// Remove onmouseover and onmouseout events (from MS Word comments effect)
+					[ /^onmouse(:?out|over)/, '' ],
+					// Remove office and vml attribute from elements.
+					[ /(?:v|o):\w+/, '' ],
+					// Remove lang/language attributes.
+					[ /^lang/, '' ]
+				],
+
+				attributes :
+				{
+					'style' : stylesFilter(
+					[
+						[ /^mso-/ ],
+						// Fixing color values.
+						[ /-color$/, null, function( value )
+						{
+							if( value == 'transparent' )
+								return false;
+							if( CKEDITOR.env.gecko )
+								return value.replace( /-moz-use-text-color/g, 'transparent' );
+						} ],
+						// Remove empty margin values, e.g. 0.00001pt 0em 0pt
+						[ /^margin$/, /^(?:\b0[^\s]*\s*){1,4}$/ ],
+						[ 'text-indent', '0cm' ],
+						[ 'page-break-before' ],
+						[ 'tab-stops' ],
+						[ 'display', 'none' ],
+						ignoreFontFace ? [ /font-?/ ] : null,
+					] ),
+					// Prefer width styles over 'width' attributes.
+					'width' : function( value, element )
+					{
+						if( element.name in dtd.$tableContent )
+							return false;
+					},
+					// Prefer border styles over table 'border' attributes.
+					'border' : function( value, element )
+					{
+						if( element.name in dtd.$tableContent )
+							return false;
+					},
+
+					// Only Firefox carry style sheet from MS-Word, which
+					// will be applied by us manually. For other browsers
+					// the css className is useless.
+					'class' : falsyFilter,
+
+					// MS-Word always generate both 'text-align' along with
+					// 'align' attribute( 'background-color' along with 'bgcolor'),
+					// simply drop the deprecated attributes.
+					'align' : falsyFilter,
+					'bgcolor' : falsyFilter,
+
+					// Deprecate 'valign' attribute in favor of 'vertical-align'.
+					'valign' : function( value, element )
+					{
+						element.addStyle( 'vertical-align', value );
+						return false;
+					}
+				},
+
+				// Fore none-IE, some useful data might be buried under these IE-conditional
+				// comments where RegExp were the right approach to dig them out where usual approach
+				// is transform it into a fake element node which hold the desired data.
+				comment : !CKEDITOR.env.ie ? function( value, node )
+				{
+					var imageInfo = value.match( /<img.*?>/ ),
+						imageSource = value.match( /<v:imagedata[^>]*o:href=['"](.*?)['"]/ ),
+						listInfo = value.match( /^\[if !supportLists\]([\s\S]*?)\[endif\]$/ );
+
+					// Reveal the <img> element in conditional comments for Firefox.
+					if( CKEDITOR.env.gecko && imageInfo )
+						return CKEDITOR.htmlParser.fragment.fromHtml( imageInfo[ 0 ] ).children[ 0 ];
+					// Try to dig the real image link from vml markup.
+					if( imageSource )
+						return new CKEDITOR.htmlParser.element( 'cke:imagesource', { src : imageSource[ 1 ] } );
+					// Seek for list bullet style indicator.
+					if ( listInfo )
+					{
+						var listSymbol = listInfo[ 1 ],
+							listType = listSymbol.match( />([^\s]+?)([.)]?)</ );
+						return createListBulletMarker( listType, listSymbol );
+					}
+					return false;
+				} : falsyFilter
+			};
+		}
+	};
+
+} )( );
+
+/**
+ * Whether the ignore all font-related format from MS-Word.
+ * @name CKEDITOR.config.pasteFromWordIgnoreFontFace
+ * @type Boolean
+ * @default true
+ * @example
+ * config.pasteFromWordIgnoreFontFace = false;
+ */
+
+/**
+ * Whether transform MS-Word Outline Numbered Heading into html list.
+ * @name CKEDITOR.config.pasteFromWordNumberedHeadingToList
+ * @type Boolean
+ * @default false
+ * @example
+ * config.pasteFromWordNumberedHeadingToList = true;
+ */
Index: CKEditor/branches/features/paste/_source/plugins/pastetext/dialogs/pastetext.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/pastetext/dialogs/pastetext.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/pastetext/dialogs/pastetext.js	(revision 4674)
@@ -24,7 +24,5 @@
 					// Get the textarea value.
 					var text = this.getContentElement( 'general', 'content' ).getInputElement().getValue();
-
-					// Inserts the text.
-					this.getParentEditor().insertText( text );
+					this.getParentEditor().fire( 'paste', { 'text' : text } );
 				},
 
Index: CKEditor/branches/features/paste/_source/plugins/pastetext/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/pastetext/plugin.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/pastetext/plugin.js	(revision 4674)
@@ -1,3 +1,3 @@
-﻿/*
+/*
 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
@@ -15,13 +15,39 @@
 		exec : function( editor )
 		{
-			// We use getClipboardData just to test if the clipboard access has
-			// been granted by the user.
-			if ( CKEDITOR.getClipboardData() === false || !window.clipboardData )
+			var clipboardText = CKEDITOR.tools.tryThese(
+				function()
+				{
+					var clipboardText = window.clipboardData.getData( 'Text' );
+					if ( !clipboardText )
+						throw 0;
+					return clipboardText;
+				},
+				function()
+				{
+					netscape.security.PrivilegeManager.enablePrivilege( "UniversalXPConnect" );
+
+					var clip = Components.classes[ "@mozilla.org/widget/clipboard;1" ]
+							.getService( Components.interfaces.nsIClipboard );
+					var trans = Components.classes[ "@mozilla.org/widget/transferable;1" ]
+							.createInstance( Components.interfaces.nsITransferable );
+					trans.addDataFlavor( "text/unicode" );
+					clip.getData( trans, clip.kGlobalClipboard );
+
+					var str = {}, strLength = {}, clipboardText;
+					trans.getTransferData( "text/unicode", str, strLength );
+					str = str.value.QueryInterface( Components.interfaces.nsISupportsString );
+					clipboardText = str.data.substring( 0, strLength.value / 2 );
+					return clipboardText;
+				}
+				// Any other approach that's working... 
+				);
+			
+			if ( !clipboardText )   // Clipboard access privilege is not granted.
 			{
 				editor.openDialog( 'pastetext' );
-				return;
+				return false;
 			}
-
-			editor.insertText( window.clipboardData.getData( 'Text' ) );
+			else
+				editor.fire( 'paste', { 'text' : clipboardText } );
 		}
 	};
@@ -39,84 +65,23 @@
 					label : editor.lang.pasteText.button,
 					command : commandName
-				});
+				} );
 
 			CKEDITOR.dialog.add( commandName, CKEDITOR.getUrl( this.path + 'dialogs/pastetext.js' ) );
 
-			if ( editor.config.forcePasteAsPlainText )
+			if( editor.config.forcePasteAsPlainText )
 			{
-				editor.on( 'beforePaste', function( event )
+				// Intercept the default pasting process.
+				editor.on( 'beforeCommandExec', function ( evt )
+				{
+					if ( evt.data.name == 'paste' )
 					{
-						if ( editor.mode == "wysiwyg" )
-						{
-							setTimeout( function() { command.exec(); }, 0 );
-							event.cancel();
-						}
-					},
-					null, null, 20 );
+						editor.execCommand( 'pastetext' );
+						evt.cancel();
+					}
+				}, null, null, 0 );
 			}
 		},
 		requires : [ 'clipboard' ]
 	});
-
-	var clipboardDiv;
-
-	CKEDITOR.getClipboardData = function()
-	{
-		if ( !CKEDITOR.env.ie )
-			return false;
-
-		var doc = CKEDITOR.document,
-			body = doc.getBody();
-
-		if ( !clipboardDiv )
-		{
-			clipboardDiv = doc.createElement( 'div',
-				{
-					attributes :
-						{
-							id: 'cke_hiddenDiv'
-						},
-					styles :
-						{
-							position : 'absolute',
-							visibility : 'hidden',
-							overflow : 'hidden',
-							width : '1px',
-							height : '1px'
-						}
-				});
-
-			clipboardDiv.setHtml( '' );
-
-			clipboardDiv.appendTo( body );
-		}
-
-		// The "enabled" flag is used to check whether the paste operation has
-		// been completed (the onpaste event has been fired).
-		var	enabled = false;
-		var setEnabled = function()
-		{
-			enabled = true;
-		};
-
-		body.on( 'paste', setEnabled );
-
-		// Create a text range and move it inside the div.
-		var textRange = body.$.createTextRange();
-		textRange.moveToElementText( clipboardDiv.$ );
-
-		// The execCommand in will fire the "onpaste", only if the
-		// security settings are enabled.
-		textRange.execCommand( 'Paste' );
-
-		// Get the DIV html and reset it.
-		var html = clipboardDiv.getHtml();
-		clipboardDiv.setHtml( '' );
-
-		body.removeListener( 'paste', setEnabled );
-
-		// Return the HTML or false if not enabled.
-		return enabled && html;
-	};
 })();
 
Index: CKEditor/branches/features/paste/_source/plugins/styles/plugin.js
===================================================================
--- CKEditor/branches/features/paste/_source/plugins/styles/plugin.js	(revision 4673)
+++ CKEditor/branches/features/paste/_source/plugins/styles/plugin.js	(revision 4674)
@@ -199,6 +199,6 @@
 							continue;
 
-						var elementAttr = element.getAttribute( attName );
-						if ( attribs[attName] ==
+						var elementAttr = element.getAttribute( attName ) || '';
+						if ( attribs[ attName ] ==
 							 ( attName == 'style' ?
 							   normalizeCssText( elementAttr, false ) : elementAttr  ) )
