Пример #1
0
        internal bool RemoveCenteringNode()
        {
            MshtmlMarkupServices MarkupServices = new MshtmlMarkupServices(_element.document as IMarkupServicesRaw);
            IHTMLElement         element        = FindCenteringNode();

            // We couldnt find a parent, so nothing to remove
            if (element == null)
            {
                return(false);
            }


            MarkupPointer start  = MarkupServices.CreateMarkupPointer();
            MarkupPointer end    = MarkupServices.CreateMarkupPointer();
            MarkupPointer target = MarkupServices.CreateMarkupPointer();

            // Move the stuff inside the smart content container ouside of itself
            start.MoveAdjacentToElement(element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
            end.MoveAdjacentToElement(element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd);
            target.MoveAdjacentToElement(element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
            MarkupServices.Move(start, end, target);

            // remove the empty smart content container
            start.MoveAdjacentToElement(element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
            end.MoveAdjacentToElement(element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
            MarkupServices.Remove(start, end);

            return(true);
        }
Пример #2
0
        /// <summary>
        /// Searches through the provided document for a start and end comment marker and then returns the fragment as
        /// a MarkupRange.
        /// </summary>
        /// <param name="document">The document to search.</param>
        /// <param name="startMarker">The comment text that marks the start of the fragment
        /// (e.g. &lt;!--StartFragment--&gt; ).</param>
        /// <param name="endMarker">The comment text that marks the end of the fragment
        /// (e.g. &lt;!--EndFragment--&gt; ).</param>
        /// <returns>The fragment as a MarkupRange or null if no valid fragment was found.</returns>
        private MarkupRange FindMarkedFragment(IHTMLDocument2 document, string startMarker, string endMarker)
        {
            MarkupPointer        startFragment  = null;
            MarkupPointer        endFragment    = null;
            MshtmlMarkupServices markupServices = new MshtmlMarkupServices((IMarkupServicesRaw)document);

            // Look for the markers in the document.
            foreach (IHTMLElement element in document.all)
            {
                if (element is IHTMLCommentElement && ((IHTMLCommentElement)element).text == startMarker)
                {
                    startFragment = markupServices.CreateMarkupPointer(element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                }
                else if (element is IHTMLCommentElement && ((IHTMLCommentElement)element).text == endMarker)
                {
                    endFragment = markupServices.CreateMarkupPointer(element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                }
            }

            if (startFragment == null || endFragment == null || !startFragment.Positioned || !endFragment.Positioned ||
                startFragment.IsRightOf(endFragment))
            {
                Trace.WriteLine("Unable to find fragment or invalid fragment!");
                return(null);
            }

            // WinLive 251786: IE (and most other browsers) allow HTML like the following:
            //  <p>This is a paragraph[cursor]
            //  <p>This is a paragraph
            // However, when we use MarkupPointers to walk through this HTML, IE pretends there is a </p> at the end
            // of each of the above lines. This can cause issues when we copy part of this HTML somewhere else (e.g
            // everything after the [cursor]) and attempt to walk through both copies (e.g. during paste with keep
            // source formatting) at the same time. This holds true for some other elements, such as <li>s and <td>s.
            MarkupContext startContext = startFragment.Right(false);

            if (startFragment.IsLeftOf(endFragment) &&
                startContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope &&
                startContext.Element != null &&
                ElementFilters.IsEndTagOptional(startContext.Element) &&
                !Regex.IsMatch(startContext.Element.outerHTML,
                               String.Format(CultureInfo.InvariantCulture, @"</{0}(\s[^>]*)?>\s*$", startContext.Element.tagName),
                               RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
            {
                startFragment.Right(true);
            }

            return(markupServices.CreateMarkupRange(startFragment, endFragment));
        }
Пример #3
0
        /// <summary>
        /// Makes sure that whole (not parts of) lists are included in the source of a paste.
        /// </summary>
        /// <param name="range">The original source range. The range may be modified.</param>
        /// <param name="markupServices">MarkupServices for the range.</param>
        private void ExpandToIncludeLists(MarkupRange range, MshtmlMarkupServices markupServices)
        {
            MarkupPointer      pointer    = markupServices.CreateMarkupPointer();
            IHTMLElementFilter listFilter =
                ElementFilters.CreateCompoundElementFilter(ElementFilters.LIST_ELEMENTS, ElementFilters.LIST_ITEM_ELEMENTS);

            IHTMLElement[] listElements = range.GetElements(listFilter, false);
            foreach (IHTMLElement element in listElements)
            {
                IHTMLElement parentList = element;
                while (parentList != null && !ElementFilters.IsListElement(parentList))
                {
                    parentList = parentList.parentElement;
                }

                if (parentList != null)
                {
                    pointer.MoveAdjacentToElement(parentList, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                    if (range.Start.IsRightOf(pointer))
                    {
                        range.Start.MoveToPointer(pointer);
                    }

                    pointer.MoveAdjacentToElement(parentList, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                    if (range.End.IsLeftOf(pointer))
                    {
                        range.End.MoveToPointer(pointer);
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Makes sure that whole (not parts of) tables are included in the source of a paste.
        /// </summary>
        /// <param name="range">The original source range. The range may be modified.</param>
        /// <param name="markupServices">MarkupServices for the range.</param>
        private void ExpandToIncludeTables(MarkupRange range, MshtmlMarkupServices markupServices)
        {
            MarkupPointer pointer = markupServices.CreateMarkupPointer();

            IHTMLElement[] tableElements = range.GetElements(ElementFilters.TABLE_ELEMENTS, false);
            foreach (IHTMLElement element in tableElements)
            {
                IHTMLElement parentTable = element;
                while (parentTable != null && markupServices.GetElementTagId(parentTable) != _ELEMENT_TAG_ID.TAGID_TABLE)
                {
                    parentTable = parentTable.parentElement;
                }

                if (parentTable != null)
                {
                    pointer.MoveAdjacentToElement(parentTable, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                    if (range.Start.IsRightOf(pointer))
                    {
                        range.Start.MoveToPointer(pointer);
                    }

                    pointer.MoveAdjacentToElement(parentTable, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                    if (range.End.IsLeftOf(pointer))
                    {
                        range.End.MoveToPointer(pointer);
                    }
                }
            }
        }
Пример #5
0
        private IHTMLElement CreateNodeForCentering()
        {
            // Create markup services using the element's document that we are analyzing
            MshtmlMarkupServices MarkupServices = new MshtmlMarkupServices(_element.document as IMarkupServicesRaw);
            MarkupPointer        end            = MarkupServices.CreateMarkupPointer();
            MarkupPointer        start          = MarkupServices.CreateMarkupPointer();

            // Find the element that we will want to wrap.
            IHTMLElement elementToEncapsulate = _element;

            // If the elements parent is an A, we will also want to
            // wrap the A and not just the image inside
            if (_element.parentElement.tagName == "A")
            {
                elementToEncapsulate = _element.parentElement;
            }

            // Move the starting pointer to before the begining of the element we want to wrap
            start.MoveAdjacentToElement(elementToEncapsulate, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);

            // Find this elements parent
            IHTMLElement3 currentBlockScope = start.CurrentBlockScope() as IHTMLElement3;

            // If its parent is also the div that is around the post
            // we need to actually create a new div and just put it around the element

            // If it is splittable block, split it
            // e.g "<DIV>Blah<IMG/>Blah</DIV>" => "<DIV>Blah</DIV><DIV><IMG/></DIV><DIV>Blah</DIV>"
            if (!IsBodyElement(currentBlockScope))
            {
                // We are in a block that can be split so split it at the begining and end
                MarkupHelpers.SplitBlockForInsertionOrBreakout(MarkupServices, null, start);
                end.MoveAdjacentToElement(elementToEncapsulate, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                MarkupHelpers.SplitBlockForInsertionOrBreakout(MarkupServices, null, end);

                // Position start back to the beginning of our element
                start.MoveAdjacentToElement(elementToEncapsulate, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
            }

            // Now we can wrap it in an P tag (centering node)
            end.MoveAdjacentToElement(elementToEncapsulate, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
            IHTMLElement centeringElement = MarkupServices.CreateElement(_ELEMENT_TAG_ID.TAGID_P, string.Empty);

            MarkupServices.InsertElement(centeringElement, start, end);
            return(centeringElement);
        }
        /// <summary>
        /// Disambiguates a set of title regions to determine which should be editable based on proximity to the main post body element.
        /// </summary>
        /// <param name="bodyElement"></param>
        /// <param name="doc"></param>
        /// <param name="titleElements"></param>
        /// <returns>The title region in closest proximity to the post body element.</returns>
        protected static IHTMLElement GetPrimaryEditableTitleElement(IHTMLElement bodyElement, IHTMLDocument doc, IHTMLElement[] titleElements)
        {
            IHTMLDocument2 doc2         = (IHTMLDocument2)doc;
            IHTMLElement   titleElement = titleElements[0];

            if (titleElements.Length > 1)
            {
                try
                {
                    MshtmlMarkupServices markupServices = new MshtmlMarkupServices((IMarkupServicesRaw)doc2);
                    MarkupRange          bodyRange      = markupServices.CreateMarkupRange(bodyElement, true);
                    MarkupPointer        titlePointer   = null;
                    MarkupPointer        tempPointer    = markupServices.CreateMarkupPointer();
                    foreach (IHTMLElement title in titleElements)
                    {
                        tempPointer.MoveAdjacentToElement(title, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                        if (titlePointer == null)
                        {
                            titlePointer = markupServices.CreateMarkupPointer(title, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                        }
                        else
                        {
                            tempPointer.MoveAdjacentToElement(title, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                            if (tempPointer.IsLeftOf(bodyRange.End) && tempPointer.IsRightOf(titlePointer))
                            {
                                //the temp pointer is closer to the body element, so assume it is more appropriate
                                //to use as the title.
                                titleElement = title;
                                titlePointer.MoveToPointer(tempPointer);
                            }
                        }
                    }
                }
                catch (COMException ex)
                {
                    Trace.WriteLine("Failed to differentiate between multiple nodes with title text, using the first node.  Exception: " + ex);
                }
                catch (InvalidCastException ex)
                {
                    Trace.WriteLine("Failed to differentiate between multiple nodes with title text, using the first node.  Exception: " + ex);
                }
            }
            return(titleElement);
        }
Пример #7
0
        public MisspelledWordInfo FindSegment(MshtmlMarkupServices markupServices, IMarkupPointerRaw current)
        {
            //binary search
            int start = 0;
            int end   = list.Count - 1;
            int i     = Middle(start, end);

            while (-1 != i)
            {
                SegmentDef x = (SegmentDef)list.GetByIndex(i);
                bool       startTest;
                current.IsRightOfOrEqualTo(x.startPtr, out startTest);
                if (startTest)
                {
                    bool endTest;
                    current.IsLeftOfOrEqualTo(x.endPtr, out endTest);
                    if (endTest)
                    {
                        MarkupPointer pStart = markupServices.CreateMarkupPointer(x.startPtr);
                        MarkupPointer pEnd   = markupServices.CreateMarkupPointer(x.endPtr);
                        MarkupRange   range  = markupServices.CreateMarkupRange(pStart, pEnd);
                        //this could be a "phantom" range...no more content due to uncommitted damage or other reasons
                        //if it is phantom, remove it from the tracker and return null
                        if (range.Text == null)
                        {
                            list.RemoveAt(i);
                            return(null);
                        }
                        return(new MisspelledWordInfo(range, x.word));
                    }
                    start = i + 1;
                }
                else
                {
                    end = i - 1;
                }
                i = Middle(start, end);
            }
            return(null);
        }
Пример #8
0
        //iterates through a word range checking for spelling errors
        //return: whether the word range is finished (true) or not
        private bool ProcessWordRange(MshtmlWordRange wordRange)
        {
            if (wordRange.CurrentWordRange.Positioned)
            {
                //track where we will need to clear;
                MarkupPointer start = _markupServices.CreateMarkupPointer();
                start.MoveToPointer(wordRange.CurrentWordRange.End);
                ArrayList highlightwords = new ArrayList(NUMBER_OF_WORDS_TO_CHECK);

                int i = 0;
                //to do....the word range is losing its place when it stays in the queue
                while (wordRange.HasNext() && i < NUMBER_OF_WORDS_TO_CHECK)
                {
                    // advance to the next word
                    wordRange.Next();
                    // check the spelling
                    int offset, length;
                    if (ProcessWord(wordRange, out offset, out length))
                    {
                        MarkupRange highlightRange = wordRange.CurrentWordRange.Clone();
                        MarkupHelpers.AdjustMarkupRange(ref stagingTextRange, highlightRange, offset, length);

                        //note: cannot just push the current word range here, as it moves before we get to the highlighting step
                        highlightwords.Add(highlightRange);
                    }
                    i++;
                }
                MarkupPointer end = wordRange.CurrentWordRange.End;

                //got our words, clear the checked range and then add the misspellings
                ClearRange(start, end);
                foreach (MarkupRange word in highlightwords)
                {
                    HighlightWordRange(word);
                }

                return(!wordRange.HasNext());
            }
            else
            {
                return(true);
            }
        }
Пример #9
0
        internal IHTMLElement FindCenteringNode()
        {
            // Create markup services using the element's document that we are analyzing
            MshtmlMarkupServices MarkupServices = new MshtmlMarkupServices(_element.document as IMarkupServicesRaw);
            // Create a pointer and move it to before the begining of its opening tag
            MarkupPointer start = MarkupServices.CreateMarkupPointer();

            start.MoveAdjacentToElement(_element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
            // Find the block parent of this node.
            IHTMLElement blockParent = start.CurrentBlockScope();

            // Check to see if the block parent is actually a centering node.
            if (IsBodyElement((IHTMLElement3)blockParent) || !IsCenteringNode(blockParent))
            {
                blockParent = null;
            }

            // Make sure that if we do have a block parents, we are the only thing inside it.
            // Since we are going to edit the block, we dont want other stuff in there that
            // will also be changed
            if (blockParent != null)
            {
                string innerHtml = ((IHTMLElement)blockParent).innerText ?? "";
                if (!string.IsNullOrEmpty(innerHtml.Trim()))
                {
                    blockParent = null;
                }
                else
                {
                    int numElements = CountVisibleElements((IHTMLElement)blockParent);
                    if (numElements != 1)
                    {
                        blockParent = null;
                    }
                }
            }

            return(blockParent);
        }
        public static void InsertContentIntoElement(string content, ISmartContent sContent, IContentSourceSidebarContext contentSourceContext, IHTMLElement element)
        {
            MshtmlMarkupServices MarkupServices = new MshtmlMarkupServices((IMarkupServicesRaw)element.document);

            //Note: undo/redo disabled for smart content since undo causes the HTML to get out of sync
            //with the inserter's settings state, so undo changes will be blown away the next time the
            //the inserter's HTML is regenerated.  Also note that making this insertion without wrapping it
            //in an undo clears the undo/redo stack, which is what we want for beta.
            //string undoId = Guid.NewGuid().ToString();

            MarkupRange htmlRange = MarkupServices.CreateMarkupRange(element, false);

            htmlRange.Start.PushCling(true);
            htmlRange.End.PushCling(true);
            MarkupServices.Remove(htmlRange.Start, htmlRange.End);
            htmlRange.Start.PopCling();
            htmlRange.End.PopCling();

            element.style.padding = ToPaddingString(sContent.Layout);

            if (sContent.Layout.Alignment == Alignment.None ||
                sContent.Layout.Alignment == Alignment.Right ||
                sContent.Layout.Alignment == Alignment.Left)
            {
                element.style.display     = "inline";
                element.style.marginLeft  = "0px";
                element.style.marginRight = "0px";
                element.style.styleFloat  = sContent.Layout.Alignment.ToString().ToLower(CultureInfo.InvariantCulture);
            }
            else if (sContent.Layout.Alignment == Alignment.Center)
            {
                element.style.styleFloat  = Alignment.None.ToString().ToLower(CultureInfo.InvariantCulture);
                element.style.display     = "block";
                element.style.marginLeft  = "auto";
                element.style.marginRight = "auto";
            }

            // Clear out any width on the overall smart content block, if the element is centered, we will add the width back in later
            // after we calcuate it from the childern, the current width value is stale.
            element.style.width = "";

            //Note: we use MarkupServices to insert the content so that IE doesn't try to fix up URLs.
            //Element.insertAdjacentHTML() is a no-no because it rewrites relaive URLs to include
            //the fullpath from the local filesytem.

            //MarkupServices.ParseString() doesn't attempt to fix up URLs, so its safe to use.
            //We will now stage the new content into a MarkupContainer, and then move it into
            //the working document.
            MarkupPointer sc1 = MarkupServices.CreateMarkupPointer();
            MarkupPointer sc2 = MarkupServices.CreateMarkupPointer();

            //Create a temporary document from the html and set the start/end pointers to the
            //start and end of the document.
            MarkupServices.ParseString(content, sc1, sc2);
            IHTMLDocument2 doc          = sc1.GetDocument();
            MarkupRange    stagingRange = MarkupServices.CreateMarkupRange(sc1, sc2);

            stagingRange.MoveToElement(doc.body, false);

            //IE7 hack: fixes bug 305512.  Note that this will destroy the inner content of the element,
            //so make sure it is called before the refreshed content is inserted.
            BeforeInsertInvalidateHackForIE7(element);

            //move the content from the staging area into the actual insertion point.
            MarkupServices.Move(stagingRange.Start, stagingRange.End, htmlRange.End);

            if (sContent.Layout.Alignment == Alignment.Center)
            {
                MarkupContext mc    = htmlRange.End.Right(false);
                MarkupRange   range = MarkupServices.CreateMarkupRange(mc.Element, false);

                IHTMLElement[] childern = range.GetTopLevelElements(MarkupRange.FilterNone);

                int maxWidth = 0;
                foreach (IHTMLElement child in childern)
                {
                    maxWidth = Math.Max(maxWidth, child.offsetWidth);
                }

                if (maxWidth != 0)
                {
                    mc.Element.style.width = maxWidth;
                }
            }

            // Let the context provider know the smart content was edited.
            string contentSourceId, contentId;

            ContentSourceManager.ParseContainingElementId(element.id, out contentSourceId, out contentId);
            contentSourceContext.OnSmartContentEdited(contentId);
        }
        private MarkupRange ApplyInlineTag(_ELEMENT_TAG_ID tagId, string attributes, MarkupRange selection)
        {
            MarkupRange newSelection = _markupServices.CreateMarkupRange();

            // If the selection is empty, then just insert the tag
            if (selection.IsEmpty())
            {
                newSelection.MoveToElement(WrapRangeInSpanElement(tagId, attributes, selection), false);
                return(newSelection);
            }

            // Start at the beginning of the selection move forward until you hit a block start/exit context or the end of the selection

            bool          keepApplying   = true;
            MarkupContext contextStart   = new MarkupContext();
            MarkupRange   blockFreeRange = _markupServices.CreateMarkupRange(selection.Start.Clone(), selection.Start.Clone());
            MarkupPointer currentPointer = _markupServices.CreateMarkupPointer(blockFreeRange.Start);

            while (keepApplying)
            {
                // Check if moving right would be beyond the bounds of the selection.
                if (currentPointer.IsRightOfOrEqualTo(selection.End))
                {
                    // We've hit the end of the selection, so we're done.
                    keepApplying = false;
                    Debug.Assert(blockFreeRange.Start.IsLeftOfOrEqualTo(selection.End));
                    blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer);

                    if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange))
                    {
                        newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange));
                    }
                    break;
                }

                // Check if the next context is entering or exiting a block.
                currentPointer.Right(false, contextStart);
                if (contextStart.Element != null && ElementFilters.IsBlockElement(contextStart.Element))
                {
                    switch (contextStart.Context)
                    {
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope:

                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope:
                    {
                        blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer);
                        if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange))
                        {
                            newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange));
                        }
                        if (contextStart.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope)
                        {
                            blockFreeRange.Start.MoveAdjacentToElement(contextStart.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                        }
                        else if (contextStart.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope)
                        {
                            blockFreeRange.Start.MoveAdjacentToElement(contextStart.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                        }

                        blockFreeRange.Collapse(true);
                    }
                    break;

                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None:
                    {
                        keepApplying = false;
                        blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer);
                        if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange))
                        {
                            newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange));
                        }
                    }
                    break;

                    default:
                        break;
                    }
                }

                // Finally, move our pointer
                currentPointer.Right(true);
            }

            if (newSelection.Positioned)
            {
                newSelection.Trim();
            }

            return(newSelection);
        }
 public MarkupServicesWordHelper(MshtmlMarkupServices markupServices)
 {
     MarkupServices = markupServices;
     _p             = MarkupServices.CreateMarkupPointer();
     _p2            = MarkupServices.CreateMarkupPointer();
 }
Пример #13
0
        /// <summary>
        /// Takes the source HTML and makes necessary modifications to keep the source formatting as if it were to be
        /// pasted into the destination range.
        /// </summary>
        /// <param name="sourceRange">The range containing the HTML that is being copied.</param>
        /// <param name="destinationRange">The range that the source HTML will be copied to.</param>
        /// <returns>A serialized string of the source HTML with necessary modifications to keep the source formatting
        /// or null if unsuccessful.</returns>
        private string KeepSourceFormatting(MarkupRange sourceRange, MarkupRange destinationRange)
        {
            Debug.Assert(sourceRange.Start.Container.GetOwningDoc() == destinationRange.Start.Container.GetOwningDoc(),
                         "Ranges must share an owning document!");

            // We will temporarily add comments to the destination document to mark the destinationRange.
            IHTMLElement startComment = null;
            IHTMLElement endComment   = null;

            try
            {
                // This is our true destination document.
                IHTMLDocument2       destinationDocument       = destinationRange.Start.Container.Document;
                MshtmlMarkupServices destinationMarkupServices = new MshtmlMarkupServices((IMarkupServicesRaw)destinationDocument);

                // However, we'll use a temp destination because we don't want to paste anything into the real
                // document yet as it could fail, it would fire events, images would start loading, etc.
                MarkupContainer temporaryDestinationContainer = destinationMarkupServices.CreateMarkupContainer();
                MarkupPointer   temporaryDestinationPointer   = destinationMarkupServices.CreateMarkupPointer();
                temporaryDestinationPointer.MoveToContainer(temporaryDestinationContainer, true);

                // We add in comments to the destination document so that when we copy this range over to the fake
                // destination we'll be able to find the range again.
                destinationRange.Start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Left;
                destinationRange.End.Gravity   = _POINTER_GRAVITY.POINTER_GRAVITY_Right;

                string startMarker = string.Format(CultureInfo.InvariantCulture, "<!--{0}-->", Guid.NewGuid());
                destinationMarkupServices.InsertHtml(startMarker, destinationRange.Start);
                startComment = destinationRange.Start.Right(false).Element;

                string endMarker = string.Format(CultureInfo.InvariantCulture, "<!--{0}-->", Guid.NewGuid());
                destinationMarkupServices.InsertHtml(endMarker, destinationRange.End);
                endComment = destinationRange.End.Left(false).Element;

                try
                {
                    // Copy over the entire destination document into the fake destination document.
                    MarkupRange destinationAll = SelectAll(destinationDocument);
                    destinationMarkupServices.Copy(destinationAll.Start, destinationAll.End, temporaryDestinationPointer);

                    // Find the original destination range in this copy.
                    MarkupRange temporaryDestinationRange = FindMarkedFragment(temporaryDestinationContainer.Document, startMarker, endMarker);

                    if (temporaryDestinationRange != null)
                    {
                        // Do the work to keep the source formatting.
                        MarkupRange inlinedRange = new KeepSourceFormatting(sourceRange, temporaryDestinationRange).Execute();
                        if (inlinedRange != null)
                        {
                            return(inlinedRange.HtmlText);
                        }
                    }
                }
                finally
                {
                    // WinLive 249077: Clear the temporary destination container, otherwise behaviors may
                    // inadvertently attach to elements in the MarkupContainer.
                    temporaryDestinationContainer.Document.body.innerHTML = String.Empty;
                }
            }
            catch (Exception e)
            {
                // I really dont want some funky html on the clipboard that causes a problem with this code
                // to prevent a paste from going through.
                Trace.Fail("Failed to get inline css for selection: " + e);
            }
            finally
            {
                Debug.Assert(startComment is IHTMLCommentElement, "Didn't find start comment or it wasn't created.");
                if (startComment is IHTMLCommentElement)
                {
                    HTMLElementHelper.RemoveElement(startComment);
                }

                Debug.Assert(endComment is IHTMLCommentElement, "Didn't find end comment or it wasn't created.");
                if (endComment is IHTMLCommentElement)
                {
                    HTMLElementHelper.RemoveElement(endComment);
                }
            }

            return(null);
        }