Index: /FCKeditor/trunk/editor/_source/classes/fckdomrange_ie.js
===================================================================
--- /FCKeditor/trunk/editor/_source/classes/fckdomrange_ie.js	(revision 864)
+++ /FCKeditor/trunk/editor/_source/classes/fckdomrange_ie.js	(revision 865)
@@ -114,13 +114,15 @@
 		bIsStartMakerAlone = ( !eStartMarker.previousSibling || eStartMarker.previousSibling.nodeName.toLowerCase() == 'br' ) && !eStartMarker.nextSibing ;
 		
+		// Append a temporary <span>&nbsp;</span> before the selection.
+		// This is needed to avoid IE destroying selections inside empty
+		// inline elements, like <b></b> (#253).
+		// It is also needed when placing the selection right after an inline
+		// element to avoid the selection moving inside of it.
+		dummySpan = this.Window.document.createElement( 'span' ) ;
+		dummySpan.innerHTML = '&nbsp;' ;
+		eStartMarker.parentNode.insertBefore( dummySpan, eStartMarker ) ;
+		
 		if ( bIsStartMakerAlone )
 		{
-			// Append a temporary <span>&nbsp;</span> before the selection.
-			// This is needed to avoid IE destroying selections inside empty
-			// inline elements, like <b></b> (#253).
-			dummySpan = this.Window.document.createElement( 'span' ) ;
-			dummySpan.innerHTML = '&nbsp;' ;
-			eStartMarker.parentNode.insertBefore( dummySpan, eStartMarker ) ;
-			
 			// To expand empty blocks or line spaces after <br>, we need
 			// instead to have a &nbsp;, which will be later deleted using the
@@ -148,8 +150,9 @@
 			// Remove our temporary stuff.
 			this.Window.document.selection.clear() ;
-			FCKDomTools.RemoveNode( dummySpan ) ;
 		}
 		else
 			oIERange.select() ;
+
+		FCKDomTools.RemoveNode( dummySpan ) ;
 	}
 	else
Index: /FCKeditor/trunk/editor/_source/classes/fckstyle.js
===================================================================
--- /FCKeditor/trunk/editor/_source/classes/fckstyle.js	(revision 864)
+++ /FCKeditor/trunk/editor/_source/classes/fckstyle.js	(revision 865)
@@ -157,5 +157,24 @@
 			var bookmark = range.CreateBookmark( true ) ;
 
-			var path = new FCKElementPath( range.StartNode || range.StartContainer ) ;
+			// Let's start from the bookmark <span> parent.
+			var bookmarkStart = range.GetBookmarkNode( bookmark, true ) ;
+
+			var path = new FCKElementPath( bookmarkStart.parentNode ) ;
+
+			// While looping through the path, we'll be saving references to
+			// parent elements if the range is in one of their boundaries. In
+			// this way, we are able to create a copy of those elements when
+			// removing a style if the range is in a boundary limit (see #1270).
+			var boundaryElements = [] ;
+
+			// Check if the range is in the boundary limits of an element
+			// (related to #1270).
+			var isBoundaryRight = !FCKDomTools.GetNextSibling( bookmarkStart ) ;
+			var isBoundary = isBoundaryRight || !FCKDomTools.GetPreviousSibling( bookmarkStart ) ;
+
+			// This is the last element to be removed in the boundary situation
+			// described at #1270.
+			var lastBoundaryElement ;
+			var boundaryLimitIndex = -1 ;
 
 			for ( var i = 0 ; i < path.Elements.length ; i++ )
@@ -164,27 +183,74 @@
 				if ( this.CheckElementRemovable( pathElement ) )
 				{
-					var pathElementName = pathElement.nodeName.toLowerCase() ;
-
-					if ( pathElementName == this.Element )
+					if ( isBoundary )
 					{
-						// Remove any attribute that conflict with this style, no
-						// matter their values.
-						for ( var att in styleAttribs )
+						lastBoundaryElement = pathElement ;
+						
+						// We'll be continuously including elements in the
+						// boundaryElements array, but only those added before
+						// setting lastBoundaryElement must be used later, so
+						// let's mark the current index here.
+						boundaryLimitIndex = boundaryElements.length - 1 ;
+					}
+					else
+					{
+						var pathElementName = pathElement.nodeName.toLowerCase() ;
+
+						if ( pathElementName == this.Element )
 						{
-							if ( FCKDomTools.HasAttribute( pathElement, att ) )
+							// Remove any attribute that conflict with this style, no
+							// matter their values.
+							for ( var att in styleAttribs )
 							{
-								if ( att == 'style' )
-									this._RemoveStylesFromElement( pathElement ) ;
-								else
-									FCKDomTools.RemoveAttribute( pathElement, att ) ;
+								if ( FCKDomTools.HasAttribute( pathElement, att ) )
+								{
+									if ( att == 'style' )
+										this._RemoveStylesFromElement( pathElement ) ;
+									else
+										FCKDomTools.RemoveAttribute( pathElement, att ) ;
+								}
 							}
 						}
+
+						// Remove overrides defined to the same element name.
+						this._RemoveOverrides( pathElement, styleOverrides[ pathElementName ] ) ;
+
+						// Remove the element if no more attributes are available.
+						this._RemoveNoAttribElement( pathElement ) ;
 					}
-
-					// Remove overrides defined to the same element name.
-					this._RemoveOverrides( pathElement, styleOverrides[ pathElementName ] ) ;
-
-					// Remove the element if no more attributes are available.
-					this._RemoveNoAttribElement( pathElement ) ;
+				}
+				else if ( isBoundary )
+					boundaryElements.push( pathElement ) ;
+
+				// Check if we are still in a boundary (at the same side).
+				isBoundary = isBoundary && ( ( isBoundaryRight && !FCKDomTools.GetNextSibling( pathElement ) ) || ( !isBoundaryRight && !FCKDomTools.GetPreviousSibling( pathElement ) ) ) ;
+
+				// If we are in an element that is not anymore a boundary, or
+				// we are at the last element, let's move things outside the
+				// boundary (if available).
+				if ( lastBoundaryElement && ( !isBoundary || ( i == path.Elements.length - 1 ) ) )
+				{
+					// Remove the bookmark node from the DOM.
+					var currentElement = FCKDomTools.RemoveNode( bookmarkStart ) ;
+
+					// Build the collapsed group of elements that are not
+					// removed by this style, but share the boundary.
+					// (see comment 1 and 2 at #1270)
+					for ( var i = 0 ; i <= boundaryLimitIndex ; i++ )
+					{
+						var newElement = FCKDomTools.CloneElement( boundaryElements[i] ) ;
+						newElement.appendChild( currentElement ) ;
+						currentElement = newElement ;
+					}
+
+					// Re-insert the bookmark node (and the collapsed elements)
+					// in the DOM, in the new position next to the styled element.
+					if ( isBoundaryRight )
+						FCKDomTools.InsertAfterNode( lastBoundaryElement, currentElement ) ;
+					else
+						lastBoundaryElement.parentNode.insertBefore( currentElement, lastBoundaryElement )
+
+					isBoundary = false ;
+					lastBoundaryElement = null ;
 				}
 			}
Index: /FCKeditor/trunk/editor/_source/internals/fckdomtools.js
===================================================================
--- /FCKeditor/trunk/editor/_source/internals/fckdomtools.js	(revision 864)
+++ /FCKeditor/trunk/editor/_source/internals/fckdomtools.js	(revision 865)
@@ -98,5 +98,5 @@
 				{
 					// If the trimmed text node is empty, just remove it.
-					
+
 					// Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#81).
 					eChildNode.parentNode.removeChild( eChildNode ) ;
@@ -120,5 +120,5 @@
 		{
 			eChildNode = node.lastChild ;
-			
+
 			if ( eChildNode && eChildNode.nodeType == 1 && eChildNode.nodeName.toLowerCase() == 'br' )
 			{
@@ -271,13 +271,13 @@
 
 		var node ;
-		
+
 		if ( !startFromSibling && currentNode.firstChild )
 			node = currentNode.firstChild ;
 		else
 			node = ( currentNode.nextSibling || this.GetNextSourceNode( currentNode.parentNode, true, nodeType ) ) ;
-		
+
 		if ( nodeType && node && node.nodeType != nodeType )
 			return this.GetNextSourceNode( node, false, nodeType ) ;
-		
+
 		return node ;
 	},
@@ -292,13 +292,13 @@
 
 		var node ;
-		
+
 		if ( !startFromSibling && currentNode.lastChild )
 			node = currentNode.lastChild ;
 		else
 			node = ( currentNode.previousSibling || this.GetPreviousSourceNode( currentNode.parentNode, true, nodeType ) ) ;
-		
+
 		if ( nodeType && node && node.nodeType != nodeType )
 			return this.GetPreviousSourceNode( node, false, nodeType ) ;
-		
+
 		return node ;
 	},
@@ -377,5 +377,5 @@
 	{
 		this.CheckAndRemovePaddingNode( doc, tagName, true ) ;
-		if ( doc.body.lastChild && ( doc.body.lastChild.nodeType != 1 
+		if ( doc.body.lastChild && ( doc.body.lastChild.nodeType != 1
 				|| doc.body.lastChild.tagName.toLowerCase() == tagName.toLowerCase() ) )
 			return ;
@@ -387,5 +387,5 @@
 				&& doc.body.firstChild.nodeType == 1
 				&& doc.body.firstChild.tagName.toLowerCase() == 'br'
-				&& ( doc.body.firstChild.getAttribute( '_moz_dirty' ) != null 
+				&& ( doc.body.firstChild.getAttribute( '_moz_dirty' ) != null
 					|| doc.body.firstChild.getAttribute( 'type' ) == '_moz' ) )
 			doc.body.replaceChild( node, doc.body.firstChild ) ;
@@ -446,5 +446,5 @@
 		return false ;
 	},
-	
+
 	/**
 	 * Remove an attribute from an element.
@@ -454,18 +454,18 @@
 		if ( FCKBrowserInfo.IsIE && attributeName.toLowerCase() == 'class' )
 			attributeName = 'className' ;
-		
+
 		return element.removeAttribute( attributeName ) ;
 	},
-	
-	
+
+
 	GetAttributeValue : function( element, att )
 	{
 		var attName = att ;
-		
+
 		if ( typeof att == 'string' )
 			att = element.attributes[ att ] ;
 		else
 			attName = att.nodeName ;
-		
+
 		if ( att && att.specified )
 		{
@@ -487,7 +487,7 @@
 		return null ;
 	},
-	
+
 	/**
-	 * Checks whether one element contains the other. 
+	 * Checks whether one element contains the other.
 	 */
 	Contains : function( mainElement, otherElement )
@@ -495,5 +495,5 @@
 		if ( mainElement.contains )
 			return mainElement.contains( otherElement ) ;
-		
+
 		while ( ( otherElement = otherElement.parentNode ) )	// Only one "="
 		{
@@ -503,5 +503,5 @@
 		return false ;
 	},
-	
+
 	/**
 	 * Breaks a parent element in the position of one of its contained elements.
@@ -515,13 +515,13 @@
 	{
 		var range = reusableRange || new FCKDomRange( FCKTools.GetElementWindow( element ) ) ;
-		
+
 		// We'll be extracting part of this element, so let's use our
 		// range to get the correct piece.
 		range.SetStart( element, 4 ) ;
 		range.SetEnd( parent, 4 ) ;
-		
+
 		// Extract it.
 		var docFrag = range.ExtractContents() ;
-		
+
 		// Move the element outside the broken element.
 		range.InsertNode( element.parentNode.removeChild( element ) ) ;
@@ -529,5 +529,5 @@
 		// Re-insert the extracted piece after the element.
 		docFrag.InsertAfterNode( element ) ;
-		
+
 		range.Release( !!reusableRange ) ;
 	},
@@ -566,12 +566,12 @@
 		return cursor ;
 	},
-	
+
 	CloneElement : function( element )
 	{
 		element = element.cloneNode( false ) ;
-		
+
 		// The "id" attribute should never be cloned to avoid duplication.
 		element.removeAttribute( 'id', false ) ;
-		
+
 		return element ;
 	},
@@ -710,4 +710,32 @@
 		}
 		return { 'listNode' : retval, 'nextIndex' : currentIndex } ;
+	},
+
+	/**
+	 * Get the next sibling node for a node. If "includeEmpties" is false,
+	 * only element or non empty text nodes are returned.
+	 */
+	GetNextSibling : function( node, includeEmpties )
+	{
+		node = node.nextSibling ;
+
+		while ( node && !includeEmpties && node.nodeType != 1 && ( node.nodeType != 3 || node.nodeValue.length == 0 ) )
+			node = node.nextSibling ;
+
+		return node ;
+	},
+
+	/**
+	 * Get the previous sibling node for a node. If "includeEmpties" is false,
+	 * only element or non empty text nodes are returned.
+	 */
+	GetPreviousSibling : function( node, includeEmpties )
+	{
+		node = node.previousSibling ;
+
+		while ( node && !includeEmpties && node.nodeType != 1 && ( node.nodeType != 3 || node.nodeValue.length == 0 ) )
+			node = node.previousSibling ;
+
+		return node ;
 	}
 } ;
