Index: /CKEditor/trunk/_source/core/config.js
===================================================================
--- /CKEditor/trunk/_source/core/config.js	(revision 3042)
+++ /CKEditor/trunk/_source/core/config.js	(revision 3043)
@@ -147,5 +147,5 @@
 	 * config.plugins = 'basicstyles,button,htmldataprocessor,toolbar,wysiwygarea';
 	 */
-	plugins : 'basicstyles,button,elementspath,horizontalrule,htmldataprocessor,keystrokes,newpage,removeformat,smiley,sourcearea,specialchar,tab,toolbar,wysiwygarea',
+	plugins : 'basicstyles,button,elementspath,horizontalrule,htmldataprocessor,keystrokes,newpage,pagebreak,removeformat,smiley,sourcearea,specialchar,tab,toolbar,wysiwygarea',
 
 	/**
Index: /CKEditor/trunk/_source/core/dom/element.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/element.js	(revision 3042)
+++ /CKEditor/trunk/_source/core/dom/element.js	(revision 3043)
@@ -260,4 +260,14 @@
 		},
 
+		getOuterHtml : function()
+		{
+			if ( this.$.outerHTML )
+				return this.$.outerHTML;
+			
+			var tmpDiv = this.$.ownerDocument.createElement( 'div' );
+			tmpDiv.appendChild( this.$.cloneNode( true ) );
+			return tmpDiv.innerHTML;
+		},
+
 		/**
 		 * Sets the inner HTML of this element.
@@ -562,4 +572,9 @@
 			var $ = this.$.nextSibling;
 			return $ ? new CKEDITOR.dom.node( $ ) : null;
+		},
+
+		getStyle : function( name )
+		{
+			return this.$.style[ CKEDITOR.tools.cssStyleToDomStyle( name ) ];
 		},
 
Index: /CKEditor/trunk/_source/core/dom/node.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/node.js	(revision 3042)
+++ /CKEditor/trunk/_source/core/dom/node.js	(revision 3043)
@@ -417,4 +417,10 @@
 
 			return this;
+		},
+
+		replace : function( nodeToReplace )
+		{
+			this.insertBefore( nodeToReplace );
+			nodeToReplace.remove();
 		}
 	}
Index: /CKEditor/trunk/_source/core/editor.js
===================================================================
--- /CKEditor/trunk/_source/core/editor.js	(revision 3042)
+++ /CKEditor/trunk/_source/core/editor.js	(revision 3043)
@@ -265,4 +265,5 @@
 
 			this._.commands = {};
+			this._.styles = [];
 
 			/**
@@ -349,4 +350,9 @@
 		},
 
+		addCss : function( css )
+		{
+			this._.styles.push( css );
+		},
+
 		/**
 		 * Destroys the editor instance, releasing all resources used by it.
Index: /CKEditor/trunk/_source/core/htmlparser/element.js
===================================================================
--- /CKEditor/trunk/_source/core/htmlparser/element.js	(revision 3042)
+++ /CKEditor/trunk/_source/core/htmlparser/element.js	(revision 3043)
@@ -14,4 +14,10 @@
 CKEDITOR.htmlParser.element = function( name, attributes )
 {
+	if ( attributes._cke_saved_src )
+		attributes.src = attributes._cke_saved_src;
+
+	if ( attributes._cke_saved_href )
+		attributes.href = attributes._cke_saved_href;
+
 	/**
 	 * The element name.
@@ -98,4 +104,23 @@
 		writeHtml : function( writer )
 		{
+			var attributes = this.attributes;
+			
+			// The "_cke_realelement" attribute indicates that the current
+			// element is a placeholder for another element.
+			if ( attributes._cke_realelement )
+			{
+				var realFragment = new CKEDITOR.htmlParser.fragment.fromHtml( decodeURIComponent( attributes._cke_realelement ) );
+				realFragment.writeHtml( writer );
+				return;
+			}
+			
+			// 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;
+			}
+		
 			// Open element tag.
 			writer.openTag( this.name, this.attributes );
@@ -103,6 +128,10 @@
 			// Copy all attributes to an array.
 			var attribsArray = [];
-			for ( var a in this.attributes )
-				attribsArray.push( [ a, this.attributes[ a ] ] );
+			for ( var a in attributes )
+			{
+				// Ignore all attributes starting with "_cke".
+				if ( !/^_cke/.test( a ) )
+					attribsArray.push( [ a, this.attributes[ a ] ] );
+			}
 
 			// Sort the attributes by name.
@@ -113,7 +142,4 @@
 			{
 				var attrib = attribsArray[ i ];
-				// IE's treated expand fields as dom attributes, skip it
-				if ( CKEDITOR.env.ie && attrib === '_cke_expando' )
-					continue;
 				writer.attribute( attrib[0], attrib[1] );
 			}
Index: /CKEditor/trunk/_source/plugins/fakeobjects/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/fakeobjects/plugin.js	(revision 3043)
+++ /CKEditor/trunk/_source/plugins/fakeobjects/plugin.js	(revision 3043)
@@ -0,0 +1,19 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.plugins.add( 'fakeobjects' );
+
+CKEDITOR.editor.prototype.createFakeElement = function( realElement, className )
+{
+	return this.document.createElement( 'img',
+		{
+			attributes :
+				{
+					'class' : className,
+					src : CKEDITOR.getUrl( 'images/spacer.gif' ),
+					_cke_realelement : encodeURIComponent( realElement.getOuterHtml() )
+				}
+		});
+};
Index: /CKEditor/trunk/_source/plugins/htmlwriter/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/htmlwriter/plugin.js	(revision 3042)
+++ /CKEditor/trunk/_source/plugins/htmlwriter/plugin.js	(revision 3043)
@@ -226,5 +226,5 @@
 	 * Writes the current indentation chars. It uses the
 	 * {@link #indentationChars} property, repeating it for the current
-	 * intentation steps.
+	 * indentation steps.
 	 * @example
 	 * // Writes "\t" (e.g.).
@@ -235,4 +235,14 @@
 		this._.output.push( this._.indentation );
 		this._.indent = false;
+	},
+
+	/**
+	 * Writes any kind of data to the ouput.
+	 * @example
+	 * writer.write( 'This is an &lt;b&gt;example&lt;/b&gt;.' );
+	 */
+	write : function( data )
+	{
+		this._.output.push( data );
 	},
 
Index: /CKEditor/trunk/_source/plugins/pagebreak/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/pagebreak/plugin.js	(revision 3043)
+++ /CKEditor/trunk/_source/plugins/pagebreak/plugin.js	(revision 3043)
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @file Horizontal Page Break
+ */
+
+// Register a plugin named "pagebreak".
+CKEDITOR.plugins.add( 'pagebreak',
+{
+	init : function( editor )
+	{
+		// Register the command.
+		editor.addCommand( 'pagebreak', CKEDITOR.plugins.pagebreakCmd );
+		
+		// Register the toolbar button.
+		editor.ui.addButton( 'PageBreak',
+			{
+				label : editor.lang.pagebreak,
+				command : 'pagebreak'
+			});
+		
+		// Add the style that renders our placeholder.
+		editor.addCss(
+			'img.cke_pagebreak' +
+			'{' +
+				'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/pagebreak.gif' ) + ');' +
+				'background-position: center center;' +
+				'background-repeat: no-repeat;' +
+				'clear: both;' +
+				'display: block;' +
+				'float: none;' +
+				'width: 100%;' +
+				'border-top: #999999 1px dotted;' +
+				'border-bottom: #999999 1px dotted;' +
+				'height: 5px;' +
+
+			'}' );
+		
+		// Listen for the "contentDom" event, so the document can be fixed to
+		// display the placeholders.
+		editor.on( 'contentDom', function()
+			{
+				var divs = editor.document.getBody().getElementsByTag( 'div' );
+				for ( var div, i = 0, length = divs.count() ; i < length ; i++ )
+				{
+					div = divs.getItem( i );
+					if ( div.getStyle( 'page-break-after' ) == 'always' && !/[^\s\u00A0]/.test( div.getText() ) )
+					{
+						editor.createFakeElement( div, 'cke_pagebreak' ).replace( div );
+					}
+				}
+			});
+	},
+	requires : [ 'fakeobjects' ]
+});
+
+CKEDITOR.plugins.pagebreakCmd =
+{
+	exec : function( editor )
+	{
+		// Create the element that represents a print break.
+		var breakObject = CKEDITOR.dom.element.createFromHtml( '<div style="page-break-after: always;"><span style="display: none;">&nbsp;</span></div>' );
+		
+		// Creates the fake image used for this element.
+		breakObject = editor.createFakeElement( breakObject, 'cke_pagebreak' );
+		
+		var ranges = editor.getSelection().getRanges();
+		
+		for ( var range, i = 0 ; i < ranges.length ; i++ )
+		{
+			range = ranges[ i ];
+
+			if ( i > 0 )
+				breakObject = breakObject.clone( true );
+
+			range.splitBlock( 'p' );
+			range.insertNode( breakObject );
+		}
+	}
+};
Index: /CKEditor/trunk/_source/plugins/toolbar/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 3042)
+++ /CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 3043)
@@ -212,5 +212,5 @@
 		'Subscript', 'Superscript', '-',
 		'SelectAll', 'RemoveFormat', '-',
-		'Smiley', 'HorizontalRule', 'SpecialChar'
+		'Smiley', 'HorizontalRule', 'SpecialChar', 'PageBreak'
 	]
 ];
Index: /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js	(revision 3042)
+++ /CKEditor/trunk/_source/plugins/wysiwygarea/plugin.js	(revision 3043)
@@ -45,24 +45,19 @@
 
 	// #### protectAttributes - START
+	
+	// TODO: Clean and simplify these regexes.
 	var protectUrlTagRegex = /<(?:a|area|img)(?=\s).*?\s(?:href|src)=((?:(?:\s*)("|').*?\2)|(?:[^"'][^ >]+))/gi,
-		protectUrlAttributeRegex = /\s(href|src)(\s*=\s*?('|")[\s\S]*?\3)/gi,
-		protectedUrlTagRegex = /<(?:a|area|img)(?=\s)(?:"[^"]*"|'[^']*'|[^<])*>/gi,
-		protectedAttributeRegex = /_cke_saved_/gi,
-		protectUrls = function( html )
-		{
-			return html.replace( protectUrlTagRegex, protectUrls_ReplaceTags );
-		},
-		protectUrls_ReplaceTags = function( tagMatch )
-		{
-			return tagMatch.replace( protectUrlAttributeRegex, '$& _cke_saved_$1$2');
-		},
-		protectUrlsRestore = function( html )
-		{
-			return html.replace( protectedUrlTagRegex, protectUrlsRestore_ReplaceTags );
-		},
-		protectUrlsRestore_ReplaceTags = function( tagMatch )
-		{
-			return tagMatch.replace( protectUrlAttributeRegex, '' ).replace( protectedAttributeRegex, '' );
-		};
+		protectUrlAttributeRegex = /\s(href|src)(\s*=\s*?('|")[\s\S]*?\3)/gi;
+	
+	var protectUrls = function( html )
+	{
+		return html.replace( protectUrlTagRegex, protectUrls_ReplaceTags );
+	};
+
+	var protectUrls_ReplaceTags = function( tagMatch )
+	{
+		return tagMatch.replace( protectUrlAttributeRegex, '$& _cke_saved_$1$2');
+	};
+
 	// #### protectAttributes - END
 
@@ -301,8 +296,4 @@
 								data = protectUrls( data );
 
-								// Replace tags with fake elements.
-								if ( editor.fakeobjects )
-									data = editor.fakeobjects.protectHtml( data );
-
 								data =
 									editor.config.docType +
@@ -310,4 +301,7 @@
 									'<head>' +
 										'<link href="' + editor.config.contentsCss + '" type="text/css" rel="stylesheet" _fcktemp="true"/>' +
+										'<style type="text/css" _fcktemp="true">' +
+											editor._.styles.join( '\n' ) +
+										'</style>'+
 									'</head>' +
 									'<body>' +
@@ -356,11 +350,4 @@
 								// Restore protected attributes.
 								data = protectEventsRestore( data );
-
-								// Restore protected URLs.
-								data = protectUrlsRestore( data );
-
-								// Restore fake elements.
-								if ( editor.fakeobjects )
-									data = editor.fakeobjects.restoreHtml( data );
 
 								return data;
Index: /CKEditor/trunk/contents.css
===================================================================
--- /CKEditor/trunk/contents.css	(revision 3042)
+++ /CKEditor/trunk/contents.css	(revision 3043)
@@ -13,37 +13,2 @@
 	background-color: #fff;
 }
-
-/* The following declarations are to be removed from this file (#2786) */
-
-img.cke_fakeobject
-{
-	background-position: center center;
-	background-repeat: no-repeat;
-	border: 1px solid #a9a9a9;
-	width: 80px;
-	height: 80px;
-}
-
-img.cke_fakeobject.flash
-{
-	background-image: url(images/flashlogo.gif);
-}
-
-img.cke_fakeobject.object
-{
-	background-image: url(images/plugin.gif);
-}
-
-img.cke_fakeobject.anchor
-{
-	background-image: url(images/anchor.gif);
-	width: 18px;
-	height: 18px;
-}
-
-img.cke_fakeobject.pagebreak
-{
-	background-image: url(images/pagebreak.gif);
-	width: 100%;
-	height: 7px;
-}
