Index: /CKEditor/branches/versions/3.1.x/CHANGES.html
===================================================================
--- /CKEditor/branches/versions/3.1.x/CHANGES.html	(revision 4555)
+++ /CKEditor/branches/versions/3.1.x/CHANGES.html	(revision 4556)
@@ -40,5 +40,5 @@
 		New features:</p>
 	<ul>
-		<li></li>
+		<li><a href="http://dev.fckeditor.net/ticket/4729">#4729</a> : Added support to fake elements for comments.</li>
 	</ul>
 	<p>
Index: /CKEditor/branches/versions/3.1.x/_source/core/dom/comment.js
===================================================================
--- /CKEditor/branches/versions/3.1.x/_source/core/dom/comment.js	(revision 4556)
+++ /CKEditor/branches/versions/3.1.x/_source/core/dom/comment.js	(revision 4556)
@@ -0,0 +1,32 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @fileOverview Defines the {@link CKEDITOR.dom.comment} class, which represents
+ *		a DOM comment node.
+ */
+
+CKEDITOR.dom.comment = CKEDITOR.tools.createClass(
+{
+	base : CKEDITOR.dom.node,
+
+	$ : function( text, ownerDocument )
+	{
+		if ( typeof text == 'string' )
+			text = ( ownerDocument ? ownerDocument.$ : document ).createComment( text );
+
+		this.base( text );
+	},
+	
+	proto :
+	{
+		type : CKEDITOR.NODE_COMMENT,
+		
+		getOuterHtml : function()
+		{
+			return '<!--' + this.$.nodeValue + '-->';
+		}
+	}
+});
Index: /CKEditor/branches/versions/3.1.x/_source/core/htmlparser/element.js
===================================================================
--- /CKEditor/branches/versions/3.1.x/_source/core/htmlparser/element.js	(revision 4555)
+++ /CKEditor/branches/versions/3.1.x/_source/core/htmlparser/element.js	(revision 4556)
@@ -35,6 +35,8 @@
 	this.children = [];
 
+	var tagName = attributes._cke_real_element_type || name;
+
 	var dtd			= CKEDITOR.dtd,
-		isBlockLike	= !!( dtd.$block[ name ] || dtd.$listItem[ name ] || dtd.$tableContent[ name ] || dtd.$nonEditable[ name ] || name == 'br' ),
+		isBlockLike	= !!( dtd.$block[ tagName ] || dtd.$listItem[ tagName ] || dtd.$tableContent[ tagName ] || dtd.$nonEditable[ tagName ] || tagName == 'br' ),
 		isEmpty		= !!dtd.$empty[ name ];
 
@@ -128,4 +130,12 @@
 						break;
 
+					// If the element has been replaced with something of a
+					// different type, then make the replacement write itself.
+					if ( element.type != CKEDITOR.NODE_ELEMENT )
+					{
+						element.writeHtml( writer, filter );
+						return;
+					}
+
 					writeName = element.name;
 					if ( !writeName )	// Send children.
Index: /CKEditor/branches/versions/3.1.x/_source/core/htmlparser/filter.js
===================================================================
--- /CKEditor/branches/versions/3.1.x/_source/core/htmlparser/filter.js	(revision 4555)
+++ /CKEditor/branches/versions/3.1.x/_source/core/htmlparser/filter.js	(revision 4556)
@@ -89,9 +89,19 @@
 
 						if ( ret && ret != element )
-							return this.onElement( ret );
+							return this.onNode( ret );
 					}
 				}
 
 				return element;
+			},
+
+			onNode : function( node )
+			{
+				var type = node.type;
+				
+				return type == CKEDITOR.NODE_ELEMENT ? this.onElement( node ) :
+					type == CKEDITOR.NODE_TEXT ? new CKEDITOR.htmlParser.text( this.onText( node.value ) ) :
+					type == CKEDITOR.NODE_COMMENT ? new CKEDITOR.htmlParser.comment( this.onComment( node.value ) ):
+					null;
 			},
 
Index: /CKEditor/branches/versions/3.1.x/_source/core/loader.js
===================================================================
--- /CKEditor/branches/versions/3.1.x/_source/core/loader.js	(revision 4555)
+++ /CKEditor/branches/versions/3.1.x/_source/core/loader.js	(revision 4556)
@@ -24,5 +24,5 @@
 		var scripts =
 		{
-			'core/_bootstrap'		: [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/elementpath', 'core/dom/text', 'core/dom/range' ],
+			'core/_bootstrap'		: [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/comment', 'core/dom/elementpath', 'core/dom/text', 'core/dom/range' ],
 			'core/ajax'				: [ 'core/xml' ],
 			'core/ckeditor'			: [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/htmlparser/filter', 'core/htmlparser/basicwriter', 'core/tools' ],
@@ -32,4 +32,5 @@
 			'core/config'			: [ 'core/ckeditor_base' ],
 			'core/dom'				: [],
+			'core/dom/comment'		: [ 'core/dom/node' ],
 			'core/dom/document'		: [ 'core/dom', 'core/dom/domobject', 'core/dom/window' ],
 			'core/dom/documentfragment'	: [ 'core/dom/element' ],
Index: /CKEditor/branches/versions/3.1.x/_source/plugins/fakeobjects/plugin.js
===================================================================
--- /CKEditor/branches/versions/3.1.x/_source/plugins/fakeobjects/plugin.js	(revision 4555)
+++ /CKEditor/branches/versions/3.1.x/_source/plugins/fakeobjects/plugin.js	(revision 4556)
@@ -16,9 +16,8 @@
 					realElement = realFragment && realFragment.children[ 0 ];
 
-				if ( realElement )
+				// If we have width/height in the element, we must move it into
+				// the real element.
+				if ( realElement && element.attributes._cke_resizable )
 				{
-					// If we have width/height in the element, we must move it into
-					// the real element.
-
 					var style = element.attributes.style;
 
@@ -64,4 +63,5 @@
 {
 	var lang = this.lang.fakeobjects;
+
 	var attributes =
 	{
@@ -69,8 +69,11 @@
 		src : CKEDITOR.getUrl( 'images/spacer.gif' ),
 		_cke_realelement : encodeURIComponent( realElement.getOuterHtml() ),
+		_cke_real_node_type : realElement.type,
 		alt : lang[ realElementType ] || lang.unknown
 	};
+
 	if ( realElementType )
 		attributes._cke_real_element_type = realElementType;
+
 	if ( isResizable )
 		attributes._cke_resizable = isResizable;
@@ -81,10 +84,10 @@
 CKEDITOR.editor.prototype.createFakeParserElement = function( realElement, className, realElementType, isResizable )
 {
+	var lang = this.lang.fakeobjects, 
+		html, writer;
+
 	var writer = new CKEDITOR.htmlParser.basicWriter();
-
 	realElement.writeHtml( writer );
-
-	var html = writer.getHtml();
-	var lang = this.lang.fakeobjects;
+	html = writer.getHtml();
 
 	var attributes =
@@ -93,4 +96,5 @@
 		src : CKEDITOR.getUrl( 'images/spacer.gif' ),
 		_cke_realelement : encodeURIComponent( html ),
+		_cke_real_node_type : realElement.type,
 		alt : lang[ realElementType ] || lang.unknown
 	};
@@ -107,5 +111,9 @@
 CKEDITOR.editor.prototype.restoreRealElement = function( fakeElement )
 {
-	var html = decodeURIComponent( fakeElement.getAttribute( '_cke_realelement' ) );
-	return CKEDITOR.dom.element.createFromHtml( html, this.document );
+	if ( fakeElement.getAttribute( '_cke_real_node_type' ) != CKEDITOR.NODE_ELEMENT )
+		return null;
+
+	return CKEDITOR.dom.element.createFromHtml( 
+		decodeURIComponent( fakeElement.getAttribute( '_cke_realelement' ) ), 
+		this.document );
 };
Index: /CKEditor/branches/versions/3.1.x/_source/plugins/htmldataprocessor/plugin.js
===================================================================
--- /CKEditor/branches/versions/3.1.x/_source/plugins/htmldataprocessor/plugin.js	(revision 4555)
+++ /CKEditor/branches/versions/3.1.x/_source/plugins/htmldataprocessor/plugin.js	(revision 4556)
@@ -11,5 +11,4 @@
 
 	var protectedSourceMarker = '{cke_protected}';
-
 
 	// Return the last non-space child node of the block (#4344).
@@ -178,6 +177,15 @@
 			comment : function( contents )
 			{
+				// If this is a comment for protected source.
 				if ( contents.substr( 0, protectedSourceMarker.length ) == protectedSourceMarker )
-					return new CKEDITOR.htmlParser.cdata( decodeURIComponent( contents.substr( protectedSourceMarker.length ) ) );
+				{
+					// Remove the extra marker for real comments from it.
+					if ( contents.substr( protectedSourceMarker.length, 3 ) == '{C}' )
+						contents = contents.substr( protectedSourceMarker.length + 3 );
+					else
+						contents = contents.substr( protectedSourceMarker.length );
+
+					return new CKEDITOR.htmlParser.cdata( decodeURIComponent( contents ) );
+				}
 
 				return contents;
@@ -240,14 +248,30 @@
 	}
 
+	function unprotectRealComments( html )
+	{
+		return html.replace( /<!--{cke_protected}{C}([\s\S]+?)-->/g, function( match, data )
+			{
+				return decodeURIComponent( data );
+			});
+	}
+
+	function protectRealComments( html )
+	{
+		return html.replace( /<!--(?!{cke_protected})[\s\S]+?-->/g, function( match )
+			{
+				return '<!--' + protectedSourceMarker +
+						'{C}' +
+						encodeURIComponent( match ).replace( /--/g, '%2D%2D' ) +
+						'-->';
+			});
+	}
+
 	function protectSource( data, protectRegexes )
 	{
 		var protectedHtml = [],
-			tempRegex = /<\!--\{cke_temp\}(\d*?)-->/g;
+			tempRegex = /<\!--\{cke_temp(comment)?\}(\d*?)-->/g;
+
 		var regexes =
 			[
-				// First of any other protection, we must protect all comments
-				// to avoid loosing them (of course, IE related).
-				(/<!--[\s\S]*?-->/g),
-
 				// Script tags will also be forced to be protected, otherwise
 				// IE will execute them.
@@ -259,4 +283,13 @@
 			.concat( protectRegexes );
 
+		// First of any other protection, we must protect all comments
+		// to avoid loosing them (of course, IE related).
+		// Note that we use a different tag for comments, as we need to
+		// transform them when applying filters.
+		data = data.replace( (/<!--[\s\S]*?-->/g), function( match )
+			{
+				return  '<!--{cke_tempcomment}' + ( protectedHtml.push( match ) - 1 ) + '-->';
+			});
+
 		for ( var i = 0 ; i < regexes.length ; i++ )
 		{
@@ -264,5 +297,5 @@
 				{
 					match = match.replace( tempRegex, 		// There could be protected source inside another one. (#3869).
-						function( $, id )
+						function( $, isComment, id )
 						{
 							return protectedHtml[ id ];
@@ -272,7 +305,8 @@
 				});
 		}
-		data = data.replace( tempRegex,	function( $, id )
+		data = data.replace( tempRegex,	function( $, isComment, id )
 			{
 				return '<!--' + protectedSourceMarker +
+						( isComment ? '{C}' : '' ) +
 						encodeURIComponent( protectedHtml[ id ] ).replace( /--/g, '%2D%2D' ) +
 						'-->';
@@ -344,4 +378,8 @@
 				data = unprotectEncodedTags( data );
 
+			// Restore the comments that have been protected, in this way they
+			// can be properly filtered.
+			data = unprotectRealComments( data );
+
 			// Now use our parser to make further fixes to the structure, as
 			// well as apply the filter.
@@ -350,6 +388,10 @@
 
 			fragment.writeHtml( writer, this.dataFilter );
-
-			return writer.getHtml( true );
+			data = writer.getHtml( true );
+
+			// Protect the real comments again.
+			data = protectRealComments( data );
+
+			return data;
 		},
 
