Index: editor/_source/internals/fckxhtml.js
===================================================================
--- editor/_source/internals/fckxhtml.js	(revision 1214)
+++ editor/_source/internals/fckxhtml.js	(working copy)
@@ -30,6 +30,9 @@
 	FCKDomTools.CheckAndRemovePaddingNode( node.ownerDocument, FCKConfig.EnterMode ) ;
 	FCKXHtmlEntities.Initialize() ;
 
+	// Random ID for protected attributes.
+	this._ProtectID = Math.random() ;
+
 	// Set the correct entity to use for empty blocks.
 	this._NbspEntity = ( FCKConfig.ProcessHTMLEntities? 'nbsp' : '#160' ) ;
 
@@ -484,3 +487,100 @@
 } ;
 
 FCKXHtml.TagProcessors.ul = FCKXHtml.TagProcessors.ol ;
+
+FCKXHtml.AttributeProcessors =
+{
+	style : function( node, htmlNode, attrValue )
+	{
+		var borderPattern = /border[a-zA-Z-]*\s*:[^;]+(;|$)\s*/g ;
+		
+		if ( attrValue.match( borderPattern ) )
+		{
+			// Remove all border attributes from the style string.
+			attrValue = attrValue.replace( borderPattern, '' ) ;
+			var oldAttrValue = attrValue ;
+
+			// Calculate the most compact border style representation.
+			// 1. Start from the 12 basic border-[DIRECTION]-[STYLE] values.
+			// 2. If [STYLE] has the same value for all [DIRECTION]s, compress to a single border-[STYLE] value,
+			// 	and eliminate the redundant values.
+			// 3. If any border-[DIRECTION] or border have all 3 [STYLE]s under it, compress the [STYLES]s to
+			// 	a single string and eliminate the redundant values.
+			var directions = ['top', 'right', 'bottom', 'left'] ;
+			var styles = ['width', 'style', 'color'] ;
+			var borderStyle = {} ;
+			for ( var i = 0 ; i < directions.length ; i++ )
+			{
+				for ( var j = 0 ; j < styles.length ; j++ )
+				{
+					var cssName = ['border', directions[i], styles[j]].join( '-' ) ;
+					var jsName = ['border', directions[i].charAt(0).toUpperCase() + directions[i].substr(1),
+					    styles[j].charAt(0).toUpperCase() + styles[j].substr(1)].join( '' ) ;
+					borderStyle[cssName] = FCKDomTools.GetCurrentElementStyle( FCKTools.GetElementWindow( htmlNode ), 
+							htmlNode, jsName ) ;
+					if ( styles[j] == 'color' )
+						borderStyle[cssName] = FCKTools.RGBToHex( borderStyle[cssName] ) ;
+				}
+			}
+
+			for ( var i = 0 ; i < styles.length ; i++ )
+			{
+				var isEqual = true ;
+				var lastValue = null ;
+				for ( var j = 0 ; j < directions.length ; j++ )
+				{
+					var cssName = ['border', directions[j], styles[i]].join( '-' ) ;
+					if ( lastValue == null )
+						lastValue = borderStyle[cssName] ;
+					if ( lastValue != borderStyle[cssName] )
+					{
+						isEqual = false ;
+						break ;
+					}
+				}
+				if ( isEqual )
+				{
+					borderStyle['border-' + styles[i]] = lastValue ;
+					for ( var j = 0 ; j < directions.length ; j++ )
+						delete borderStyle[['border', directions[j], styles[i]].join( '-' )] ;
+				}
+			}
+
+			for ( var i = 0 ; i < directions.length ; i++ )
+			{
+				if ( borderStyle['border-' + directions[i] + '-width'] &&
+						borderStyle['border-' + directions[i] + '-style'] &&
+						borderStyle['border-' + directions[i] + '-color'])
+				{
+					borderStyle['border-' + directions[i]] = borderStyle['border-' + directions[i] + '-width'] + ' '
+						+ borderStyle['border-' + directions[i] + '-style'] + ' '
+						+ borderStyle['border-' + directions[i] + '-color'] ;
+					delete borderStyle['border-' + directions[i] + '-width'] ;
+					delete borderStyle['border-' + directions[i] + '-style'] ;
+					delete borderStyle['border-' + directions[i] + '-color'] ;
+				}
+			}
+
+			if ( borderStyle['border-width'] && borderStyle['border-style'] && borderStyle['border-color'] )
+			{
+				borderStyle['border'] = borderStyle['border-width'] + ' ' 
+					+ borderStyle['border-style'] + ' '
+					+ borderStyle['border-color'] ;
+				delete borderStyle['border-width'] ;
+				delete borderStyle['border-style'] ;
+				delete borderStyle['border-color'] ;
+			}
+
+			// Calculate the style string fragment according to the minimal representation and append it
+			// to the attrValue.
+			var fragment = [] ;
+			for ( var i in borderStyle )
+				fragment.push( i + ': ' + borderStyle[i] ) ;
+			fragment = ' ' + fragment.join( '; ' ) + ';' ;
+			attrValue += fragment ;
+			attrValue = attrValue.Trim() ;
+		}
+
+		FCKXHtml._AppendAttribute( node, 'style_protected_' + FCKXHtml._ProtectID , attrValue ) ;
+	}
+} ;
Index: editor/_source/internals/fcktools.js
===================================================================
--- editor/_source/internals/fcktools.js	(revision 1214)
+++ editor/_source/internals/fcktools.js	(working copy)
@@ -619,3 +619,24 @@
 {
   return function() { obj[methodName].apply(obj, arguments); } ;
 }
+
+/**
+ * Convert a CSS rgb(R, G, B) color back to #RRGGBB format.
+ */
+FCKTools.RGBToHex = function( rgb )
+{
+	var matchResults = rgb.match( /(rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\))/i ) ;
+	if ( !matchResults )
+		return rgb ;
+
+	var red = parseInt( matchResults[2], 10 ).toString( 16 ),
+	    green = parseInt( matchResults[3], 10 ).toString( 16 ),
+	    blue = parseInt( matchResults[4], 10 ).toString( 16 ) ;
+	var color = [red, green, blue] ;
+	
+	// Add padding zeros if the hex value is less than 0x10.
+	for ( var i = 0 ; i < color.length ; i++ )
+		color[i] = String( '0' + color[i] ).slice( -2 ) ;
+
+	return '#' + color.join( '' ) ;
+}
Index: editor/_source/internals/fckxhtml_gecko.js
===================================================================
--- editor/_source/internals/fckxhtml_gecko.js	(revision 1214)
+++ editor/_source/internals/fckxhtml_gecko.js	(working copy)
@@ -24,7 +24,8 @@
 
 FCKXHtml._GetMainXmlString = function()
 {
-	return '<xhtml>' + this.MainNode.innerHTML + '</xhtml>' ;
+	var html = this.MainNode.innerHTML.replace( new RegExp( '_protected_' + this._ProtectID, 'g' ), '' ) ;
+	return '<xhtml>' + html + '</xhtml>' ;
 }
 
 FCKXHtml._AppendAttributes = function( xmlNode, htmlNode, node )
@@ -60,7 +61,10 @@
 			else
 				sAttValue = htmlNode.getAttribute( sAttName, 2 ) ;	// We must use getAttribute to get it exactly as it is defined.
 
-			this._AppendAttribute( node, sAttName, sAttValue ) ;
+			if ( this.AttributeProcessors[sAttName] )
+				this.AttributeProcessors[sAttName]( node, htmlNode, sAttValue ) ;
+			else
+				this._AppendAttribute( node, sAttName, sAttValue ) ;
 		}
 	}
 }
Index: editor/_source/internals/fckxhtml_ie.js
===================================================================
--- editor/_source/internals/fckxhtml_ie.js	(revision 1214)
+++ editor/_source/internals/fckxhtml_ie.js	(working copy)
@@ -24,7 +24,8 @@
 
 FCKXHtml._GetMainXmlString = function()
 {
-	return this.MainNode.xml ;
+	var html = this.MainNode.xml.replace( new RegExp( '_protected_' + this._ProtectID, 'g' ), '' ) ;
+	return html ;
 }
 
 FCKXHtml._AppendAttributes = function( xmlNode, htmlNode, node, nodeName )
@@ -77,7 +78,10 @@
 				}
 				catch (e) {}
 			}
-			this._AppendAttribute( node, sAttName, sAttValue || oAttribute.nodeValue ) ;
+			if ( this.AttributeProcessors[sAttName] )
+				this.AttributeProcessors[sAttName]( node, htmlNode, sAttValue) ;
+			else
+				this._AppendAttribute( node, sAttName, sAttValue || oAttribute.nodeValue ) ;
 		}
 	}
 }
@@ -200,4 +204,4 @@
 	node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
 
 	return node ;
-}
\ No newline at end of file
+}
Index: editor/dialog/fck_tablecell.html
===================================================================
--- editor/dialog/fck_tablecell.html	(revision 1214)
+++ editor/dialog/fck_tablecell.html	(working copy)
@@ -64,6 +64,10 @@
 		if ( oCell.attributes['noWrap'] != null && oCell.attributes['noWrap'].specified )
 			GetE('selWordWrap').value = !oCell.noWrap ;
 
+		var sBorderColor = oCell.style.borderColor ;
+		var matchResults = null ;
+		sBorderColor = oEditor.FCKTools.RGBToHex( sBorderColor ) ;
+
 		GetE('txtWidth').value			= iWidth ;
 		GetE('txtHeight').value			= GetAttribute( oCell, 'height' ) ;
 		GetE('selHAlign').value			= GetAttribute( oCell, 'align' ) ;
@@ -71,7 +75,7 @@
 		GetE('txtRowSpan').value		= GetAttribute( oCell, 'rowSpan' ) ;
 		GetE('txtCollSpan').value		= GetAttribute( oCell, 'colSpan' ) ;
 		GetE('txtBackColor').value		= GetAttribute( oCell, 'bgColor' ) ;
-		GetE('txtBorderColor').value	= GetAttribute( oCell, 'borderColor' ) ;
+		GetE('txtBorderColor').value	= sBorderColor ;
 //		GetE('cmbFontStyle').value		= oCell.className ;
 	}
 }
@@ -97,7 +101,21 @@
 		SetAttribute( aCells[i], 'rowSpan'		, GetE('txtRowSpan').value ) ;
 		SetAttribute( aCells[i], 'colSpan'		, GetE('txtCollSpan').value ) ;
 		SetAttribute( aCells[i], 'bgColor'		, GetE('txtBackColor').value ) ;
-		SetAttribute( aCells[i], 'borderColor'	, GetE('txtBorderColor').value ) ;
+
+		var sBorderColor = GetE( 'txtBorderColor' ).value ;
+		if ( sBorderColor.length > 0 )
+		{
+			var borderStyle = {'borderColor' : sBorderColor} ;
+			var presentStyle = oEditor.FCKDomTools.GetCurrentElementStyle( oEditor.FCKTools.GetElementWindow( aCells[i] ), aCells[i] , 'borderTopStyle' ) ;
+			if ( presentStyle.match( /^(none|.*inset.*)$/ ) )
+			{
+				borderStyle.borderWidth = '1px' ;
+				borderStyle.borderStyle = 'solid' ;
+			}
+			oEditor.FCKDomTools.SetElementStyles( aCells[i], borderStyle ) ;
+		}
+		else
+			aCells[i].style.border = 'default' ;
 //		SetAttribute( aCells[i], 'className'	, GetE('cmbFontStyle').value ) ;
 	}
 
