//--------------------------------------------------------------------
        // Highlight compositing
        //---------------------------------------------------------------------

        private void _OnHighlightChanged(object sender, HighlightChangedEventArgs args)
        {
            Debug.Assert(sender != null);
            Debug.Assert(args != null);
            Debug.Assert(args.Ranges != null);
#if DEBUG
            {
                Highlights        highlights = this.Highlights;
                StaticTextPointer highlightTransitionPosition;
                StaticTextPointer highlightRangeStart;
                object            selected;

                DocumentsTrace.FixedDocumentSequence.Highlights.Trace("===BeginNewHighlightRange===");
                highlightTransitionPosition = ((ITextContainer)this).CreateStaticPointerAtOffset(0);
                while (true)
                {
                    // Move to the next highlight start.
                    if (!highlights.IsContentHighlighted(highlightTransitionPosition, LogicalDirection.Forward))
                    {
                        highlightTransitionPosition = highlights.GetNextHighlightChangePosition(highlightTransitionPosition, LogicalDirection.Forward);

                        // No more highlights?
                        if (highlightTransitionPosition.IsNull)
                        {
                            break;
                        }
                    }

                    // highlightTransitionPosition is at the start of a new highlight run.
                    selected = highlights.GetHighlightValue(highlightTransitionPosition, LogicalDirection.Forward, typeof(TextSelection));

                    // Save the start position and find the end.
                    highlightRangeStart         = highlightTransitionPosition;
                    highlightTransitionPosition = highlights.GetNextHighlightChangePosition(highlightTransitionPosition, LogicalDirection.Forward);
                    Invariant.Assert(!highlightTransitionPosition.IsNull, "Highlight start not followed by highlight end!");

                    // Store the highlight.
                    if (selected != DependencyProperty.UnsetValue)
                    {
                        DocumentsTrace.FixedDocumentSequence.Highlights.Trace(string.Format("HightlightRange {0}-{1}", highlightRangeStart.ToString(), highlightTransitionPosition.ToString()));
                        if (highlightRangeStart.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text)
                        {
                            DocumentsTrace.FixedDocumentSequence.Highlights.Trace("<HighlightNotOnText>");
                        }
                        else
                        {
                            char[] sb = new char[256];
                            TextPointerBase.GetTextWithLimit(highlightRangeStart.CreateDynamicTextPointer(LogicalDirection.Forward), LogicalDirection.Forward, sb, 0, 256, highlightTransitionPosition.CreateDynamicTextPointer(LogicalDirection.Forward));
                            DocumentsTrace.FixedDocumentSequence.TextOM.Trace(string.Format("HightlightContent [{0}]", new String(sb)));
                        }
                    }
                }
                DocumentsTrace.FixedDocumentSequence.TextOM.Trace("===EndNewHighlightRange===");
            }
#endif
            Debug.Assert(args.Ranges.Count > 0 && ((TextSegment)args.Ranges[0]).Start.CompareTo(((TextSegment)args.Ranges[0]).End) < 0);


            // For each change range we received, we need to figure out
            // affected child TextContainer, and notify it with appropriate
            // ranges that are in the child's address space.
            //
            // We only fire one highlight change notification for any child
            // TextContainer even if there is multiple change ranges fall
            // into the same child TextContainer.
            //
            // We scan the ranges and the child TextContainer in the same loop,
            // moving forward two scanning pointers and at boundary of each
            // TextContainer, we fire a change notification.
            //
            int idxScan = 0;
            DocumentSequenceTextPointer tsScan     = null;
            ChildDocumentBlock          cdbScan    = null;
            List <TextSegment>          rangeArray = new List <TextSegment>(4);
            while (idxScan < args.Ranges.Count)
            {
                TextSegment ts = (TextSegment)args.Ranges[idxScan];
                DocumentSequenceTextPointer tsEnd = (DocumentSequenceTextPointer)ts.End;
                ITextPointer       tpChildStart, tpChildEnd;
                ChildDocumentBlock lastBlock;

                // If tsScan == null, we were done with previous range,
                // so we are going to set tsScan to begining of this range.
                // Otherwise the previous range was split so we will simply
                // start from what was left over from previous loop.
                if (tsScan == null)
                {
                    tsScan = (DocumentSequenceTextPointer)ts.Start;
                }
                lastBlock = cdbScan;
                cdbScan   = tsScan.ChildBlock;

                if (lastBlock != null && cdbScan != lastBlock && !(lastBlock.ChildContainer is NullTextContainer) && rangeArray.Count != 0)
                {
                    // This range is in a different block, so take care of old blocks first
                    lastBlock.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection <TextSegment>(rangeArray));
                    rangeArray.Clear();
                }

                tpChildStart = tsScan.ChildPointer;

                if (tsEnd.ChildBlock != cdbScan)
                {
                    // If this range crosses blocks, we are done with current block
                    tpChildEnd = tsScan.ChildPointer.TextContainer.End;
                    if (tpChildStart.CompareTo(tpChildEnd) != 0)
                    {
                        rangeArray.Add(new TextSegment(tpChildStart, tpChildEnd));
                    }
                    // Notify child container
                    if (!(cdbScan.ChildContainer is NullTextContainer) && rangeArray.Count != 0)
                    {
                        cdbScan.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection <TextSegment>(rangeArray));
                    }

                    // Move on to next block;
                    cdbScan = cdbScan.NextBlock;
                    tsScan  = new DocumentSequenceTextPointer(cdbScan, cdbScan.ChildContainer.Start);
                    rangeArray.Clear();
                }
                else
                {
                    // Otherwise we need to go on to see if there is more ranges
                    // fall withing the same block. Simply add this change range
                    tpChildEnd = tsEnd.ChildPointer;
                    if (tpChildStart.CompareTo(tpChildEnd) != 0)
                    {
                        rangeArray.Add(new TextSegment(tpChildStart, tpChildEnd));
                    }

                    // Move on to next range
                    idxScan++;
                    tsScan = null;
                }
            }

            // Fire change notification for the last child block.
            if (rangeArray.Count > 0 && (!(cdbScan == null || cdbScan.ChildContainer is NullTextContainer)))
            {
                cdbScan.ChildHighlightLayer.RaiseHighlightChangedEvent(new ReadOnlyCollection <TextSegment>(rangeArray));
            }
        }