"use strict";
/**
 * User: Ilja.Kirillov
 * Date: 03.12.13
 * Time: 18:28
 */

function ParaRun(Paragraph, bMathRun)
{
    ParaRun.superclass.constructor.call(this);
    
    this.Id         = g_oIdCounter.Get_NewId();  // Id данного элемента
    this.Type       = para_Run;                  // тип данного элемента
    this.Paragraph  = Paragraph;                 // Ссылка на параграф
    this.Pr         = new CTextPr();             // Текстовые настройки данного run
    this.Content    = [];                        // Содержимое данного run
        
    this.State      = new CParaRunState();       // Положение курсора и селекта в данного run
    this.Selection  = this.State.Selection;
    this.CompiledPr = new CTextPr();             // Скомпилированные настройки
    this.RecalcInfo = new CParaRunRecalcInfo();  // Флаги для пересчета (там же флаг пересчета стиля)

    this.TextAscent  = 0; // текстовый ascent + linegap
    this.TextAscent  = 0; // текстовый ascent + linegap
    this.TextDescent = 0; // текстовый descent
    this.TextHeight  = 0; // высота текста
    this.TextAscent2 = 0; // текстовый ascent
    this.Ascent      = 0; // общий ascent
    this.Descent     = 0; // общий descent
    this.YOffset     = 0; // смещение по Y

    this.CollaborativeMarks = new CRunCollaborativeMarks();
    this.m_oContentChanges = new CContentChanges(); // список изменений(добавление/удаление элементов)

    this.NearPosArray  = [];
    this.SearchMarks   = [];
    this.SpellingMarks = [];

    if(bMathRun)
    {
        this.Type = para_Math_Run;

        this.Parent       = null;
        this.ArgSize      = 0;
        this.bEqqArray    = false;
        //this.UpdateMathPr = true;
        this.size         = new CMathSize();
        this.MathPrp      = new CMPrp();
    }
    this.StartState = null;

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
    g_oTableId.Add( this, this.Id );
    if(this.Paragraph && !this.Paragraph.bFromDocument)
    {
        this.Save_StartState();
    }
}

Asc.extendClass(ParaRun, CParagraphContentWithContentBase)

ParaRun.prototype.Get_Type = function()
{
    return this.Type;
};
//-----------------------------------------------------------------------------------
// Функции для работы с Id
//-----------------------------------------------------------------------------------
ParaRun.prototype.Set_Id = function(newId)
{
    g_oTableId.Reset_Id( this, newId, this.Id );
    this.Id = newId;
};

ParaRun.prototype.Get_Id = function()
{
    return this.Id;
};

ParaRun.prototype.Get_Paragraph = function()
{
    return this.Paragraph;
};

ParaRun.prototype.Set_Paragraph = function(Paragraph)
{
    this.Paragraph = Paragraph;
};

ParaRun.prototype.Save_StartState = function()
{
    this.StartState = new CParaRunStartState(this);
};
//-----------------------------------------------------------------------------------
// Функции для работы с содержимым данного рана
//-----------------------------------------------------------------------------------
ParaRun.prototype.Copy = function(Selected)
{
    var NewRun = new ParaRun(this.Paragraph);

    NewRun.Set_Pr( this.Pr.Copy() );

    if(this.Type == para_Math_Run)
    {
        NewRun.MathPrp = this.MathPrp.Copy();
    }

    var StartPos = 0;
    var EndPos   = this.Content.length;

    if ( true === Selected && true === this.State.Selection.Use )
    {
        StartPos = this.State.Selection.StartPos;
        EndPos   = this.State.Selection.EndPos;

        if ( StartPos > EndPos )
        {
            StartPos = this.State.Selection.EndPos;
            EndPos   = this.State.Selection.StartPos;
        }
    }

    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];

        // TODO: Как только перенесем para_End в сам параграф (как и нумерацию) убрать здесь
        if ( para_End !== Item.Type )
            NewRun.Add_ToContent( CurPos - StartPos, Item.Copy(), false );
    }

    return NewRun;
};

ParaRun.prototype.Copy2 = function()
{
    var NewRun = new ParaRun(this.Paragraph);

    NewRun.Set_Pr( this.Pr.Copy() );

    var StartPos = 0;
    var EndPos   = this.Content.length;

    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];
        NewRun.Add_ToContent( CurPos - StartPos, Item.Copy(), false );
    }
    return NewRun;
};

ParaRun.prototype.Get_AllDrawingObjects = function(DrawingObjs)
{
    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = this.Content[Index];

        if ( para_Drawing === Item.Type )
            DrawingObjs.push(Item);
    }
};

ParaRun.prototype.Clear_ContentChanges = function()
{
    this.m_oContentChanges.Clear();
};

ParaRun.prototype.Add_ContentChanges = function(Changes)
{
    this.m_oContentChanges.Add( Changes );
};

ParaRun.prototype.Refresh_ContentChanges = function()
{
    this.m_oContentChanges.Refresh();
};

ParaRun.prototype.Get_Text = function(Text)
{
    if ( null === Text.Text )
        return;

    var ContentLen = this.Content.length;

    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Item = this.Content[CurPos];
        var ItemType = Item.Type;

        var bBreak = false;

        switch ( ItemType )
        {
            case para_Drawing:
            case para_End:
            case para_PageNum:
            {
                Text.Text = null;
                bBreak = true;
                break;
            }

            case para_Text : Text.Text += String.fromCharCode(Item.Value); break;
            case para_Space:
            case para_Tab  : Text.Text += " "; break;
        }

        if ( true === bBreak )
            break;
    }
};

// Проверяем пустой ли ран
ParaRun.prototype.Is_Empty = function(Props)
{
    var SkipAnchor = (undefined !== Props ? Props.SkipAnchor : false);
    var SkipEnd    = (undefined !== Props ? Props.SkipEnd    : false);

    var Count = this.Content.length;

    if ( true !== SkipAnchor && true !== SkipEnd )
    {
        if ( Count > 0 )
            return false;
        else
            return true;
    }
    else
    {
        for ( var CurPos = 0; CurPos < this.Content.length; CurPos++ )
        {
            var Item = this.Content[CurPos];
            var ItemType = Item.Type;

            if ( ( true !== SkipAnchor || para_Drawing !== ItemType || false !== Item.Is_Inline() ) && ( true !== SkipEnd || para_End !== ItemType ) )
                return false;
        }

        return true;
    }
};

// Начинается ли данный ран с новой строки
ParaRun.prototype.Is_StartFromNewLine = function()
{
    if (this.protected_GetLinesCount() < 2 || 0 !== this.protected_GetRangeStartPos(1, 0))
        return false;

    return true;
};

// Добавляем элемент в текущую позицию
ParaRun.prototype.Add = function(Item, bMath)
{
    this.Add_ToContent(this.State.ContentPos, Item, true, bMath);
};

ParaRun.prototype.Remove = function(Direction, bOnAddText)
{
    var Selection = this.State.Selection;

    if ( true === Selection.Use )
    {
        var StartPos = Selection.StartPos;
        var EndPos   = Selection.EndPos;

        if ( StartPos > EndPos )
        {
            var Temp = StartPos;
            StartPos = EndPos;
            EndPos   = Temp;
        }

        // Если в выделение попадает ParaEnd, тогда удаляем все кроме этого элемента
        if ( true === this.Selection_CheckParaEnd() )
        {
            for ( var CurPos = EndPos - 1; CurPos >= StartPos; CurPos-- )
            {
                if ( para_End !== this.Content[CurPos].Type )
                    this.Remove_FromContent( CurPos, 1, true );
            }
        }
        else
        {
            this.Remove_FromContent( StartPos, EndPos - StartPos, true );
        }

        this.Selection_Remove();
        this.State.ContentPos = StartPos;
    }
    else
    {
        var CurPos = this.State.ContentPos;

        if ( Direction < 0 )
        {
            // Пропускаем все Flow-объекты
            while ( CurPos > 0 && para_Drawing === this.Content[CurPos - 1].Type && false === this.Content[CurPos - 1].Is_Inline() )
                CurPos--;

            if ( CurPos <= 0 )
                return false;

            // Проверяем, возможно предыдущий элемент - инлайн картинка, тогда мы его не удаляем, а выделяем как картинку
            if ( para_Drawing == this.Content[CurPos - 1].Type && true === this.Content[CurPos - 1].Is_Inline() )
            {
                return this.Paragraph.Parent.Select_DrawingObject( this.Content[CurPos - 1].Get_Id() );
            }

            this.Remove_FromContent( CurPos - 1, 1, true );

            this.State.ContentPos = CurPos - 1;
        }
        else
        {
            if ( CurPos >= this.Content.length || para_End === this.Content[CurPos].Type )
                return false;

            // Проверяем, возможно следующий элемент - инлайн картинка, тогда мы его не удаляем, а выделяем как картинку
            if ( para_Drawing == this.Content[CurPos].Type && true === this.Content[CurPos].Is_Inline() )
            {
                return this.Paragraph.Parent.Select_DrawingObject( this.Content[CurPos].Get_Id() );
            }

            this.Remove_FromContent( CurPos, 1, true );

            this.State.ContentPos = CurPos;
        }
    }

    return true;
};

ParaRun.prototype.Remove_ParaEnd = function()
{
    var Pos = -1;

    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        if ( para_End === this.Content[CurPos].Type )
        {
            Pos = CurPos;
            break;
        }
    }

    if ( -1 === Pos )
        return false;

    this.Remove_FromContent( Pos, ContentLen - Pos, true );

    return true;
};

// Добавляем элемент в позицию с сохранием в историю
ParaRun.prototype.Add_ToContent = function(Pos, Item, UpdatePosition, bMath)
{
    History.Add( this, { Type : historyitem_ParaRun_AddItem, Pos : Pos, EndPos : Pos, Items : [ Item ] } );
    this.Content.splice( Pos, 0, Item );

    if ( true === UpdatePosition )
    {
        // Обновляем текущую позицию
        if ( this.State.ContentPos >= Pos )
            this.State.ContentPos++;

        // Обновляем начало и конец селекта
        if ( true === this.State.Selection.Use )
        {
            if ( this.State.Selection.StartPos >= Pos )
                this.State.Selection.StartPos++;

            if ( this.State.Selection.EndPos >= Pos )
                this.State.Selection.EndPos++;
        }

        // Также передвинем всем метки переносов страниц и строк
        var LinesCount = this.protected_GetLinesCount();
        for ( var CurLine = 0; CurLine < LinesCount; CurLine++ )
        {
            var RangesCount = this.protected_GetRangesCount(CurLine);

            for ( var CurRange = 0; CurRange < RangesCount; CurRange++ )
            {
                var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
                var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

                if (StartPos > Pos)
                    StartPos++;

                if (EndPos > Pos)
                    EndPos++;

                this.protected_FillRange(CurLine, CurRange, StartPos, EndPos);
            }

            // Особый случай, когда мы добавляем элемент в самый последний ран
            if (Pos === this.Content.length - 1 && LinesCount - 1 === CurLine && !bMath)
            {
                this.protected_FillRangeEndPos(CurLine, RangesCount - 1, this.protected_GetRangeEndPos(CurLine, RangesCount - 1) + 1);
            }
        }
    }

    // Обновляем позиции в NearestPos
    var NearPosLen = this.NearPosArray.length;
    for ( var Index = 0; Index < NearPosLen; Index++ )
    {
        var RunNearPos = this.NearPosArray[Index];
        var ContentPos = RunNearPos.NearPos.ContentPos;
        var Depth      = RunNearPos.Depth;

        if ( ContentPos.Data[Depth] >= Pos )
            ContentPos.Data[Depth]++;
    }

    // Обновляем позиции в поиске
    var SearchMarksCount = this.SearchMarks.length;
    for ( var Index = 0; Index < SearchMarksCount; Index++ )
    {
        var Mark       = this.SearchMarks[Index];
        var ContentPos = ( true === Mark.Start ? Mark.SearchResult.StartPos : Mark.SearchResult.EndPos );
        var Depth      = Mark.Depth;

        if ( ContentPos.Data[Depth] >= Pos )
            ContentPos.Data[Depth]++;
    }

    // Обновляем позиции для орфографии
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var Index = 0; Index < SpellingMarksCount; Index++ )
    {
        var Mark       = this.SpellingMarks[Index];
        var ContentPos = ( true === Mark.Start ? Mark.Element.StartPos : Mark.Element.EndPos );
        var Depth      = Mark.Depth;

        if ( ContentPos.Data[Depth] >= Pos )
            ContentPos.Data[Depth]++;
    }

    if(this.Paragraph !== null)
        this.Paragraph.SpellChecker.Update_OnAdd( this, Pos, Item );

    // Обновляем позиции меток совместного редактирования
    this.CollaborativeMarks.Update_OnAdd( Pos );

    // Отмечаем, что надо перемерить элементы в данном ране
    this.RecalcInfo.Measure = true;
};

ParaRun.prototype.Remove_FromContent = function(Pos, Count, UpdatePosition)
{
    // Получим массив удаляемых элементов
    var DeletedItems = this.Content.slice( Pos, Pos + Count );
    History.Add( this, { Type : historyitem_Paragraph_RemoveItem, Pos : Pos, EndPos : Pos + Count - 1, Items : DeletedItems } );

    this.Content.splice( Pos, Count );

    if ( true === UpdatePosition )
    {
        // Обновим текущую позицию
        if ( this.State.ContentPos > Pos + Count )
            this.State.ContentPos -= Count;
        else if ( this.State.ContentPos > Pos )
            this.State.ContentPos = Pos;

        // Обновим начало и конец селекта
        if ( true === this.State.Selection.Use )
        {
            if ( this.State.Selection.StartPos <= this.State.Selection.EndPos )
            {
                if ( this.State.Selection.StartPos > Pos + Count )
                    this.State.Selection.StartPos -= Count;
                else if ( this.State.Selection.StartPos > Pos )
                    this.State.Selection.StartPos = Pos;

                if ( this.State.Selection.EndPos >= Pos + Count )
                    this.State.Selection.EndPos -= Count;
                else if ( this.State.Selection.EndPos > Pos )
                    this.State.Selection.EndPos = Math.max( 0, Pos - 1 );
            }
            else
            {
                if ( this.State.Selection.StartPos >= Pos + Count )
                    this.State.Selection.StartPos -= Count;
                else if ( this.State.Selection.StartPos > Pos )
                    this.State.Selection.StartPos = Math.max( 0, Pos - 1 );

                if ( this.State.Selection.EndPos > Pos + Count )
                    this.State.Selection.EndPos -= Count;
                else if ( this.State.Selection.EndPos > Pos )
                    this.State.Selection.EndPos = Pos;
            }
        }

        // Также передвинем всем метки переносов страниц и строк
        var LinesCount = this.protected_GetLinesCount();
        for ( var CurLine = 0; CurLine < LinesCount; CurLine++ )
        {
            var RangesCount = this.protected_GetRangesCount(CurLine);
            for ( var CurRange = 0; CurRange < RangesCount; CurRange++ )
            {
                var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
                var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

                if (StartPos > Pos + Count)
                    StartPos -= Count;
                else if (StartPos > Pos)
                    StartPos = Math.max( 0 , Pos );

                if (EndPos >= Pos + Count)
                    EndPos -= Count;
                else if (EndPos >= Pos)
                    EndPos = Math.max( 0 , Pos );

                this.protected_FillRange(CurLine, CurRange, StartPos, EndPos);
            }
        }
    }

    // Обновляем позиции в NearestPos
    var NearPosLen = this.NearPosArray.length;
    for ( var Index = 0; Index < NearPosLen; Index++ )
    {
        var RunNearPos = this.NearPosArray[Index];
        var ContentPos = RunNearPos.NearPos.ContentPos;
        var Depth      = RunNearPos.Depth;

        if ( ContentPos.Data[Depth] > Pos + Count )
            ContentPos.Data[Depth] -= Count;
        else if ( ContentPos.Data[Depth] > Pos )
            ContentPos.Data[Depth] = Math.max( 0 , Pos );
    }

    // Обновляем позиции в поиске
    var SearchMarksCount = this.SearchMarks.length;
    for ( var Index = 0; Index < SearchMarksCount; Index++ )
    {
        var Mark       = this.SearchMarks[Index];
        var ContentPos = ( true === Mark.Start ? Mark.SearchResult.StartPos : Mark.SearchResult.EndPos );
        var Depth      = Mark.Depth;

        if ( ContentPos.Data[Depth] > Pos + Count )
            ContentPos.Data[Depth] -= Count;
        else if ( ContentPos.Data[Depth] > Pos )
            ContentPos.Data[Depth] = Math.max( 0 , Pos );
    }

    // Обновляем позиции для орфографии
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var Index = 0; Index < SpellingMarksCount; Index++ )
    {
        var Mark       = this.SpellingMarks[Index];
        var ContentPos = ( true === Mark.Start ? Mark.Element.StartPos : Mark.Element.EndPos );
        var Depth      = Mark.Depth;

        if ( ContentPos.Data[Depth] > Pos + Count )
            ContentPos.Data[Depth] -= Count;
        else if ( ContentPos.Data[Depth] > Pos )
            ContentPos.Data[Depth] = Math.max( 0 , Pos );
    }

    this.Paragraph.SpellChecker.Update_OnRemove( this, Pos, Count );

    // Обновляем позиции меток совместного редактирования
    this.CollaborativeMarks.Update_OnRemove( Pos, Count );

    // Отмечаем, что надо перемерить элементы в данном ране
    this.RecalcInfo.Measure = true;
};

ParaRun.prototype.Concat_ToContent = function(NewItems)
{
    var StartPos = this.Content.length;
    this.Content = this.Content.concat( NewItems );

    History.Add( this, { Type : historyitem_ParaRun_AddItem, Pos : StartPos, EndPos : this.Content.length - 1, Items : NewItems } );

    // Отмечаем, что надо перемерить элементы в данном ране
    this.RecalcInfo.Measure = true;
};

// Определим строку и отрезок текущей позиции
ParaRun.prototype.Get_CurrentParaPos = function()
{
    var Pos = this.State.ContentPos;

    if (-1 === this.StartLine)
        return new CParaPos(-1, -1, -1, -1);

    var CurLine  = 0;
    var CurRange = 0;

    var LinesCount = this.protected_GetLinesCount();
    for (; CurLine < LinesCount; CurLine++)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine);
        for (CurRange = 0; CurRange < RangesCount; CurRange++)
        {
            var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
            if ( Pos < EndPos && Pos >= StartPos )
                return new CParaPos((CurLine === 0 ? CurRange + this.StartRange : CurRange), CurLine + this.StartLine, 0, 0);
        }
    }

    // Значит курсор стоит в самом конце, поэтому посылаем последний отрезок
    return new CParaPos((LinesCount <= 1 ? this.protected_GetRangesCount(0) - 1 + this.StartRange : this.protected_GetRangesCount(LinesCount - 1) - 1), LinesCount - 1 + this.StartLine, 0, 0 );
};

ParaRun.prototype.Get_ParaPosByContentPos = function(ContentPos, Depth)
{
    var Pos = ContentPos.Get(Depth);

    var CurLine  = 0;
    var CurRange = 0;

    var LinesCount = this.protected_GetLinesCount();
    for (; CurLine < LinesCount; CurLine++)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine);
        for (CurRange = 0; CurRange < RangesCount; CurRange++)
        {
            var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);
            if (Pos < EndPos && Pos >= StartPos)
                return new CParaPos((CurLine === 0 ? CurRange + this.StartRange : CurRange), CurLine + this.StartLine, 0, 0);
        }
    }

    return new CParaPos((LinesCount === 1 ? this.protected_GetRangesCount(0) - 1 + this.StartRange : this.protected_GetRangesCount(0) - 1), LinesCount - 1 + this.StartLine, 0, 0);

};

ParaRun.prototype.Recalculate_CurPos = function(X, Y, CurrentRun, _CurRange, _CurLine, CurPage, UpdateCurPos, UpdateTarget, ReturnTarget, PointsInfo)
{
    var Para = this.Paragraph;

    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Pos = StartPos;
    var _EndPos = ( true === CurrentRun ? Math.min( EndPos, this.State.ContentPos ) : EndPos );
    for ( ; Pos < _EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch( ItemType )
        {
            case para_Text:
            case para_Space:
            case para_Sym:
            case para_PageNum:
            case para_Tab:
            case para_End:
            case para_NewLine:
            case para_Math_Text:
            case para_Math_Placeholder:
            {
                X += Item.Get_WidthVisible();
                break;
            }
            case para_Drawing:
            {
                if ( drawing_Inline != Item.DrawingType )
                    break;

                X += Item.Get_WidthVisible();
                break;
            }
            case para_Math_Ampersand:
            {
                PointsInfo.NextAlignRange();
                X += PointsInfo.GetAlign();
            }
        }
    }

    if ( true === CurrentRun && Pos === this.State.ContentPos )
    {
        if ( true === UpdateCurPos )
        {
            // Обновляем позицию курсора в параграфе

            Para.CurPos.X        = X;
            Para.CurPos.Y        = Y;
            Para.CurPos.PagesPos = CurPage;

            if ( true === UpdateTarget )
            {
                var CurTextPr = this.Get_CompiledPr(false);

                g_oTextMeasurer.SetTextPr( CurTextPr, this.Paragraph.Get_Theme() );
                g_oTextMeasurer.SetFontSlot( fontslot_ASCII, CurTextPr.Get_FontKoef() );
                var Height    = g_oTextMeasurer.GetHeight();
                var Descender = Math.abs( g_oTextMeasurer.GetDescender() );
                var Ascender  = Height - Descender;


                Para.DrawingDocument.SetTargetSize( Height );


                var RGBA;
                if(CurTextPr.Unifill)
                {
                    CurTextPr.Unifill.check(Para.Get_Theme(), Para.Get_ColorMap());
                    RGBA = CurTextPr.Unifill.getRGBAColor();
                    Para.DrawingDocument.SetTargetColor( RGBA.R, RGBA.G, RGBA.B );
                }
                else
                {
                    if ( true === CurTextPr.Color.Auto )
                    {
                        // Выясним какая заливка у нашего текста
                        var Pr = Para.Get_CompiledPr();
                        var BgColor = undefined;
                        if ( undefined !== Pr.ParaPr.Shd && shd_Nil !== Pr.ParaPr.Shd.Value )
                        {
                            if(Pr.ParaPr.Shd.Unifill)
                            {
                                Pr.ParaPr.Shd.Unifill.check(this.Paragraph.Get_Theme(), this.Paragraph.Get_ColorMap());
                                var RGBA =  Pr.ParaPr.Shd.Unifill.getRGBAColor();
                                BgColor = new CDocumentColor(RGBA.R, RGBA.G, RGBA.B, false);
                            }
                            else
                            {
                                BgColor = Pr.ParaPr.Shd.Color;
                            }
                        }
                        else
                        {
                            // Нам надо выяснить заливку у родительского класса (возможно мы находимся в ячейке таблицы с забивкой)
                            BgColor = Para.Parent.Get_TextBackGroundColor();

                            if ( undefined !== CurTextPr.Shd && shd_Nil !== CurTextPr.Shd.Value )
                                BgColor = CurTextPr.Shd.Get_Color( this.Paragraph );
                        }

                        // Определим автоцвет относительно заливки
                        var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );
                        Para.DrawingDocument.SetTargetColor( AutoColor.r, AutoColor.g, AutoColor.b );
                    }
                    else
                        Para.DrawingDocument.SetTargetColor( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b );
                }

                var TargetY = Y - Ascender - CurTextPr.Position;
                switch( CurTextPr.VertAlign )
                {
                    case vertalign_SubScript:
                    {
                        TargetY -= CurTextPr.FontSize * g_dKoef_pt_to_mm * vertalign_Koef_Sub;
                        break;
                    }
                    case vertalign_SuperScript:
                    {
                        TargetY -= CurTextPr.FontSize * g_dKoef_pt_to_mm * vertalign_Koef_Super;
                        break;
                    }
                }

                var Page_Abs = Para.Get_StartPage_Absolute() + CurPage;
                Para.DrawingDocument.UpdateTarget( X, TargetY, Page_Abs );

                // TODO: Тут делаем, чтобы курсор не выходил за границы буквицы. На самом деле, надо делать, чтобы
                //       курсор не выходил за границы строки, но для этого надо делать обрезку по строкам, а без нее
                //       такой вариант будет смотреться плохо.
                if ( undefined != Para.Get_FramePr() )
                {
                    var __Y0 = TargetY, __Y1 = TargetY + Height;
                    var ___Y0 = Para.Pages[CurPage].Y + Para.Lines[CurLine].Top;
                    var ___Y1 = Para.Pages[CurPage].Y + Para.Lines[CurLine].Bottom;

                    __Y0 = Math.max( __Y0, ___Y0 );
                    __Y1 = Math.min( __Y1, ___Y1 );

                    Para.DrawingDocument.SetTargetSize( __Y1 - __Y0 );
                    Para.DrawingDocument.UpdateTarget( X, __Y0, Page_Abs );
                }
            }
        }

        if ( true === ReturnTarget )
        {

            var CurTextPr = this.Get_CompiledPr(false);


            g_oTextMeasurer.SetTextPr( CurTextPr, this.Paragraph.Get_Theme() );
            g_oTextMeasurer.SetFontSlot( fontslot_ASCII, CurTextPr.Get_FontKoef() );


            var Height    = g_oTextMeasurer.GetHeight();
            var Descender = Math.abs( g_oTextMeasurer.GetDescender() );
            var Ascender  = Height - Descender;

            var TargetY = Y - Ascender - CurTextPr.Position;

            switch( CurTextPr.VertAlign )
            {
                case vertalign_SubScript:
                {
                    TargetY -= CurTextPr.FontSize * g_dKoef_pt_to_mm * vertalign_Koef_Sub;
                    break;
                }
                case vertalign_SuperScript:
                {
                    TargetY -= CurTextPr.FontSize * g_dKoef_pt_to_mm * vertalign_Koef_Super;
                    break;
                }
            }


            return { X : X, Y : TargetY, Height : Height, Internal : { Line : CurLine, Page : CurPage, Range : CurRange } };
        }
        else
            return { X : X, Y : Y, PageNum : CurPage + Para.Get_StartPage_Absolute(), Internal : { Line : CurLine, Page : CurPage, Range : CurRange } };

    }

    return { X : X, Y: Y,  Internal : { Line : CurLine, Page : CurPage, Range : CurRange } };
};

// Проверяем, произошло ли простейшее изменение (набор или удаление текста)
ParaRun.prototype.Is_SimpleChanges = function(Changes)
{
    if ( para_Math_Run === this.Type )
        return false;

    var ParaPos = null;

    var Count = Changes.length;
    for (var Index = 0; Index < Count; Index++)
    {
        var Data = Changes[Index].Data;

        if (undefined === Data.Items || 1 !== Data.Items.length)
            return false;

        var Type = Data.Type;
        var Item = Data.Items[0];

        if (undefined === Item)
            return false;

        if (historyitem_ParaRun_AddItem !== Type && historyitem_ParaRun_RemoveItem !== Type)
            return false;

        // Добавление/удаление картинок может изменить размер строки. Добавление/удаление переноса строки/страницы/колонки
        // нельзя обсчитывать функцией Recalculate_Fast.
        // TODO: Но на самом деле стоило бы сделать нормальную проверку на высоту строки в функции Recalculate_Fast
        var ItemType = Item.Type;
        if (para_Drawing === ItemType || para_NewLine === ItemType)
            return false;

        // Проверяем, что все изменения произошли в одном и том же отрезке
        var CurParaPos = this.Get_SimpleChanges_ParaPos([Changes[Index]]);
        if (null === CurParaPos)
            return false;

        if (null === ParaPos)
            ParaPos = CurParaPos;
        else if (ParaPos.Line !== CurParaPos.Line || ParaPos.Range !== CurParaPos.Range)
            return false;
    }

    return true;
};

// Возвращаем строку и отрезок, в котором произошли простейшие изменения
ParaRun.prototype.Get_SimpleChanges_ParaPos = function(Changes)
{
    var Change = Changes[0].Data;
    var Type   = Changes[0].Data.Type;
    var Pos    = Change.Pos;

    var CurLine  = 0;
    var CurRange = 0;

    var LinesCount = this.protected_GetLinesCount();
    for (; CurLine < LinesCount; CurLine++)
    {
        var RangesCount = this.protected_GetRangesCount(CurLine);
        for (CurRange = 0; CurRange < RangesCount; CurRange++)
        {
            var RangeStartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var RangeEndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

            if  ( ( historyitem_ParaRun_AddItem === Type && Pos < RangeEndPos && Pos >= RangeStartPos ) || ( historyitem_ParaRun_RemoveItem === Type && Pos < RangeEndPos && Pos >= RangeStartPos ) || ( historyitem_ParaRun_RemoveItem === Type && Pos >= RangeEndPos && CurLine === LinesCount - 1 && CurRange === RangesCount - 1 ) )
            {
                // Если отрезок остается пустым, тогда надо все заново пересчитывать
                if ( RangeStartPos === RangeEndPos )
                    return null;

                return new CParaPos( ( CurLine === 0 ? CurRange + this.StartRange : CurRange ), CurLine + this.StartLine, 0, 0 );
            }
        }
    }

    // Если отрезок остается пустым, тогда надо все заново пересчитывать
    if (this.protected_GetRangeStartPos(0, 0) === this.protected_GetRangeEndPos(0, 0))
        return null;

    return new CParaPos( this.StartRange, this.StartLine, 0, 0 );
};

ParaRun.prototype.Split = function (ContentPos, Depth)
{
    var CurPos = ContentPos.Get(Depth);
    return this.Split2( CurPos );
};

ParaRun.prototype.Split2 = function(CurPos)
{
    // Создаем новый ран
    var bMathRun = this.Type == para_Math_Run;
    var NewRun = new ParaRun(this.Paragraph, bMathRun);

    // Копируем настройки
    NewRun.Set_Pr( this.Pr.Copy() );

    if(bMathRun)
        NewRun.Set_MathPr(this.MathPrp.Copy());

    // TODO: Как только избавимся от para_End переделать тут
    // Проверим, если наш ран содержит para_End, тогда мы должны para_End переметить в правый ран

    var CheckEndPos = -1;
    var CheckEndPos2 = Math.min( CurPos, this.Content.length );
    for ( var Pos = 0; Pos < CheckEndPos2; Pos++ )
    {
        if ( para_End === this.Content[Pos].Type )
        {
            CheckEndPos = Pos;
            break;
        }
    }

    if ( -1 !== CheckEndPos )
        CurPos = CheckEndPos;

    // Разделяем содержимое по ранам
    NewRun.Concat_ToContent( this.Content.slice(CurPos) );
    this.Remove_FromContent( CurPos, this.Content.length - CurPos, true );

    // Если были точки орфографии, тогда переместим их в новый ран
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var Index = 0; Index < SpellingMarksCount; Index++ )
    {
        var Mark    = this.SpellingMarks[Index];
        var MarkPos = ( true === Mark.Start ? Mark.Element.StartPos.Get(Mark.Depth) : Mark.Element.EndPos.Get(Mark.Depth) );

        if ( MarkPos >= CurPos )
        {
            var MarkElement = Mark.Element;
            if ( true === Mark.Start )
            {
                MarkElement.StartPos.Data[Mark.Depth] -= CurPos;
            }
            else
            {
                MarkElement.EndPos.Data[Mark.Depth] -= CurPos;
            }

            NewRun.SpellingMarks.push( Mark );

            this.SpellingMarks.splice( Index, 1 );
            SpellingMarksCount--;
            Index--;
        }
    }

    return NewRun;
};

ParaRun.prototype.Check_NearestPos = function(ParaNearPos, Depth)
{
    var RunNearPos = new CParagraphElementNearPos();
    RunNearPos.NearPos = ParaNearPos.NearPos;
    RunNearPos.Depth   = Depth;

    this.NearPosArray.push( RunNearPos );
    ParaNearPos.Classes.push( this );
};

ParaRun.prototype.Get_DrawingObjectRun = function(Id)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        if ( para_Drawing === Element.Type && Id === Element.Get_Id() )
            return this;
    }

    return null;
};

ParaRun.prototype.Get_DrawingObjectContentPos = function(Id, ContentPos, Depth)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        if ( para_Drawing === Element.Type && Id === Element.Get_Id() )
        {
            ContentPos.Update( CurPos, Depth );
            return true;
        }
    }

    return false;
};

ParaRun.prototype.Remove_DrawingObject = function(Id)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Element = this.Content[CurPos];

        if ( para_Drawing === Element.Type && Id === Element.Get_Id() )
        {
            this.Remove_FromContent( CurPos, 1, true );
            return;
        }
    }
};

ParaRun.prototype.Get_Layout = function(DrawingLayout, UseContentPos, ContentPos, Depth)
{
    var CurLine  = DrawingLayout.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? DrawingLayout.Range - this.StartRange : DrawingLayout.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var CurContentPos = ( true === UseContentPos ? ContentPos.Get(Depth) : -1 );

    var CurPos = StartPos;
    for ( ; CurPos < EndPos; CurPos++ )
    {
        if ( CurContentPos === CurPos )
            break;

        var Item         = this.Content[CurPos];
        var ItemType     = Item.Type;
        var WidthVisible = Item.Get_WidthVisible();

        switch ( ItemType )
        {
            case para_Text:
            case para_Space:
            case para_PageNum:
            {
                DrawingLayout.LastW = WidthVisible;

                break;
            }
            case para_Drawing:
            {
                if ( true === Item.Is_Inline() || true === DrawingLayout.Paragraph.Parent.Is_DrawingShape() )
                {
                    DrawingLayout.LastW = WidthVisible;
                }

                break;
            }
        }

        DrawingLayout.X += WidthVisible;
    }

    if ( CurContentPos === CurPos )
    {
        var LogicDocument = this.Paragraph.LogicDocument;
        var LD_PageLimits = LogicDocument.Get_PageLimits( CurPage );
        var LD_PageFields = LogicDocument.Get_PageFields( CurPage );

        var Page_Width  = LD_PageLimits.XLimit;
        var Page_Height = LD_PageLimits.YLimit;

        var X_Left_Field   = LD_PageFields.X;
        var Y_Top_Field    = LD_PageFields.Y;
        var X_Right_Field  = LD_PageFields.XLimit;
        var Y_Bottom_Field = LD_PageFields.YLimit;

        var X_Left_Margin   = X_Left_Field;
        var X_Right_Margin  = Page_Width  - X_Right_Field;
        var Y_Bottom_Margin = Page_Height - Y_Bottom_Field;
        var Y_Top_Margin    = Y_Top_Field;

        var Para    = DrawingLayout.Paragraph;
        var CurPage = DrawingLayout.Page;
        var Drawing = DrawingLayout.Drawing;

        var DrawingObjects = Para.Parent.DrawingObjects;
        var PageLimits     = Para.Parent.Get_PageLimits(Para.PageNum + CurPage);
        var PageFields     = Para.Parent.Get_PageFields(Para.PageNum + CurPage);

        var ColumnStartX = (0 === CurPage ? Para.X_ColumnStart : Para.Pages[CurPage].X);
        var ColumnEndX   = (0 === CurPage ? Para.X_ColumnEnd   : Para.Pages[CurPage].XLimit);

        var Top_Margin    = Y_Top_Margin;
        var Bottom_Margin = Y_Bottom_Margin;
        var Page_H        = Page_Height;

        if ( true === Para.Parent.Is_TableCellContent() && undefined != Drawing && true == Drawing.Use_TextWrap() )
        {
            Top_Margin    = 0;
            Bottom_Margin = 0;
            Page_H        = 0;
        }

        if ( undefined != Drawing && true != Drawing.Use_TextWrap() )
        {
            PageFields = LD_PageFields;
            PageLimits = LD_PageLimits;
        }

        DrawingLayout.Layout = new CParagraphLayout( DrawingLayout.X, DrawingLayout.Y , Para.Get_StartPage_Absolute() + CurPage, DrawingLayout.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[CurPage].Y );
        DrawingLayout.Limits = PageLimits;
    }
};

ParaRun.prototype.Get_NextRunElements = function(RunElements, UseContentPos, Depth)
{
    var StartPos   = ( true === UseContentPos ? RunElements.ContentPos.Get(Depth) : 0 );
    var ContentLen = this.Content.length;

    for ( var CurPos = StartPos; CurPos < ContentLen; CurPos++ )
    {
        var Item = this.Content[CurPos];
        var ItemType = Item.Type;

        if ( para_Text === ItemType || para_Space === ItemType || para_Tab === ItemType )
        {
            RunElements.Elements.push( Item );
            RunElements.Count--;

            if ( RunElements.Count <= 0 )
                return;
        }
    }
};

ParaRun.prototype.Get_PrevRunElements = function(RunElements, UseContentPos, Depth)
{
    var StartPos   = ( true === UseContentPos ? RunElements.ContentPos.Get(Depth) - 1 : this.Content.length - 1 );
    var ContentLen = this.Content.length;

    for ( var CurPos = StartPos; CurPos >= 0; CurPos-- )
    {
        var Item = this.Content[CurPos];
        var ItemType = Item.Type;

        if ( para_Text === ItemType || para_Space === ItemType || para_Tab === ItemType )
        {
            RunElements.Elements.push( Item );
            RunElements.Count--;

            if ( RunElements.Count <= 0 )
                return;
        }
    }
};

ParaRun.prototype.Collect_DocumentStatistics = function(ParaStats)
{
    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = this.Content[Index];
        var ItemType = Item.Type;

        var bSymbol  = false;
        var bSpace   = false;
        var bNewWord = false;

        if ((para_Text === ItemType && false === Item.Is_NBSP()) || (para_PageNum === ItemType))
        {
            if ( false === ParaStats.Word )
                bNewWord = true;

            bSymbol = true;
            bSpace  = false;

            ParaStats.Word           = true;
            ParaStats.EmptyParagraph = false;
        }
        else if ((para_Text === ItemType && true === Item.Is_NBSP()) || para_Space === ItemType || para_Tab === ItemType)
        {
            bSymbol = true;
            bSpace  = true;

            ParaStats.Word = false;
        }

        if ( true === bSymbol )
            ParaStats.Stats.Add_Symbol( bSpace );

        if ( true === bNewWord )
            ParaStats.Stats.Add_Word();
    }
};

ParaRun.prototype.Create_FontMap = function(Map, ArgSize)
{
    // для Math_Para_Pun argSize учитывается, когда мержатся текстовые настройки в Internal_Compile_Pr()
    if ( undefined !== this.Paragraph && null !== this.Paragraph )
    {
        var TextPr;
        var FontSize, FontSizeCS;
        if(this.Type === para_Math_Run)
        {
            TextPr = this.Get_CompiledPr(false);
            FontSize   = TextPr.FontSize;
            FontSizeCS = TextPr.FontSizeCS;

            if(this.Parent !== null)
                this.Parent.ParaMath.ApplyArgSize_2(TextPr, ArgSize.value);
        }
        else
            TextPr = this.Get_CompiledPr(false);

        TextPr.Document_CreateFontMap( Map, this.Paragraph.Get_Theme().themeElements.fontScheme);
        var Count = this.Content.length;
        for (var Index = 0; Index < Count; Index++)
        {
            var Item = this.Content[Index];

            if ( para_Drawing === Item.Type )
                Item.documentCreateFontMap( Map );
        }

        if(this.Type === para_Math_Run)
        {
            TextPr.FontSize = FontSize;
            TextPr.FontSizeCS = FontSizeCS;
        }
    }
};

ParaRun.prototype.Get_AllFontNames = function(AllFonts)
{
    this.Pr.Document_Get_AllFontNames( AllFonts );

    var Count = this.Content.length;
    for (var Index = 0; Index < Count; Index++)
    {
        var Item = this.Content[Index];

        if ( para_Drawing === Item.Type )
            Item.documentGetAllFontNames( AllFonts );
    }
};

ParaRun.prototype.Get_SelectedText = function(bAll, bClearText)
{
    var StartPos = 0;
    var EndPos   = 0;

    if ( true === bAll )
    {
        StartPos = 0;
        EndPos   = this.Content.length;
    }
    else if ( true === this.Selection.Use )
    {
        StartPos = this.State.Selection.StartPos;
        EndPos   = this.State.Selection.EndPos;

        if ( StartPos > EndPos )
        {
            var Temp = EndPos;
            EndPos   = StartPos;
            StartPos = Temp;
        }
    }

    var Str = "";

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch ( ItemType )
        {
            case para_Drawing:
            case para_End:
            case para_Numbering:
            case para_PresentationNumbering:
            case para_PageNum:
            {
                if ( true === bClearText )
                    return null;

                break;
            }

            case para_Text : Str += String.fromCharCode(Item.Value); break;
            case para_Space:
            case para_Tab  : Str += " "; break;
        }
    }

    return Str;
};

ParaRun.prototype.Can_AddDropCap = function()
{
    var Count = this.Content.length;

    for ( var Pos = 0; Pos < Count; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch ( ItemType )
        {
            case para_Text:
                return true;

            case para_Space:
            case para_Tab:
            case para_PageNum:
                return false;

        }
    }

    return null;
};

ParaRun.prototype.Get_TextForDropCap = function(DropCapText, UseContentPos, ContentPos, Depth)
{
    var EndPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length );

    for ( var Pos = 0; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( true === DropCapText.Check )
        {
            if ( para_Space === ItemType || para_Tab === ItemType || para_PageNum === ItemType || para_Drawing === ItemType )
            {
                DropCapText.Mixed = true;
                return;
            }
        }
        else
        {
            if ( para_Text === ItemType )
            {
                DropCapText.Runs.push(this);
                DropCapText.Text.push(Item);

                this.Remove_FromContent( Pos, 1, true );
                Pos--;
                EndPos--;

                if ( true === DropCapText.Mixed )
                    return;
            }
        }
    }
};

ParaRun.prototype.Get_StartTabsCount = function(TabsCounter)
{
    var ContentLen = this.Content.length;

    for ( var Pos = 0; Pos < ContentLen; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( para_Tab === ItemType )
        {
            TabsCounter.Count++;
            TabsCounter.Pos.push( Pos );
        }
        else if ( para_Text === ItemType || para_Space === ItemType || (para_Drawing === ItemType && true === Item.Is_Inline() ) || para_PageNum === ItemType || para_Math === ItemType )
            return false;
    }

    return true;
};

ParaRun.prototype.Remove_StartTabs = function(TabsCounter)
{
    var ContentLen = this.Content.length;
    for ( var Pos = 0; Pos < ContentLen; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( para_Tab === ItemType )
        {
            this.Remove_FromContent( Pos, 1, true );

            TabsCounter.Count--;
            Pos--;
            ContentLen--;
        }
        else if ( para_Text === ItemType || para_Space === ItemType || (para_Drawing === ItemType && true === Item.Is_Inline() ) || para_PageNum === ItemType || para_Math === ItemType )
            return false;
    }

    return true;
};
//-----------------------------------------------------------------------------------
// Функции пересчета
//-----------------------------------------------------------------------------------   
// Пересчитываем размеры всех элементов
ParaRun.prototype.Recalculate_MeasureContent = function()
{
    if ( false === this.RecalcInfo.Measure )
        return;

    var Pr = this.Get_CompiledPr(false);

    var Theme = this.Paragraph.Get_Theme();
    g_oTextMeasurer.SetTextPr(Pr, Theme);
    g_oTextMeasurer.SetFontSlot(fontslot_ASCII);

    // Запрашиваем текущие метрики шрифта, под TextAscent мы будем понимать ascent + linegap(которые записаны в шрифте)
    this.TextHeight  = g_oTextMeasurer.GetHeight();
    this.TextDescent = Math.abs( g_oTextMeasurer.GetDescender() );
    this.TextAscent  = this.TextHeight - this.TextDescent;
    this.TextAscent2 = g_oTextMeasurer.GetAscender();
    this.YOffset     = Pr.Position;

    var ContentLength = this.Content.length;

    for ( var Pos = 0; Pos < ContentLength; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if (para_Drawing === ItemType)
        {
            Item.Parent          = this.Paragraph;
            Item.DocumentContent = this.Paragraph.Parent;
            Item.DrawingDocument = this.Paragraph.Parent.DrawingDocument;
        }

        // TODO: Как только избавимся от para_End переделать здесь
        if ( para_End === ItemType )
        {
            var EndTextPr = this.Paragraph.Get_CompiledPr2(false).TextPr.Copy();
            EndTextPr.Merge(this.Paragraph.TextPr.Value);

            g_oTextMeasurer.SetTextPr( EndTextPr, this.Paragraph.Get_Theme());
            Item.Measure( g_oTextMeasurer, EndTextPr );

            continue;
        }

        Item.Measure( g_oTextMeasurer, Pr );

        if (para_Drawing === Item.Type)
        {
            // После автофигур надо заново выставлять настройки
            g_oTextMeasurer.SetTextPr(Pr, Theme);
            g_oTextMeasurer.SetFontSlot(fontslot_ASCII);
        }
    }

    this.RecalcInfo.Recalc  = true;
    this.RecalcInfo.Measure = false;
};
ParaRun.prototype.Recalculate_Measure2 = function(Metrics)
{
    var TAscent  = Metrics.Ascent;
    var TDescent = Metrics.Descent;

    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = this.Content[Index];
        var ItemType = Item.Type;

        if ( para_Text === ItemType )
        {
            var Temp = g_oTextMeasurer.Measure2(String.fromCharCode(Item.Value));

            if ( null === TAscent || TAscent < Temp.Ascent )
                TAscent = Temp.Ascent;

            if ( null === TDescent || TDescent > Temp.Ascent - Temp.Height )
                TDescent = Temp.Ascent - Temp.Height;
        }
    }

    Metrics.Ascent  = TAscent;
    Metrics.Descent = TDescent;
};

ParaRun.prototype.Recalculate_Range = function(PRS, ParaPr, Depth)
{
    if ( this.Paragraph !== PRS.Paragraph )
    {
        this.Paragraph = PRS.Paragraph;

        /*if(this.Type == para_Math_Run)
        {
            this.ArgSize   = PRS.ArgSize.value;
            this.bEqqArray = PRS.bEqqArray;
            this.Parent    = PRS.Parent;
        }*/
        this.RecalcInfo.TextPr = true;

        this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );
    }

    // Сначала измеряем элементы (можно вызывать каждый раз, внутри разруливается, чтобы измерялось 1 раз)

    this.Recalculate_MeasureContent();


    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );

    // Если мы рассчитываем первый отрезок в первой строке, тогда нам нужно обновить информацию о нумерации
    if ( 0 === CurRange && 0 === CurLine )
    {
        var PrevRecalcInfo = PRS.RunRecalcInfoLast;

        // Либо до этого ничего не было (изначально первая строка и первый отрезок), либо мы заново пересчитываем
        // первую строку и первый отрезок (из-за обтекания, например).
        if ( null === PrevRecalcInfo )
            this.RecalcInfo.NumberingAdd = true;
        else
            this.RecalcInfo.NumberingAdd = PrevRecalcInfo.NumberingAdd;

        this.RecalcInfo.NumberingUse  = false;
        this.RecalcInfo.NumberingItem = null;
    }

    // Сохраняем ссылку на информацию пересчета данного рана
    PRS.RunRecalcInfoLast = this.RecalcInfo;

    // Добавляем информацию о новом отрезке
    var RangeStartPos = this.protected_AddRange(CurLine, CurRange);
    var RangeEndPos   = 0;

    var Para = PRS.Paragraph;

    var MoveToLBP       = PRS.MoveToLBP;
    var NewRange        = PRS.NewRange;
    var ForceNewPage    = PRS.ForceNewPage;
    var NewPage         = PRS.NewPage;
    var BreakPageLine   = PRS.BreakPageLine;
    var End             = PRS.End;

    var Word            = PRS.Word;
    var StartWord       = PRS.StartWord;
    var FirstItemOnLine = PRS.FirstItemOnLine;
    var EmptyLine       = PRS.EmptyLine;

    var RangesCount     = PRS.RangesCount;

    var SpaceLen        = PRS.SpaceLen;
    var WordLen         = PRS.WordLen;

    var X               = PRS.X;
    var XEnd            = PRS.XEnd;

    var ParaLine        = PRS.Line;
    var ParaRange       = PRS.Range;

    var LineRule        = ParaPr.Spacing.LineRule;

    var Pos = RangeStartPos;

    var UpdateLineMetricsText = false;
    var ContentLen = this.Content.length;
    for ( ; Pos < ContentLen; Pos++ )
    {
        if ( false === StartWord && true === FirstItemOnLine && XEnd - X < 0.001 && RangesCount > 0 )
        {
            NewRange    = true;
            RangeEndPos = Pos;
            break;
        }

        var Item     = this.Content[Pos];
        var ItemType = Item.Type;

        // Проверяем, не нужно ли добавить нумерацию к данному элементу
        if ( true === this.RecalcInfo.NumberingAdd && true === Item.Can_AddNumbering() )
        {
            var TempRes = this.Internal_Recalculate_Numbering( Item, PRS.Paragraph, ParaPr, X, PRS.LineAscent, PRS.Page, PRS.Line, PRS.Range );

            X              = TempRes.X;
            PRS.LineAscent = TempRes.LineAscent;
        }

        switch( ItemType )
        {
            case para_Sym:
            case para_Text:
            {
                // Отмечаем, что началось слово
                StartWord = true;

                UpdateLineMetricsText = true;

                // При проверке, убирается ли слово, мы должны учитывать ширину предшествующих пробелов.
                var LetterLen = Item.Width / TEXTWIDTH_DIVIDER;//var LetterLen = Item.Get_Width();
                if ( true !== Word )
                {
                    // Слово только началось. Делаем следующее:
                    // 1) Если до него на строке ничего не было и данная строка не
                    //    имеет разрывов, тогда не надо проверять убирается ли слово в строке.
                    // 2) В противном случае, проверяем убирается ли слово в промежутке.

                    // Если слово только началось, и до него на строке ничего не было, и в строке нет разрывов, тогда не надо проверять убирается ли оно на строке.
                    if ( true !== FirstItemOnLine || false === Para.Internal_Check_Ranges(ParaLine, ParaRange) )
                    {
                        if ( X + SpaceLen + LetterLen > XEnd )
                        {
                            NewRange    = true;
                            RangeEndPos = Pos;
                        }
                    }

                    if ( true !== NewRange )
                    {
                        // Отмечаем начало нового слова
                        PRS.Set_LineBreakPos( Pos );
                        WordLen = LetterLen;
                        Word    = true;
                    }
                }
                else
                {
                    if ( X + SpaceLen + WordLen + LetterLen > XEnd )
                    {
                        if ( true === FirstItemOnLine )
                        {
                            // Слово оказалось единственным элементом в промежутке, и, все равно,
                            // не умещается целиком. Делаем следующее:
                            //
                            // 1) Если у нас строка без вырезов, тогда ставим перенос строки на
                            //    текущей позиции.
                            // 2) Если у нас строка с вырезом, и данный вырез не последний, тогда
                            //    ставим перенос внутри строки в начале слова.
                            // 3) Если у нас строка с вырезом и вырез последний, тогда ставим перенос
                            //    строки в начале слова.

                            if ( false === Para.Internal_Check_Ranges(ParaLine, ParaRange)  )
                            {
                                // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                                MoveToLBP = true;
                                NewRange  = true;
                            }
                            else
                            {
                                EmptyLine   = false;
                                X          += WordLen;

                                // Слово не убирается в отрезке, но, поскольку, слово 1 на строке и отрезок тоже 1,
                                // делим слово в данном месте
                                NewRange    = true;
                                RangeEndPos = Pos;
                            }
                        }
                        else
                        {
                            // Слово не убирается в отрезке. Переносим слово в следующий отрезок
                            MoveToLBP = true;
                            NewRange  = true;
                        }
                    }

                    if ( true !== NewRange )
                    {
                        // Мы убираемся в пределах данной строки. Прибавляем ширину буквы к ширине слова
                        WordLen += LetterLen;

                        // Если текущий символ с переносом, например, дефис, тогда на нем заканчивается слово
                        if (Item.Flags & PARATEXT_FLAGS_SPACEAFTER)//if ( true === Item.Is_SpaceAfter() )
                        {
                            // Добавляем длину пробелов до слова и ширину самого слова.
                            X += SpaceLen + WordLen;

                            Word            = false;
                            FirstItemOnLine = false;
                            EmptyLine       = false;
                            SpaceLen        = 0;
                            WordLen         = 0;
                        }
                    }
                }

                break;
            }
            case para_Space:
            {
                FirstItemOnLine = false;

                if ( true === Word )
                {
                    // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                    // убирается ли слово, мы это проверяем при добавленнии букв.
                    X += SpaceLen + WordLen;

                    Word        = false;
                    EmptyLine   = false;
                    SpaceLen    = 0;
                    WordLen     = 0;
                }

                // На пробеле не делаем перенос. Перенос строки или внутристрочный
                // перенос делаем при добавлении любого непробельного символа
                SpaceLen += Item.Width / TEXTWIDTH_DIVIDER;//SpaceLen += Item.Get_Width();

                break;
            }
            case para_Drawing:
            {
                if ( true === Item.Is_Inline() || true === Para.Parent.Is_DrawingShape() )
                {
                    if ( true !== Item.Is_Inline() )
                        Item.Set_DrawingType( drawing_Inline );

                    if ( true === StartWord )
                        FirstItemOnLine = false;

                    Item.YOffset = this.YOffset;

                    // Если до этого было слово, тогда не надо проверять убирается ли оно, но если стояли пробелы,
                    // тогда мы их учитываем при проверке убирается ли данный элемент, и добавляем только если
                    // данный элемент убирается
                    if ( true === Word || WordLen > 0 )
                    {
                        // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                        // убирается ли слово, мы это проверяем при добавленнии букв.
                        X += SpaceLen + WordLen;

                        Word        = false;
                        EmptyLine   = false;
                        SpaceLen    = 0;
                        WordLen     = 0;
                    }

                    var DrawingWidth = Item.Get_Width();
                    if ( X + SpaceLen + DrawingWidth > XEnd && ( false === FirstItemOnLine || false === Para.Internal_Check_Ranges( ParaLine, ParaRange ) ) )
                    {
                        // Автофигура не убирается, ставим перенос перед ней
                        NewRange    = true;
                        RangeEndPos = Pos;
                    }
                    else
                    {
                        // Обновим метрики строки
                        if ( linerule_Exact === LineRule )
                        {
                            if ( PRS.LineAscent < Item.Height )
                                PRS.LineAscent = Item.Height;
                        }
                        else
                        {
                            if ( PRS.LineAscent < Item.Height + this.YOffset )
                                PRS.LineAscent = Item.Height + this.YOffset;

                            if ( PRS.LineDescent < -this.YOffset )
                                PRS.LineDescent = -this.YOffset;
                        }

                        // Добавляем длину пробелов до автофигуры
                        X += SpaceLen + DrawingWidth;

                        FirstItemOnLine = false;
                        EmptyLine       = false;
                    }

                    SpaceLen    = 0;
                }
                else
                {
                    // Основная обработка происходит в Recalculate_Range_Spaces. Здесь обрабатывается единственный случай,
                    // когда после второго пересчета с уже добавленной картинкой оказывается, что место в параграфе, где
                    // идет картинка ушло на следующую страницу. В этом случае мы ставим перенос страницы перед картинкой.

                    var LogicDocument  = Para.Parent;
                    var LDRecalcInfo   = LogicDocument.RecalcInfo;
                    var DrawingObjects = LogicDocument.DrawingObjects;
                    var CurPage        = PRS.Page;

                    if ( true === LDRecalcInfo.Check_FlowObject(Item) && true === LDRecalcInfo.Is_PageBreakBefore() )
                    {
                        LDRecalcInfo.Reset();

                        // Добавляем разрыв страницы. Если это первая страница, тогда ставим разрыв страницы в начале параграфа,
                        // если нет, тогда в начале текущей строки.

                        if ( null != Para.Get_DocumentPrev() && true != Para.Parent.Is_TableCellContent() && 0 === CurPage )
                        {
                            Para.Recalculate_Drawing_AddPageBreak( 0, 0, true );
                            PRS.RecalcResult = recalcresult_NextPage;
                            PRS.NewRange = true;
                            return;
                        }
                        else
                        {
                            if ( ParaLine != Para.Pages[CurPage].FirstLine )
                            {
                                Para.Recalculate_Drawing_AddPageBreak( CurLine, CurPage, false );
                                PRS.RecalcResult = recalcresult_NextPage;
                                PRS.NewRange = true;
                                return;
                            }
                            else
                            {
                                RangeEndPos  = Pos;
                                NewRange     = true;
                                ForceNewPage = true;
                            }
                        }


                        // Если до этого было слово, тогда не надо проверять убирается ли оно
                        if ( true === Word || WordLen > 0 )
                        {
                            // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                            // убирается ли слово, мы это проверяем при добавленнии букв.
                            X += SpaceLen + WordLen;

                            Word        = false;
                            SpaceLen    = 0;
                            WordLen     = 0;
                        }
                    }
                }

                break;
            }
            case para_PageNum:
            {
                // Выставляем номер страницы

                var LogicDocument = Para.LogicDocument;
                var SectionPage   = LogicDocument.Get_SectionPageNumInfo2(PRS.Page + Para.Get_StartPage_Absolute()).CurPage;

                Item.Set_Page(SectionPage);

                // Если до этого было слово, тогда не надо проверять убирается ли оно, но если стояли пробелы,
                // тогда мы их учитываем при проверке убирается ли данный элемент, и добавляем только если
                // данный элемент убирается
                if ( true === Word || WordLen > 0 )
                {
                    // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                    // убирается ли слово, мы это проверяем при добавленнии букв.
                    X += SpaceLen + WordLen;

                    Word        = false;
                    EmptyLine   = false;
                    SpaceLen    = 0;
                    WordLen     = 0;
                }

                // Если на строке начиналось какое-то слово, тогда данная строка уже не пустая
                if ( true === StartWord )
                    FirstItemOnLine = false;

                UpdateLineMetricsText = true;

                var PageNumWidth = Item.Get_Width();
                if ( X + SpaceLen + PageNumWidth > XEnd && ( false === FirstItemOnLine || false === Para.Internal_Check_Ranges( ParaLine, ParaRange ) ) )
                {
                    // Данный элемент не убирается, ставим перенос перед ним
                    NewRange    = true;
                    RangeEndPos = Pos;
                }
                else
                {
                    // Добавляем длину пробелов до слова и ширину данного элемента
                    X += SpaceLen + PageNumWidth;

                    FirstItemOnLine = false;
                    EmptyLine       = false;
                }

                SpaceLen    = 0;

                break;
            }
            case para_Tab:
            {
                // Сначала проверяем, если у нас уже есть таб, которым мы должны рассчитать, тогда высчитываем
                // его ширину.

                X = this.Internal_Recalculate_LastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen);

                // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять
                // убирается ли слово, мы это проверяем при добавленнии букв.
                X += SpaceLen + WordLen;
                Word        = false;
                SpaceLen    = 0;
                WordLen     = 0;

                var TabPos = Para.Internal_GetTabPos(X, ParaPr, PRS.CurPage);
                var NewX     = TabPos.NewX;
                var TabValue = TabPos.TabValue;

                // Если таб не левый, значит он не может быть сразу рассчитан, а если левый, тогда
                // рассчитываем его сразу здесь
                if ( tab_Left !== TabValue )
                {
                    PRS.LastTab.TabPos = NewX;
                    PRS.LastTab.Value  = TabValue;
                    PRS.LastTab.X      = X;
                    PRS.LastTab.Item   = Item;

                    Item.Width        = 0;
                    Item.WidthVisible = 0;
                }
                else
                {
                    if ( NewX > XEnd && ( false === FirstItemOnLine || false === Para.Internal_Check_Ranges( ParaLine, ParaRange ) ) )
                    {
                        WordLen     = NewX - X;
                        RangeEndPos = Pos;
                        NewRange    = true;
                    }
                    else
                    {
                        Item.Width        = NewX - X;
                        Item.WidthVisible = NewX - X;

                        X = NewX;
                    }
                }

                // Если перенос идет по строке, а не из-за обтекания, тогда разрываем перед табом, а если
                // из-за обтекания, тогда разрываем перед последним словом, идущим перед табом
                if ( RangesCount === CurRange )
                {
                    if ( true === StartWord )
                    {
                        FirstItemOnLine = false;
                        EmptyLine       = false;
                    }
                }

                // Считаем, что с таба начинается слово
                PRS.Set_LineBreakPos( Pos );

                StartWord = true;
                Word      = true;

                break;
            }
            case para_NewLine:
            {
                // Сначала проверяем, если у нас уже есть таб, которым мы должны рассчитать, тогда высчитываем
                // его ширину.
                X = this.Internal_Recalculate_LastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen);

                X += WordLen;

                if ( true === Word )
                {
                    EmptyLine   = false;
                    Word        = false;
                    X          += SpaceLen;
                    SpaceLen    = 0;
                }

                if ( break_Page === Item.BreakType )
                {
                    if ( true === PRS.SkipPageBreak && Item === PRS.PageBreak )
                        continue;

                    Item.Flags.NewLine = true;

                    // PageBreak вне самого верхнего документа не надо учитывать
                    if ( !(Para.Parent instanceof CDocument) || true !== Para.Is_Inline() )
                    {
                        // TODO: Продумать, как избавиться от данного элемента, т.к. удалять его при пересчете нельзя,
                        //       иначе будут проблемы с совместным редактированием.

                        Item.Flags.Use = false;
                        continue;
                    }

                    NewPage       = true;
                    NewRange      = true;
                    BreakPageLine = true;

                    PRS.PageBreak = Item;
                }
                else
                {
                    NewRange  = true;
                    EmptyLine = false;
                }

                RangeEndPos = Pos + 1;

                break;
            }
            case para_End:
            {
                if ( true === Word )
                {
                    FirstItemOnLine = false;
                    EmptyLine       = false;
                }

                // false === PRS.ExtendBoundToBottom, потому что это уже делалось для PageBreak
                if ( false === PRS.ExtendBoundToBottom )
                {
                    X += WordLen;

                    if ( true === Word )
                    {
                        X += SpaceLen;
                        SpaceLen    = 0;
                        WordLen     = 0;
                    }

                    X = this.Internal_Recalculate_LastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen);
                }

                NewRange = true;
                End      = true;

                RangeEndPos = Pos + 1;

                break;
            }
        }

        if ( true === NewRange )
            break;
    }

    if ( true === UpdateLineMetricsText )
    {
        // Пересчитаем метрику строки относительно размера данного текста
        if ( PRS.LineTextAscent < this.TextAscent )
            PRS.LineTextAscent = this.TextAscent;

        if ( PRS.LineTextAscent2 < this.TextAscent2 )
            PRS.LineTextAscent2 = this.TextAscent2;

        if ( PRS.LineTextDescent < this.TextDescent )
            PRS.LineTextDescent = this.TextDescent;

        if ( linerule_Exact === LineRule )
        {
            // Смещение не учитывается в метриках строки, когда расстояние между строк точное
            if ( PRS.LineAscent < this.TextAscent )
                PRS.LineAscent = this.TextAscent;

            if ( PRS.LineDescent < this.TextDescent )
                PRS.LineDescent = this.TextDescent;
        }
        else
        {
            if ( PRS.LineAscent < this.TextAscent + this.YOffset  )
                PRS.LineAscent = this.TextAscent + this.YOffset;

            if ( PRS.LineDescent < this.TextDescent - this.YOffset )
                PRS.LineDescent = this.TextDescent - this.YOffset;
        }
    }

    PRS.MoveToLBP       = MoveToLBP;
    PRS.NewRange        = NewRange;
    PRS.ForceNewPage    = ForceNewPage;
    PRS.NewPage         = NewPage;
    PRS.BreakPageLine   = BreakPageLine;
    PRS.End             = End;

    PRS.Word            = Word;
    PRS.StartWord       = StartWord;
    PRS.FirstItemOnLine = FirstItemOnLine;
    PRS.EmptyLine       = EmptyLine;

    PRS.SpaceLen        = SpaceLen;
    PRS.WordLen         = WordLen;

    PRS.X               = X;
    PRS.XEnd            = XEnd;

    if ( Pos >= ContentLen )
    {
        RangeEndPos = Pos;
    }

    this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos);

    this.RecalcInfo.Recalc = false;
};

ParaRun.prototype.Recalculate_Set_RangeEndPos = function(PRS, PRP, Depth)
{
    var CurLine  = PRS.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range );
    var CurPos   = PRP.Get(Depth);

    this.protected_FillRangeEndPos(CurLine, CurRange, CurPos);
};

ParaRun.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch( ItemType )
        {
            case para_Sym:
            case para_Text:
            {
                PRSC.Letters++;

                if ( true !== PRSC.Word )
                {
                    PRSC.Word = true;
                    PRSC.Words++;
                }

                PRSC.Range.W += Item.Width / TEXTWIDTH_DIVIDER;//Item.Get_Width();
                PRSC.Range.W += PRSC.SpaceLen;

                PRSC.SpaceLen = 0;

                // Пробелы перед первым словом в строке не считаем
                if (PRSC.Words > 1)
                    PRSC.Spaces += PRSC.SpacesCount;
                else
                    PRSC.SpacesSkip += PRSC.SpacesCount;

                PRSC.SpacesCount = 0;

                // Если текущий символ, например, дефис, тогда на нем заканчивается слово
                if (Item.Flags & PARATEXT_FLAGS_SPACEAFTER)//if ( true === Item.Is_SpaceAfter() )
                    PRSC.Word = false;

                break;
            }
            case para_Space:
            {
                if ( true === PRSC.Word )
                {
                    PRSC.Word        = false;
                    PRSC.SpacesCount = 1;
                    PRSC.SpaceLen    = Item.Width / TEXTWIDTH_DIVIDER;//Item.Get_Width();
                }
                else
                {
                    PRSC.SpacesCount++;
                    PRSC.SpaceLen += Item.Width / TEXTWIDTH_DIVIDER;//Item.Get_Width();
                }

                break;
            }
            case para_Drawing:
            {
                PRSC.Words++;
                PRSC.Range.W += PRSC.SpaceLen;

                if (PRSC.Words > 1)
                    PRSC.Spaces += PRSC.SpacesCount;
                else
                    PRSC.SpacesSkip += PRSC.SpacesCount;

                PRSC.Word        = false;
                PRSC.SpacesCount = 0;
                PRSC.SpaceLen    = 0;

                if ( true === Item.Is_Inline() || true === PRSC.Paragraph.Parent.Is_DrawingShape() )
                    PRSC.Range.W += Item.Get_Width();

                break;
            }
            case para_PageNum:
            {
                PRSC.Words++;
                PRSC.Range.W += PRSC.SpaceLen;

                if (PRSC.Words > 1)
                    PRSC.Spaces += PRSC.SpacesCount;
                else
                    PRSC.SpacesSkip += PRSC.SpacesCount;

                PRSC.Word        = false;
                PRSC.SpacesCount = 0;
                PRSC.SpaceLen    = 0;

                PRSC.Range.W += Item.Get_Width();

                break;
            }
            case para_Tab:
            {
                PRSC.Range.W += Item.Get_Width();
                PRSC.Range.W += PRSC.SpaceLen;

                // Учитываем только слова и пробелы, идущие после последнего таба

                PRSC.LettersSkip += PRSC.Letters;
                PRSC.SpacesSkip  += PRSC.Spaces;

                PRSC.Words   = 0;
                PRSC.Spaces  = 0;
                PRSC.Letters = 0;

                PRSC.SpaceLen    = 0;
                PRSC.SpacesCount = 0;
                PRSC.Word        = false;

                break;
            }

            case para_NewLine:
            {
                if (true === PRSC.Word && PRSC.Words > 1)
                    PRSC.Spaces += PRSC.SpacesCount;

                PRSC.SpacesCount = 0;
                PRSC.Word        = false;

                break;
            }
            case para_End:
            {
                if ( true === PRSC.Word )
                    PRSC.Spaces += PRSC.SpacesCount;

                break;
            }
        }
    }
};

ParaRun.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, CurPage)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch( ItemType )
        {
            case para_Sym:
            case para_Text:
            {
                var WidthVisible = 0;

                if ( 0 !== PRSA.LettersSkip )
                {
                    WidthVisible = Item.Width / TEXTWIDTH_DIVIDER;//WidthVisible = Item.Get_Width();
                    PRSA.LettersSkip--;
                }
                else
                    WidthVisible = Item.Width / TEXTWIDTH_DIVIDER + PRSA.JustifyWord;//WidthVisible = Item.Get_Width() + PRSA.JustifyWord;

                Item.WidthVisible = (WidthVisible * TEXTWIDTH_DIVIDER) | 0;//Item.Set_WidthVisible(WidthVisible);

                PRSA.X    += WidthVisible;
                PRSA.LastW = WidthVisible;

                break;
            }
            case para_Space:
            {
                var WidthVisible = Item.Width / TEXTWIDTH_DIVIDER;//WidthVisible = Item.Get_Width();

                if ( 0 !== PRSA.SpacesSkip )
                {
                    PRSA.SpacesSkip--;
                }
                else if ( 0 !== PRSA.SpacesCounter )
                {
                    WidthVisible += PRSA.JustifySpace;
                    PRSA.SpacesCounter--;
                }

                Item.WidthVisible = (WidthVisible * TEXTWIDTH_DIVIDER) | 0;//Item.Set_WidthVisible(WidthVisible);

                PRSA.X    += WidthVisible;
                PRSA.LastW = WidthVisible;

                break;
            }
            case para_Drawing:
            {
                var Para = PRSA.Paragraph;

                var LogicDocument = this.Paragraph.LogicDocument;
                var LD_PageLimits = LogicDocument.Get_PageLimits( CurPage );
                var LD_PageFields = LogicDocument.Get_PageFields( CurPage );

                var Page_Width  = LD_PageLimits.XLimit;
                var Page_Height = LD_PageLimits.YLimit;

                var X_Left_Field   = LD_PageFields.X;
                var Y_Top_Field    = LD_PageFields.Y;
                var X_Right_Field  = LD_PageFields.XLimit;
                var Y_Bottom_Field = LD_PageFields.YLimit;

                var X_Left_Margin   = X_Left_Field;
                var X_Right_Margin  = Page_Width  - X_Right_Field;
                var Y_Bottom_Margin = Page_Height - Y_Bottom_Field;
                var Y_Top_Margin    = Y_Top_Field;

                var DrawingObjects = Para.Parent.DrawingObjects;
                var PageLimits     = Para.Parent.Get_PageLimits(Para.PageNum + CurPage);
                var PageFields     = Para.Parent.Get_PageFields(Para.PageNum + CurPage);

                var ColumnStartX = (0 === CurPage ? Para.X_ColumnStart : Para.Pages[CurPage].X     );
                var ColumnEndX   = (0 === CurPage ? Para.X_ColumnEnd   : Para.Pages[CurPage].XLimit);

                var Top_Margin    = Y_Top_Margin;
                var Bottom_Margin = Y_Bottom_Margin;
                var Page_H        = Page_Height;

                if ( true === Para.Parent.Is_TableCellContent() && true == Item.Use_TextWrap() )
                {
                    Top_Margin    = 0;
                    Bottom_Margin = 0;
                    Page_H        = 0;
                }

                if ( true != Item.Use_TextWrap() )
                {
                    PageFields.X      = X_Left_Field;
                    PageFields.Y      = Y_Top_Field;
                    PageFields.XLimit = X_Right_Field;
                    PageFields.YLimit = Y_Bottom_Field;

                    PageLimits.X = 0;
                    PageLimits.Y = 0;
                    PageLimits.XLimit = Page_Width;
                    PageLimits.YLimit = Page_Height;
                }

                if ( true === Item.Is_Inline() || true === Para.Parent.Is_DrawingShape() )
                {
                    Item.Update_Position( new CParagraphLayout( PRSA.X, PRSA.Y , Para.Get_StartPage_Absolute() + CurPage, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[CurPage].Y), PageLimits );
                    Item.Reset_SavedPosition();

                    PRSA.X    += Item.WidthVisible;
                    PRSA.LastW = Item.WidthVisible;
                }
                else
                {
                    if ( true === PRSA.RecalcFast )
                    {
                        // Если у нас быстрый пересчет, тогда мы не трогаем плавающие картинки
                        // TODO: Если здесь привязка к символу, тогда быстрый пересчет надо отменить
                        break;
                    }

                    if (true === PRSA.RecalcFast2)
                    {
                        // Тут мы должны сравнить положение картинок

                        var oRecalcObj = Item.Save_RecalculateObject();
                        var Page_abs   = Para.Get_StartPage_Absolute() + CurPage;
                        Item.Update_Position( new CParagraphLayout( PRSA.X, PRSA.Y , Page_abs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[CurPage].Y), PageLimits);

                        if (Math.abs(Item.X - oRecalcObj.X) > 0.001 || Math.abs(Item.Y - oRecalcObj.Y) > 0.001 || Item.PageNum !== oRecalcObj.PageNum)
                        {
                            // Положение картинок не совпало, отправляем пересчет текущей страницы.
                            PRSA.RecalcResult = recalcresult_CurPage;
                            return;
                        }

                        break;
                    }

                    // У нас Flow-объект. Если он с обтеканием, тогда мы останавливаем пересчет и
                    // запоминаем текущий объект. В функции Internal_Recalculate_2 пересчитываем
                    // его позицию и сообщаем ее внешнему классу.

                    if ( true === Item.Use_TextWrap() )
                    {
                        var LogicDocument = Para.Parent;
                        var LDRecalcInfo  = Para.Parent.RecalcInfo;
                        var Page_abs      = Para.Get_StartPage_Absolute() + CurPage;

                        if ( true === LDRecalcInfo.Can_RecalcObject() )
                        {
                            // Обновляем позицию объекта
                            Item.Update_Position( new CParagraphLayout( PRSA.X, PRSA.Y , Page_abs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[CurPage].Y), PageLimits);
                            LDRecalcInfo.Set_FlowObject( Item, 0, recalcresult_NextElement, -1 );

                            if (0 === PRSA.CurPage && Item.wrappingPolygon.top > PRSA.PageY + 0.001)
                                PRSA.RecalcResult = recalcresult_CurPagePara;
                            else
                                PRSA.RecalcResult = recalcresult_CurPage;

                            return;
                        }
                        else if ( true === LDRecalcInfo.Check_FlowObject(Item) )
                        {
                            // Если мы находимся с таблице, тогда делаем как Word, не пересчитываем предыдущую страницу,
                            // даже если это необходимо. Такое поведение нужно для точного определения рассчиталась ли
                            // данная страница окончательно или нет. Если у нас будет ветка с переходом на предыдущую страницу,
                            // тогда не рассчитав следующую страницу мы о конечном рассчете текущей страницы не узнаем.

                            // Если данный объект нашли, значит он уже был рассчитан и нам надо проверить номер страницы
                            if ( Item.PageNum === Page_abs )
                            {
                                // Все нормально, можно продолжить пересчет
                                LDRecalcInfo.Reset();
                                Item.Reset_SavedPosition();
                            }
                            else if ( true === Para.Parent.Is_TableCellContent() )
                            {
                                // Картинка не на нужной странице, но так как это таблица
                                // мы пересчитываем заново текущую страницу, а не предыдущую

                                // Обновляем позицию объекта
                                Item.Update_Position( new CParagraphLayout( PRSA.X, PRSA.Y, Page_abs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[CurPage].Y), PageLimits);

                                LDRecalcInfo.Set_FlowObject( Item, 0, recalcresult_NextElement, -1 );
                                LDRecalcInfo.Set_PageBreakBefore( false );
                                PRSA.RecalcResult = recalcresult_CurPage;
                                return;
                            }
                            else
                            {
                                LDRecalcInfo.Set_PageBreakBefore( true );
                                DrawingObjects.removeById( Item.PageNum, Item.Get_Id() );
                                PRSA.RecalcResult = recalcresult_PrevPage;
                                return;
                            }
                        }
                        else
                        {
                            // Либо данный элемент уже обработан, либо будет обработан в будущем
                        }

                        continue;
                    }
                    else
                    {
                        // Картинка ложится на или под текст, в данном случае пересчет можно спокойно продолжать
                        Item.Update_Position( new CParagraphLayout( PRSA.X, PRSA.Y , Para.Get_StartPage_Absolute() + CurPage, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[CurPage].Y), PageLimits);
                        Item.Reset_SavedPosition();
                    }
                }


                break;
            }
            case para_PageNum:
            {
                PRSA.X    += Item.WidthVisible;
                PRSA.LastW = Item.WidthVisible;

                break;
            }
            case para_Tab:
            {
                PRSA.X += Item.WidthVisible;

                break;
            }
            case para_End:
            {
                var SectPr = PRSA.Paragraph.Get_SectionPr();
                if ( undefined !== SectPr )
                {
                    // Нас интересует следующая секция
                    var LogicDocument = PRSA.Paragraph.LogicDocument;
                    var NextSectPr = LogicDocument.SectionsInfo.Get_SectPr(PRSA.Paragraph.Index + 1).SectPr;

                    Item.Update_SectionPr(NextSectPr, PRSA.XEnd - PRSA.X);
                }
                else
                    Item.Clear_SectionPr();

                PRSA.X += Item.Get_Width();

                break;
            }
            case para_NewLine:
            {
                if ( break_Page === Item.BreakType )
                    Item.Update_String( PRSA.XEnd - PRSA.X );

                PRSA.X += Item.WidthVisible;

                break;
            }
        }
    }
};

ParaRun.prototype.Recalculate_PageEndInfo = function(PRSI, _CurLine, _CurRange)
{
};

ParaRun.prototype.Internal_Recalculate_Numbering = function(Item, Para, ParaPr, _X, _LineAscent, CurPage, CurLine, CurRange)
{
    var X = _X, LineAscent = _LineAscent;

    // Если нужно добавить нумерацию и на текущем элементе ее можно добавить, тогда добавляем её
    var NumberingItem = Para.Numbering;
    var NumberingType = Para.Numbering.Type;

    if ( para_Numbering === NumberingType )
    {
        var NumPr = ParaPr.NumPr;
        if ( undefined === NumPr || undefined === NumPr.NumId || 0 === NumPr.NumId || "0" === NumPr.NumId || ( undefined !== Para.Get_SectionPr() && true === Para.IsEmpty() ) )
        {
            // Так мы обнуляем все рассчитанные ширины данного элемента
            NumberingItem.Measure( g_oTextMeasurer, undefined );
        }
        else
        {
            var Numbering = Para.Parent.Get_Numbering();
            var NumLvl    = Numbering.Get_AbstractNum( NumPr.NumId ).Lvl[NumPr.Lvl];
            var NumSuff   = NumLvl.Suff;
            var NumJc     = NumLvl.Jc;
            var NumInfo   = Para.Parent.Internal_GetNumInfo( Para.Id, NumPr );
            var NumTextPr = Para.Get_CompiledPr2(false).TextPr.Copy();
            NumTextPr.Merge( Para.TextPr.Value );
            NumTextPr.Merge( NumLvl.TextPr );


            // Здесь измеряется только ширина символов нумерации, без суффикса
            NumberingItem.Measure( g_oTextMeasurer, Numbering, NumInfo, NumTextPr, NumPr, Para.Get_Theme() );

            // При рассчете высоты строки, если у нас параграф со списком, то размер символа
            // в списке влияет только на высоту строки над Baseline, но не влияет на высоту строки
            // ниже baseline.
            if ( LineAscent < NumberingItem.Height )
                LineAscent = NumberingItem.Height;

            switch ( NumJc )
            {
                case align_Right:
                {
                    NumberingItem.WidthVisible = 0;
                    break;
                }
                case align_Center:
                {
                    NumberingItem.WidthVisible = NumberingItem.WidthNum / 2;
                    break;
                }
                case align_Left:
                default:
                {
                    NumberingItem.WidthVisible = NumberingItem.WidthNum;
                    break;
                }
            }

            X += NumberingItem.WidthVisible;

            switch( NumSuff )
            {
                case numbering_suff_Nothing:
                {
                    // Ничего не делаем
                    break;
                }
                case numbering_suff_Space:
                {
                    var OldTextPr = g_oTextMeasurer.GetTextPr();



                    var Theme = Para.Get_Theme();
                    g_oTextMeasurer.SetTextPr( NumTextPr, Theme );
                    g_oTextMeasurer.SetFontSlot( fontslot_ASCII );
                    NumberingItem.WidthSuff = g_oTextMeasurer.Measure( " " ).Width;
                    g_oTextMeasurer.SetTextPr( OldTextPr, Theme );
                    break;
                }
                case numbering_suff_Tab:
                {
                    var NewX = Para.Internal_GetTabPos(X, ParaPr, CurPage).NewX;

                    NumberingItem.WidthSuff = NewX - X;

                    break;
                }
            }

            NumberingItem.Width         = NumberingItem.WidthNum;
            NumberingItem.WidthVisible += NumberingItem.WidthSuff;

            X += NumberingItem.WidthSuff;
        }
    }
    else if ( para_PresentationNumbering === NumberingType )
    {
        var Level = Para.PresentationPr.Level;
        var Bullet = Para.PresentationPr.Bullet;

        var BulletNum = 0;
        if (Bullet.Get_Type() >= numbering_presentationnumfrmt_ArabicPeriod)
        {
            var Prev = Para.Prev;
            while (null != Prev && type_Paragraph === Prev.GetType())
            {
                var PrevLevel = Prev.PresentationPr.Level;
                var PrevBullet = Prev.Get_PresentationNumbering();

                // Если предыдущий параграф более низкого уровня, тогда его не учитываем
                if (Level < PrevLevel)
                {
                    Prev = Prev.Prev;
                    continue;
                }
                else if (Level > PrevLevel)
                    break;
                else if (PrevBullet.Get_Type() === Bullet.Get_Type() && PrevBullet.Get_StartAt() === PrevBullet.Get_StartAt())
                {
                    if (true != Prev.IsEmpty())
                        BulletNum++;

                    Prev = Prev.Prev;
                }
                else
                    break;
            }
        }

        // Найдем настройки для первого текстового элемента
        var FirstTextPr = Para.Get_FirstTextPr();

        NumberingItem.Bullet = Bullet;
        NumberingItem.BulletNum = BulletNum + 1;
        NumberingItem.Measure(g_oTextMeasurer, FirstTextPr, Para.Get_Theme());


        if ( numbering_presentationnumfrmt_None != Bullet.Get_Type() )
        {
            if ( ParaPr.Ind.FirstLine < 0 )
                NumberingItem.WidthVisible = Math.max( NumberingItem.Width, Para.X + ParaPr.Ind.Left + ParaPr.Ind.FirstLine - X, Para.X + ParaPr.Ind.Left - X );
            else
                NumberingItem.WidthVisible = Math.max( Para.X + ParaPr.Ind.Left + NumberingItem.Width - X, Para.X + ParaPr.Ind.Left + ParaPr.Ind.FirstLine - X, Para.X + ParaPr.Ind.Left - X );
        }

        X += NumberingItem.WidthVisible;
    }

    // Запоминаем, что на данном элементе была добавлена нумерация
    this.RecalcInfo.NumberingAdd  = false;
    this.RecalcInfo.NumberingUse  = true;
    this.RecalcInfo.NumberingItem = NumberingItem;

    // Заполним обратные данные в элементе нумерации
    NumberingItem.Item  = Item;
    NumberingItem.Run   = this;

    NumberingItem.Line  = CurLine;
    NumberingItem.Range = CurRange;

    return { X : X, LineAscent : LineAscent };
};

ParaRun.prototype.Internal_Recalculate_LineMetrics = function(PRS, SpacingLineRule)
{
    if ( PRS.LineTextAscent < this.TextAscent )
        PRS.LineTextAscent = this.TextAscent;

    if ( PRS.LineTextAscent2 < this.TextAscent2 )
        PRS.LineTextAscent2 = this.TextAscent2;

    if ( PRS.LineTextDescent < this.TextDescent )
        PRS.LineTextDescent = this.TextDescent;

    if ( linerule_Exact === SpacingLineRule )
    {
        // Смещение не учитывается в метриках строки, когда расстояние между строк точное
        if ( PRS.LineAscent < this.TextAscent )
            PRS.LineAscent = this.TextAscent;

        if ( PRS.LineDescent < this.TextDescent )
            PRS.LineDescent = this.TextDescent;
    }
    else
    {
        if ( PRS.LineAscent < this.TextAscent + this.YOffset  )
            PRS.LineAscent = this.TextAscent + this.YOffset;

        if ( PRS.LineDescent < this.TextDescent - this.YOffset )
            PRS.LineDescent = this.TextDescent - this.YOffset;
    }
};

ParaRun.prototype.Internal_Recalculate_LastTab = function(LastTab, X, XEnd, Word, WordLen, SpaceLen)
{
    if ( -1 !== LastTab.Value )
    {
        var TempXPos = X;

        if ( true === Word || WordLen > 0 )
            TempXPos += SpaceLen + WordLen;

        var TabItem   = LastTab.Item;
        var TabStartX = LastTab.X;
        var TabRangeW = TempXPos - TabStartX;
        var TabValue  = LastTab.Value;
        var TabPos    = LastTab.TabPos;

        var TabCalcW = 0;
        if ( tab_Right === TabValue )
            TabCalcW = Math.max( TabPos - (TabStartX + TabRangeW), 0 );
        else if ( tab_Center === TabValue )
            TabCalcW = Math.max( TabPos - (TabStartX + TabRangeW / 2), 0 );

        if ( X + TabCalcW > XEnd )
            TabCalcW = XEnd - X;

        TabItem.Width        = TabCalcW;
        TabItem.WidthVisible = TabCalcW;

        LastTab.Reset();

        return X + TabCalcW;
    }

    return X;
};

ParaRun.prototype.Refresh_RecalcData = function(Data)
{
    var Para = this.Paragraph;

    if(this.Type == para_Math_Run)
    {
        if(this.Parent !== null && this.Parent !== undefined)
        {
            this.Parent.Refresh_RecalcData();
        }
    }
    else if ( -1 !== this.StartLine && undefined !== Para )
    {
        var CurLine = this.StartLine;

        var PagesCount = Para.Pages.length;
        for (var CurPage = 0 ; CurPage < PagesCount; CurPage++ )
        {
            var Page = Para.Pages[CurPage];
            if ( Page.StartLine <= CurLine && Page.EndLine >= CurLine  )
            {
                Para.Refresh_RecalcData2(CurPage);
                return;
            }

        }

        Para.Refresh_RecalcData2(0);
    }
};

ParaRun.prototype.Save_RecalculateObject = function(Copy)
{
    var RecalcObj = new CRunRecalculateObject(this.StartLine, this.StartRange);
    RecalcObj.Save_Lines( this, Copy );
    RecalcObj.Save_RunContent( this, Copy );
    return RecalcObj;
};

ParaRun.prototype.Load_RecalculateObject = function(RecalcObj)
{
    RecalcObj.Load_Lines(this);
    RecalcObj.Load_RunContent(this);
};

ParaRun.prototype.Prepare_RecalculateObject = function()
{
    this.protected_ClearLines();

    var Count = this.Content.length;
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = this.Content[Index];
        var ItemType = Item.Type;

        if ( para_PageNum === ItemType || para_Drawing === ItemType )
            Item.Prepare_RecalculateObject();
    }
};

ParaRun.prototype.Is_EmptyRange = function(_CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    if ( EndPos <= StartPos )
        return true;

    return false;
};

ParaRun.prototype.Check_Range_OnlyMath = function(Checker, _CurRange, _CurLine)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for (var Pos = StartPos; Pos < EndPos; Pos++)
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if (para_End === ItemType || para_NewLine === ItemType || (para_Drawing === ItemType && true !== Item.Is_Inline()))
            continue;
        else
        {
            Checker.Result = false;
            Checker.Math   = null;
            break;
        }
    }
};

ParaRun.prototype.Check_MathPara = function(Checker)
{
    var Count = this.Content.length;
    if ( Count <= 0 )
        return;

    var Item = ( Checker.Direction > 0 ? this.Content[0] : this.Content[Count - 1] );
    var ItemType = Item.Type;

    if ( para_End === ItemType || para_NewLine === ItemType )
    {
        Checker.Result = true;
        Checker.Found  = true;
    }
    else
    {
        Checker.Result = false;
        Checker.Found  = true;
    }
};

ParaRun.prototype.Check_PageBreak = function()
{
    var Count = this.Content.length;
    for (var Pos = 0; Pos < Count; Pos++)
    {
        var Item = this.Content[Pos];
        if (para_NewLine === Item.Type && break_Page === Item.BreakType)
            return true;
    }

    return false;
};

ParaRun.prototype.Check_BreakPageEnd = function(PBChecker)
{
    var ContentLen = this.Content.length;
    for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
    {
        var Item = this.Content[CurPos];

        if ( true === PBChecker.FindPB )
        {
            if ( Item === PBChecker.PageBreak )
            {
                PBChecker.FindPB = false;
                PBChecker.PageBreak.Flags.NewLine = true;
            }
        }
        else
        {
            var ItemType = Item.Type;

            if ( para_End === ItemType )
                return true;
            else if ( para_Drawing !== ItemType || drawing_Anchor !== Item.Get_DrawingType() )
                return false;
        }
    }

    return true;
};

ParaRun.prototype.Recalculate_MinMaxContentWidth = function(MinMax)
{
    this.Recalculate_MeasureContent();

    var bWord        = MinMax.bWord;
    var nWordLen     = MinMax.nWordLen;
    var nSpaceLen    = MinMax.nSpaceLen;
    var nMinWidth    = MinMax.nMinWidth;
    var nMaxWidth    = MinMax.nMaxWidth;
    var nCurMaxWidth = MinMax.nCurMaxWidth;

    var Count = this.Content.length;
    for ( var Pos = 0; Pos < Count; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch( ItemType )
        {
            case para_Text:
            {
                var ItemWidth = Item.Width / TEXTWIDTH_DIVIDER;//var ItemWidth = Item.Get_Width();
                if ( false === bWord )
                {
                    bWord    = true;
                    nWordLen = ItemWidth;
                }
                else
                {
                    nWordLen += ItemWidth;

                    if (Item.Flags & PARATEXT_FLAGS_SPACEAFTER)
                    {
                        if ( nMinWidth < nWordLen )
                            nMinWidth = nWordLen;

                        bWord    = false;
                        nWordLen = 0;
                    }
                }

                if ( nSpaceLen > 0 )
                {
                    nCurMaxWidth += nSpaceLen;
                    nSpaceLen     = 0;
                }

                nCurMaxWidth += ItemWidth;

                break;
            }

            case para_Space:
            {
                if ( true === bWord )
                {
                    if ( nMinWidth < nWordLen )
                        nMinWidth = nWordLen;

                    bWord    = false;
                    nWordLen = 0;
                }

                // Мы сразу не добавляем ширину пробелов к максимальной ширине, потому что
                // пробелы, идущие в конце параграфа или перед переносом строки(явным), не
                // должны учитываться.
                nSpaceLen += Item.Width / TEXTWIDTH_DIVIDER;//nSpaceLen += Item.Get_Width();

                break;
            }

            case para_Drawing:
            {
                if ( true === bWord )
                {
                    if ( nMinWidth < nWordLen )
                        nMinWidth = nWordLen;

                    bWord    = false;
                    nWordLen = 0;
                }

                if ( ( true === Item.Is_Inline() || true === this.Paragraph.Parent.Is_DrawingShape() ) && Item.Width > nMinWidth )
                    nMinWidth = Item.Width;

                if ( nSpaceLen > 0 )
                {
                    nCurMaxWidth += nSpaceLen;
                    nSpaceLen     = 0;
                }

                if ( true === Item.Is_Inline() || true === this.Paragraph.Parent.Is_DrawingShape() )
                    nCurMaxWidth += Item.Width;

                break;
            }

            case para_PageNum:
            {
                if ( true === bWord )
                {
                    if ( nMinWidth < nWordLen )
                        nMinWidth = nWordLen;

                    bWord    = false;
                    nWordLen = 0;
                }

                if ( Item.Width > nMinWidth )
                    nMinWidth = Item.Width;

                if ( nSpaceLen > 0 )
                {
                    nCurMaxWidth += nSpaceLen;
                    nSpaceLen     = 0;
                }

                nCurMaxWidth += Item.Width;

                break;
            }

            case para_Tab:
            {
                nWordLen += Item.Width;

                if ( nMinWidth < nWordLen )
                    nMinWidth = nWordLen;

                bWord    = false;
                nWordLen = 0;

                if ( nSpaceLen > 0 )
                {
                    nCurMaxWidth += nSpaceLen;
                    nSpaceLen     = 0;
                }

                nCurMaxWidth += Item.Width;

                break;
            }

            case para_NewLine:
            {
                if ( nMinWidth < nWordLen )
                    nMinWidth = nWordLen;

                bWord    = false;
                nWordLen = 0;

                nSpaceLen = 0;

                if ( nCurMaxWidth > nMaxWidth )
                    nMaxWidth = nCurMaxWidth;

                nCurMaxWidth = 0;

                break;
            }

            case para_End:
            {
                if ( nMinWidth < nWordLen )
                    nMinWidth = nWordLen;

                if ( nCurMaxWidth > nMaxWidth )
                    nMaxWidth = nCurMaxWidth;

                break;
            }
        }
    }

    MinMax.bWord        = bWord;
    MinMax.nWordLen     = nWordLen;
    MinMax.nSpaceLen    = nSpaceLen;
    MinMax.nMinWidth    = nMinWidth;
    MinMax.nMaxWidth    = nMaxWidth;
    MinMax.nCurMaxWidth = nCurMaxWidth;
};

ParaRun.prototype.Get_Range_VisibleWidth = function(RangeW, _CurLine, _CurRange)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        switch( ItemType )
        {
            case para_Sym:
            case para_Text:
            case para_Space:
            {
                RangeW.W += Item.Get_WidthVisible();

                break;
            }

            case para_Drawing:
            {
                if ( true === Item.Is_Inline() )
                    RangeW.W += Item.Width;

                break;
            }
            case para_PageNum:
            case para_Tab:
            {
                RangeW.W += Item.Width;
                break;
            }
            case para_NewLine:
            {
                RangeW.W += Item.WidthVisible;

                break;
            }
            case para_End:
            {
                RangeW.W += Item.Get_WidthVisible();
                RangeW.End = true;

                break;
            }
        }
    }
};

ParaRun.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];

        if ( para_Drawing === Item.Type )
            Item.Shift( Dx, Dy );
    }
};
//-----------------------------------------------------------------------------------
// Функции отрисовки
//-----------------------------------------------------------------------------------
ParaRun.prototype.Draw_HighLights = function(PDSH)
{
    var pGraphics = PDSH.Graphics;

    var CurLine   = PDSH.Line - this.StartLine;
    var CurRange  = ( 0 === CurLine ? PDSH.Range - this.StartRange : PDSH.Range );

    var aHigh     = PDSH.High;
    var aColl     = PDSH.Coll;
    var aFind     = PDSH.Find;
    var aComm     = PDSH.Comm;
    var aShd      = PDSH.Shd;

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Para     = PDSH.Paragraph;
    var SearchResults = Para.SearchResults;

    var bDrawFind = PDSH.DrawFind;
    var bDrawColl = PDSH.DrawColl;

    var oShd = this.Get_CompiledPr(false).Shd;
    var bDrawShd  = ( oShd === undefined || shd_Nil === oShd.Value ? false : true );
    var ShdColor  = ( true === bDrawShd ? oShd.Get_Color( PDSH.Paragraph ) : null );

    var X  = PDSH.X;
    var Y0 = PDSH.Y0;
    var Y1 = PDSH.Y1;

    var CommentsCount = PDSH.Comments.length;
    var CommentId     = ( CommentsCount > 0 ? PDSH.Comments[CommentsCount - 1] : null );
    var CommentsFlag  = PDSH.CommentsFlag;

    var HighLight = this.Get_CompiledPr(false).HighLight;

    var SearchMarksCount = this.SearchMarks.length;

    this.CollaborativeMarks.Init_Drawing();

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType         = Item.Type;
        var ItemWidthVisible = Item.Get_WidthVisible();

        // Определим попадание в поиск и совместное редактирование. Попадание в комментарий определять не надо,
        // т.к. класс CParaRun попадает или не попадает в комментарий целиком.

        for ( var SPos = 0; SPos < SearchMarksCount; SPos++)
        {
            var Mark = this.SearchMarks[SPos];
            var MarkPos = Mark.SearchResult.StartPos.Get(Mark.Depth);

            if ( Pos === MarkPos && true === Mark.Start )
                PDSH.SearchCounter++;
        }

        var DrawSearch = ( PDSH.SearchCounter > 0 && true === bDrawFind ? true : false );

        var DrawColl = this.CollaborativeMarks.Check( Pos );

        if ( true === bDrawShd )
            aShd.Add( Y0, Y1, X, X + ItemWidthVisible, 0, ShdColor.r, ShdColor.g, ShdColor.b );

        switch( ItemType )
        {
            case para_PageNum:
            case para_Drawing:
            case para_Tab:
            case para_Text:
            case para_Sym:
            {
                if ( para_Drawing === ItemType && drawing_Anchor === Item.DrawingType )
                    break;

                if ( CommentsFlag != comments_NoComment )
                    aComm.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0, { Active : CommentsFlag === comments_ActiveComment ? true : false, CommentId : CommentId } );
                else if ( highlight_None != HighLight )
                    aHigh.Add( Y0, Y1, X, X + ItemWidthVisible, 0, HighLight.r, HighLight.g, HighLight.b );

                if ( true === DrawSearch )
                    aFind.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0  );
                else if ( null !== DrawColl )
                    aColl.Add( Y0, Y1, X, X + ItemWidthVisible, 0, DrawColl.r, DrawColl.g, DrawColl.b );

                if ( para_Drawing != ItemType || drawing_Anchor != Item.DrawingType )
                    X += ItemWidthVisible;

                break;
            }
            case para_Space:
            {
                // Пробелы в конце строки (и строку состоящую из пробелов) не подчеркиваем, не зачеркиваем и не выделяем
                if ( PDSH.Spaces > 0 )
                {
                    if ( CommentsFlag != comments_NoComment )
                        aComm.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0, { Active : CommentsFlag === comments_ActiveComment ? true : false, CommentId : CommentId } );
                    else if ( highlight_None != HighLight )
                        aHigh.Add( Y0, Y1, X, X + ItemWidthVisible, 0, HighLight.r, HighLight.g, HighLight.b );

                    PDSH.Spaces--;
                }

                if ( true === DrawSearch )
                    aFind.Add( Y0, Y1, X, X + ItemWidthVisible, 0, 0, 0, 0  );
                else if ( null !== DrawColl )
                    aColl.Add( Y0, Y1, X, X + ItemWidthVisible, 0, DrawColl.r, DrawColl.g, DrawColl.b  );

                X += ItemWidthVisible;

                break;
            }
            case para_End:
            {
                if ( null !== DrawColl )
                    aColl.Add( Y0, Y1, X, X + ItemWidthVisible, 0, DrawColl.r, DrawColl.g, DrawColl.b  );

                X += Item.Get_Width();
                break;
            }
            case para_NewLine:
            {
                X += ItemWidthVisible;
                break;
            }
        }

        for ( var SPos = 0; SPos < SearchMarksCount; SPos++)
        {
            var Mark = this.SearchMarks[SPos];
            var MarkPos = Mark.SearchResult.EndPos.Get(Mark.Depth);

            if ( Pos + 1 === MarkPos && true !== Mark.Start )
                PDSH.SearchCounter--;
        }
    }

    // Обновим позицию X
    PDSH.X = X;
};

ParaRun.prototype.Draw_Elements = function(PDSE)
{
    var CurLine  = PDSE.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSE.Range - this.StartRange : PDSE.Range );
    var CurPage  = PDSE.Page;

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Para      = PDSE.Paragraph;
    var pGraphics = PDSE.Graphics;
    var BgColor   = PDSE.BgColor;
    var Theme     = PDSE.Theme;
    var FontScheme = Theme.themeElements.fontScheme;

    var X = PDSE.X;
    var Y = PDSE.Y;

    var CurTextPr = this.Get_CompiledPr( false );
    pGraphics.SetTextPr( CurTextPr, Theme );

    if ( undefined !== CurTextPr.Shd && shd_Nil !== CurTextPr.Shd.Value )
        BgColor = CurTextPr.Shd.Get_Color( Para );

    var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );

    var RGBA;
    if(CurTextPr.Unifill)
    {
        CurTextPr.Unifill.check(PDSE.Theme, PDSE.ColorMap);
        RGBA = CurTextPr.Unifill.getRGBAColor();

        if ( true === PDSE.VisitedHyperlink && ( undefined === this.Pr.Color && undefined === this.Pr.Unifill ) )
        {
            G_O_VISITED_HLINK_COLOR.check(PDSE.Theme, PDSE.ColorMap);
            RGBA = G_O_VISITED_HLINK_COLOR.getRGBAColor();
            pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
        }
        else
        {
            pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A);
        }
    }
    else
    {
        if ( true === PDSE.VisitedHyperlink && ( undefined === this.Pr.Color && undefined === this.Pr.Unifill ) )
        {
            G_O_VISITED_HLINK_COLOR.check(PDSE.Theme, PDSE.ColorMap);
            RGBA = G_O_VISITED_HLINK_COLOR.getRGBAColor();
            pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, RGBA.A );
        }
        else if ( true === CurTextPr.Color.Auto )
            pGraphics.b_color1( AutoColor.r, AutoColor.g, AutoColor.b, 255);
        else
        {
            pGraphics.b_color1( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b, 255);
        }
    }

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        var TempY = Y;
        switch( CurTextPr.VertAlign )
        {
            case vertalign_SubScript:
            {
                Y -= vertalign_Koef_Sub * CurTextPr.FontSize * g_dKoef_pt_to_mm;

                break;
            }
            case vertalign_SuperScript:
            {
                Y -= vertalign_Koef_Super * CurTextPr.FontSize * g_dKoef_pt_to_mm;

                break;
            }
        }

        switch( ItemType )
        {
            case para_PageNum:
            case para_Drawing:
            case para_Tab:
            case para_Text:
            case para_Sym:
            {
                if ( para_Drawing != ItemType || drawing_Anchor != Item.DrawingType )
                {
                    Item.Draw( X, Y - this.YOffset, pGraphics );

                    X += Item.Get_WidthVisible();
                }

                // Внутри отрисовки инлайн-автофигур могут изменится цвета и шрифт, поэтому восстанавливаем настройки
                if ( para_Drawing === ItemType && drawing_Inline === Item.DrawingType )
                {
                    pGraphics.SetTextPr( CurTextPr, Theme );

                    if(RGBA)
                    {
                        pGraphics.b_color1( RGBA.R, RGBA.G, RGBA.B, 255);
                        pGraphics.p_color( RGBA.R, RGBA.G, RGBA.B, 255);
                    }
                    else
                    {
                        if ( true === CurTextPr.Color.Auto )
                        {
                            pGraphics.b_color1( AutoColor.r, AutoColor.g, AutoColor.b, 255);
                            pGraphics.p_color( AutoColor.r, AutoColor.g, AutoColor.b, 255);
                        }
                        else
                        {
                            pGraphics.b_color1( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b, 255);
                            pGraphics.p_color(  CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b, 255);
                        }
                    }
                }

                break;
            }
            case para_Space:
            {
                Item.Draw( X, Y - this.YOffset, pGraphics );

                X += Item.Get_WidthVisible();

                break;
            }
            case para_End:
            {
                var SectPr = Para.Get_SectionPr();

                if ( undefined === SectPr )
                {
                    // Выставляем настройки для символа параграфа
                    var EndTextPr = Para.Get_CompiledPr2(false).TextPr.Copy();
                    EndTextPr.Merge(Para.TextPr.Value);

                    if(EndTextPr.Unifill)
                    {
                        EndTextPr.Unifill.check(PDSE.Theme, PDSE.ColorMap);
                        var RGBAEnd = EndTextPr.Unifill.getRGBAColor();
                        pGraphics.SetTextPr(EndTextPr, PDSE.Theme);
                        pGraphics.b_color1(RGBAEnd.R, RGBAEnd.G, RGBAEnd.B, 255);
                    }
                    else
                    {
                        pGraphics.SetTextPr(EndTextPr, PDSE.Theme);
                        if (true === EndTextPr.Color.Auto)
                            pGraphics.b_color1(AutoColor.r, AutoColor.g, AutoColor.b, 255);
                        else
                            pGraphics.b_color1(EndTextPr.Color.r, EndTextPr.Color.g, EndTextPr.Color.b, 255);
                    }

                    var bEndCell = false;
                    if (null === Para.Get_DocumentNext() && true === Para.Parent.Is_TableCellContent())
                        bEndCell = true;

                    Item.Draw(X, Y - this.YOffset, pGraphics, bEndCell);
                }
                else
                {
                    Item.Draw(X, Y - this.YOffset, pGraphics, false);
                }

                X += Item.Get_Width();

                break;
            }
            case para_NewLine:
            {
                Item.Draw( X, Y - this.YOffset, pGraphics );
                X += Item.WidthVisible;
                break;
            }
        }

        Y = TempY;
    }
    // Обновляем позицию
    PDSE.X = X;
};

ParaRun.prototype.Draw_Lines = function(PDSL)
{
    var CurLine  = PDSL.Line - this.StartLine;
    var CurRange = ( 0 === CurLine ? PDSL.Range - this.StartRange : PDSL.Range );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var X        = PDSL.X;
    var Y        = PDSL.Baseline;
    var UndOff   = PDSL.UnderlineOffset;

    var Para       = PDSL.Paragraph;

    var aStrikeout  = PDSL.Strikeout;
    var aDStrikeout = PDSL.DStrikeout;
    var aUnderline  = PDSL.Underline;
    var aSpelling   = PDSL.Spelling;

    var CurTextPr = this.Get_CompiledPr( false );

    var StrikeoutY = Y - this.YOffset;

    switch(CurTextPr.VertAlign)
    {
        case vertalign_Baseline   : StrikeoutY += -CurTextPr.FontSize * g_dKoef_pt_to_mm * 0.27; break;
        case vertalign_SubScript  : StrikeoutY += -CurTextPr.FontSize * vertalign_Koef_Size * g_dKoef_pt_to_mm * 0.27 - vertalign_Koef_Sub * CurTextPr.FontSize * g_dKoef_pt_to_mm; break;
        case vertalign_SuperScript: StrikeoutY += -CurTextPr.FontSize * vertalign_Koef_Size * g_dKoef_pt_to_mm * 0.27 - vertalign_Koef_Super * CurTextPr.FontSize * g_dKoef_pt_to_mm; break;
    }

    var UnderlineY = Y + UndOff -  this.YOffset;
    var LineW      = (CurTextPr.FontSize / 18) * g_dKoef_pt_to_mm;


    var BgColor = PDSL.BgColor;
    if ( undefined !== CurTextPr.Shd && shd_Nil !== CurTextPr.Shd.Value )
        BgColor = CurTextPr.Shd.Get_Color( Para );

    var AutoColor = ( undefined != BgColor && false === BgColor.Check_BlackAutoColor() ? new CDocumentColor( 255, 255, 255, false ) : new CDocumentColor( 0, 0, 0, false ) );

    var CurColor, RGBA, Theme = this.Paragraph.Get_Theme(), ColorMap = this.Paragraph.Get_ColorMap();

    // Выставляем цвет обводки
    if ( true === PDSL.VisitedHyperlink && ( undefined === this.Pr.Color && undefined === this.Pr.Unifill ) )
        CurColor = new CDocumentColor( 128, 0, 151 );
    else if ( true === CurTextPr.Color.Auto && !CurTextPr.Unifill)
        CurColor = new CDocumentColor( AutoColor.r, AutoColor.g, AutoColor.b );
    else
    {
        if(CurTextPr.Unifill)
        {
            CurTextPr.Unifill.check(Theme, ColorMap);
            RGBA = CurTextPr.Unifill.getRGBAColor();
            CurColor = new CDocumentColor( RGBA.R, RGBA.G, RGBA.B );
        }
        else
        {
            CurColor = new CDocumentColor( CurTextPr.Color.r, CurTextPr.Color.g, CurTextPr.Color.b );
        }
    }

    var SpellingMarksArray = {};
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var SPos = 0; SPos < SpellingMarksCount; SPos++)
    {
        var Mark = this.SpellingMarks[SPos];

        if ( false === Mark.Element.Checked )
        {
            if ( true === Mark.Start )
            {
                var MarkPos = Mark.Element.StartPos.Get(Mark.Depth);

                if ( undefined === SpellingMarksArray[MarkPos] )
                    SpellingMarksArray[MarkPos] = 1;
                else
                    SpellingMarksArray[MarkPos] += 1;
            }
            else
            {
                var MarkPos = Mark.Element.EndPos.Get(Mark.Depth);

                if ( undefined === SpellingMarksArray[MarkPos] )
                    SpellingMarksArray[MarkPos] = 2;
                else
                    SpellingMarksArray[MarkPos] += 2;
            }
        }
    }

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item             = this.Content[Pos];
        var ItemType         = Item.Type;
        var ItemWidthVisible = Item.Get_WidthVisible();

        if ( 1 === SpellingMarksArray[Pos] || 3 === SpellingMarksArray[Pos] )
            PDSL.SpellingCounter++;

        switch( ItemType )
        {
            case para_End:
            case para_NewLine:
            {
                X += ItemWidthVisible;

                break;
            }

            case para_PageNum:
            case para_Drawing:
            case para_Tab:
            case para_Text:
            case para_Sym:
            {
                if ( para_Drawing != ItemType || drawing_Anchor != Item.DrawingType )
                {
                    if ( true === CurTextPr.DStrikeout )
                        aDStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b );
                    else if ( true === CurTextPr.Strikeout )
                        aStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b );

                    if ( true === CurTextPr.Underline )
                        aUnderline.Add( UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b );

                    if ( PDSL.SpellingCounter > 0 )
                        aSpelling.Add( UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, 0, 0, 0 );

                    X += ItemWidthVisible;
                }

                break;
            }
            case para_Space:
            {
                // Пробелы, идущие в конце строки, не подчеркиваем и не зачеркиваем
                if ( PDSL.Spaces > 0 )
                {
                    if ( true === CurTextPr.DStrikeout )
                        aDStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b );
                    else if ( true === CurTextPr.Strikeout )
                        aStrikeout.Add( StrikeoutY, StrikeoutY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b );

                    if ( true === CurTextPr.Underline )
                        aUnderline.Add( UnderlineY, UnderlineY, X, X + ItemWidthVisible, LineW, CurColor.r, CurColor.g, CurColor.b );

                    PDSL.Spaces--;
                }

                X += ItemWidthVisible;

                break;
            }
        }

        if ( 2 === SpellingMarksArray[Pos + 1] || 3 === SpellingMarksArray[Pos + 1] )
            PDSL.SpellingCounter--;
    }

    // Обновляем позицию
    PDSL.X = X;
};
//-----------------------------------------------------------------------------------
// Функции для работы с курсором
//-----------------------------------------------------------------------------------
// Находится ли курсор в начале рана
ParaRun.prototype.Is_CursorPlaceable = function()
{
    return true;
};

ParaRun.prototype.Cursor_Is_Start = function()
{
    if ( this.State.ContentPos <= 0 )
        return true;

    return false;
};

// Проверяем нужно ли поправить позицию курсора
ParaRun.prototype.Cursor_Is_NeededCorrectPos = function()
{
    if ( true === this.Is_Empty(false) )
        return true;

    var NewRangeStart = false;
    var RangeEnd      = false;

    var Pos = this.State.ContentPos;

    var LinesLen = this.protected_GetLinesCount();
    for ( var CurLine = 0; CurLine < LinesLen; CurLine++ )
    {
        var RangesLen = this.protected_GetRangesCount(CurLine);
        for ( var CurRange = 0; CurRange < RangesLen; CurRange++ )
        {
            var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
            var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

            if (0 !== CurLine || 0 !== CurRange)
            {
                if (Pos === StartPos)
                {
                    NewRangeStart = true;
                }
            }

            if (Pos === EndPos)
            {
                RangeEnd = true;
            }
        }

        if ( true === NewRangeStart )
            break;
    }

    if ( true !== NewRangeStart && true !== RangeEnd && true === this.Cursor_Is_Start() )
        return true;

    return false;
};

ParaRun.prototype.Cursor_Is_End = function()
{
    if ( this.State.ContentPos >= this.Content.length )
        return true;

    return false;
};

ParaRun.prototype.Cursor_MoveToStartPos = function()
{
    this.State.ContentPos = 0;
};

ParaRun.prototype.Cursor_MoveToEndPos = function(SelectFromEnd)
{
    if ( true === SelectFromEnd )
    {
        var Selection = this.State.Selection;
        Selection.Use      = true;
        Selection.StartPos = this.Content.length;
        Selection.EndPos   = this.Content.length;
    }
    else
    {
        var CurPos = this.Content.length;

        while ( CurPos > 0 )
        {
            if ( para_End === this.Content[CurPos - 1].Type )
                CurPos--;
            else
                break;
        }

        this.State.ContentPos = CurPos;
    }
};

ParaRun.prototype.Get_ParaContentPosByXY = function(SearchPos, Depth, _CurLine, _CurRange, StepEnd, PointsInfo)
{
    var Result = false;

    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var CurPos = StartPos;
    var bNotUpdate = SearchPos.InText && this.Type === para_Math_Run;
    for (; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];
        var ItemType = Item.Type;

        var TempDx = 0;

        if(para_Math_Ampersand === ItemType)
        {
            PointsInfo.NextAlignRange();
            TempDx = PointsInfo.GetAlign();
        }
        else if ( para_Drawing != ItemType || true === Item.Is_Inline() )
        {
            TempDx = Item.Get_WidthVisible();
        }

        // Проверяем, попали ли мы в данный элемент
        var Diff = SearchPos.X - SearchPos.CurX;
        if (Math.abs( Diff ) < SearchPos.DiffX + 0.001 && !bNotUpdate)
        {
            SearchPos.DiffX = Math.abs( Diff );
            SearchPos.Pos.Update( CurPos, Depth );
            Result = true;

            if ( Diff >= - 0.001 && Diff <= TempDx + 0.001 )
            {
                SearchPos.InTextPos.Update( CurPos, Depth );
                SearchPos.InText = true;
            }
        }

        SearchPos.CurX += TempDx;

        // Заглушка для знака параграфа и конца строки
        if (Math.abs(SearchPos.X - SearchPos.CurX) < SearchPos.DiffX && !bNotUpdate)
        {
            if ( para_End === ItemType )
            {
                SearchPos.End = true;

                // Если мы ищем позицию для селекта, тогда нужно искать и за знаком параграфа
                if ( true === StepEnd )
                {
                    SearchPos.Pos.Update( this.Content.length, Depth );
                    Result = true;
                }
            }
            else if ( CurPos === EndPos - 1 && para_NewLine != ItemType )
            {
                SearchPos.Pos.Update( EndPos, Depth );
                Result = true;
            }
        }
    }

    // Такое возможно, если все раны до этого (в том числе и этот) были пустыми, тогда, чтобы не возвращать
    // неправильную позицию вернем позицию начала данного путого рана.
    if ( SearchPos.DiffX > 1000000 - 1 )
    {
        SearchPos.Pos.Update( StartPos, Depth );
        Result = true;
    }

    if (this.Type == para_Math_Run) // не только для пустых Run, но и для проверки на конец Run (т.к. Diff не обновляется)
    {
        var Diff = SearchPos.X - SearchPos.CurX;
        if (Math.abs( Diff ) < SearchPos.DiffX + 0.001 && !bNotUpdate)
        {
            SearchPos.DiffX = Math.abs( Diff );
            SearchPos.Pos.Update( CurPos, Depth );
            Result = true;
        }
    }

    return Result;
};

ParaRun.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos)
{
    var Pos = ( true !== bSelection ? this.State.ContentPos : ( false !== bStart ? this.State.Selection.StartPos : this.State.Selection.EndPos ) );
    ContentPos.Add(Pos);
};

ParaRun.prototype.Set_ParaContentPos = function(ContentPos, Depth)
{
    var Pos = ContentPos.Get(Depth);

    var Count = this.Content.length;
    if ( Pos > Count )
        Pos = Count;

    // TODO: Как только переделаем работу c Para_End переделать здесь
    for ( var TempPos = 0; TempPos < Pos; TempPos++ )
    {
        if ( para_End === this.Content[TempPos].Type )
        {
            Pos = TempPos;
            break;
        }
    }

    if ( Pos < 0 )
        Pos = 0;

    this.State.ContentPos = Pos;
};

ParaRun.prototype.Get_PosByElement = function(Class, ContentPos, Depth, UseRange, Range, Line)
{
    if ( this === Class )
        return true;

    return false;
};

ParaRun.prototype.Get_PosByDrawing = function(Id, ContentPos, Depth)
{
    var Count = this.Content.length;
    for ( var CurPos = 0; CurPos < Count; CurPos++ )
    {
        var Item = this.Content[CurPos];
        if ( para_Drawing === Item.Type && Id === Item.Get_Id() )
        {
            ContentPos.Update( CurPos, Depth );
            return true;
        }
    }

    return false;
};

ParaRun.prototype.Get_RunElementByPos = function(ContentPos, Depth)
{
    if ( undefined !== ContentPos )
    {
        var CurPos = ContentPos.Get(Depth);
        var ContentLen = this.Content.length;

        if ( CurPos >= this.Content.length || CurPos < 0 )
            return null;

        return this.Content[CurPos];
    }
    else
    {
        if ( this.Content.length > 0 )
            return this.Content[0];
        else
            return null;
    }
};

ParaRun.prototype.Get_LastRunInRange = function(_CurLine, _CurRange)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    return this;
};

ParaRun.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length );

    while ( true )
    {
        CurPos--;

        var Item = this.Content[CurPos];
        if ( CurPos < 0 || para_Drawing !== Item.Type || false !== Item.Is_Inline() )
            break;
    }

    if ( CurPos >= 0 )
    {
        SearchPos.Found = true;
        SearchPos.Pos.Update( CurPos, Depth );
    }
};

ParaRun.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : 0 );

    var Count = this.Content.length;
    while ( true )
    {
        CurPos++;

        // Мы встали в конец рана:
        //   Если мы перешагнули para_End или para_Drawing Anchor, тогда возвращаем false
        //   В противном случае true
        if ( Count === CurPos )
        {
            if ( CurPos === 0 )
                return;

            var PrevItem = this.Content[CurPos - 1];
            var PrevItemType = PrevItem.Type;
            if ((true !== StepEnd && para_End === PrevItemType) || (para_Drawing === PrevItemType && false === PrevItem.Is_Inline()))
                return;

            break;
        }

        if (CurPos > Count)
            break;

        var Item = this.Content[CurPos];
        var ItemType = Item.Type;
        if ((para_Drawing !== ItemType && (false !== StepEnd || para_End !== this.Content[CurPos - 1].Type)) || (para_Drawing === ItemType && false !== Item.Is_Inline()))
            break;
    }

    if ( CurPos <= Count )
    {
        SearchPos.Found = true;
        SearchPos.Pos.Update( CurPos, Depth );
    }
};

ParaRun.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos)
{
    var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) - 1 : this.Content.length - 1 );

    if ( CurPos < 0 )
        return;

    SearchPos.Shift = true;

    var NeedUpdate = false;

    // На первом этапе ищем позицию первого непробельного элемента
    if ( 0 === SearchPos.Stage )
    {
        while ( true )
        {
            var Item = this.Content[CurPos];
            var Type = Item.Type;

            var bSpace = false;

            if ( para_Space === Type || para_Tab === Type || ( para_Text === Type && true === Item.Is_NBSP() ) || ( para_Drawing === Type && true !== Item.Is_Inline() ) )
                bSpace = true;

            if ( true === bSpace )
            {
                CurPos--;

                // Выходим из данного рана
                if ( CurPos < 0 )
                    return;
            }
            else
            {
                // Если мы остановились на нетекстовом элементе, тогда его и возвращаем
                if ( para_Text !== this.Content[CurPos].Type && para_Math_Text !== this.Content[CurPos].Type)
                {
                    SearchPos.Pos.Update( CurPos, Depth );
                    SearchPos.Found     = true;
                    SearchPos.UpdatePos = true;
                    return;
                }

                SearchPos.Pos.Update( CurPos, Depth );
                SearchPos.Stage       = 1;
                SearchPos.Punctuation = this.Content[CurPos].Is_Punctuation();
                NeedUpdate            = true;

                break;
            }
        }
    }
    else
    {
        CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length );
    }

    // На втором этапе мы смотрим на каком элементе мы встали: если текст - пунктуация, тогда сдвигаемся
    // до конца всех знаков пунктуации

    while ( CurPos > 0 )
    {
        CurPos--;
        var Item = this.Content[CurPos];
        var TempType = Item.Type;

        if ( (para_Text !== TempType && para_Math_Text !== TempType) || true === Item.Is_NBSP() || ( true === SearchPos.Punctuation && true !== Item.Is_Punctuation() ) || ( false === SearchPos.Punctuation && false !== Item.Is_Punctuation() ) )
        {
            SearchPos.Found = true;
            break;
        }
        else
        {
            SearchPos.Pos.Update( CurPos, Depth );
            NeedUpdate = true;
        }
    }

    SearchPos.UpdatePos = NeedUpdate;
};

ParaRun.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd)
{
    var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : 0 );

    var ContentLen = this.Content.length;
    if ( CurPos >= ContentLen )
        return;

    var NeedUpdate = false;

    if ( 0 === SearchPos.Stage )
    {
        // На первом этапе ищем первый нетекстовый ( и не таб ) элемент
        while ( true )
        {
            var Item = this.Content[CurPos];
            var Type = Item.Type;
            var bText = false;

            if ( (para_Text === Type || para_Math_Text === Type) && true != Item.Is_NBSP() && ( true === SearchPos.First || ( SearchPos.Punctuation === Item.Is_Punctuation() ) ) )
                bText = true;

            if ( true === bText )
            {
                if ( true === SearchPos.First )
                {
                    SearchPos.First       = false;
                    SearchPos.Punctuation = Item.Is_Punctuation();
                }

                CurPos++;

                // Отмечаем, что сдвиг уже произошел
                SearchPos.Shift = true;

                // Выходим из рана
                if ( CurPos >= ContentLen )
                    return;
            }
            else
            {
                SearchPos.Stage = 1;

                // Первый найденный элемент не текстовый, смещаемся вперед
                if ( true === SearchPos.First )
                {
                    // Если первый найденный элемент - конец параграфа, тогда выходим из поиска
                    if ( para_End === Type )
                    {
                        if ( true === StepEnd )
                        {
                            SearchPos.Pos.Update( CurPos + 1, Depth );
                            SearchPos.Found     = true;
                            SearchPos.UpdatePos = true;
                        }

                        return;
                    }

                    CurPos++;

                    // Отмечаем, что сдвиг уже произошел
                    SearchPos.Shift = true;
                }

                break;
            }
        }
    }

    if ( CurPos >= ContentLen )
        return;


    // На втором этапе мы смотрим на каком элементе мы встали: если это не пробел, тогда
    // останавливаемся здесь. В противном случае сдвигаемся вперед, пока не попали на первый
    // не пробельный элемент.
    if ( !(para_Space === this.Content[CurPos].Type || ( para_Text === this.Content[CurPos].Type && true === this.Content[CurPos].Is_NBSP() ) ) )
    {
        SearchPos.Pos.Update( CurPos, Depth );
        SearchPos.Found     = true;
        SearchPos.UpdatePos = true;
    }
    else
    {
        while ( CurPos < ContentLen - 1 )
        {
            CurPos++;
            var Item = this.Content[CurPos];
            var TempType = Item.Type;

            if ( (true !== StepEnd && para_End === TempType) || !( para_Space === TempType || ( para_Text === TempType && true === Item.Is_NBSP() ) ) )
            {
                SearchPos.Found = true;
                break;
            }
        }

        // Обновляем позицию в конце каждого рана (хуже от этого не будет)
        SearchPos.Pos.Update( CurPos, Depth );
        SearchPos.UpdatePos = true;
    }
};

ParaRun.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var LastPos = -1;
    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];
        var ItemType = Item.Type;
        if ( !((para_Drawing === ItemType && true !== Item.Is_Inline()) || para_End === ItemType || (para_NewLine === ItemType && break_Line === Item.BreakType)))
            LastPos = CurPos + 1;
    }

    // Проверяем, попал ли хоть один элемент в данный отрезок, если нет, тогда не регистрируем такой ран
    if ( -1 !== LastPos )
    {
        SearchPos.Pos.Update( LastPos, Depth );
        return true;
    }
    else
        return false;
};

ParaRun.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth)
{
    var CurLine = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var FirstPos = -1;
    for ( var CurPos = EndPos - 1; CurPos >= StartPos; CurPos-- )
    {
        var Item = this.Content[CurPos];
        if ( !(para_Drawing === Item.Type && true !== Item.Is_Inline()) )
            FirstPos = CurPos;
    }

    // Проверяем, попал ли хоть один элемент в данный отрезок, если нет, тогда не регистрируем такой ран
    if ( -1 !== FirstPos )
    {
        SearchPos.Pos.Update( FirstPos, Depth );
        return true;
    }
    else if(this.Type == para_Math_Run && this.Parent.Is_FirstComposition())
    {
        SearchPos.Pos.Update( 0, Depth );
        return true;
    }
    else
        return false;
};

ParaRun.prototype.Get_StartRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var Pos = this.protected_GetRangeStartPos(CurLine, CurRange);
    ContentPos.Update( Pos, Depth );
};

ParaRun.prototype.Get_StartPos = function(ContentPos, Depth)
{
    ContentPos.Update( 0, Depth );
};

ParaRun.prototype.Get_EndPos = function(BehindEnd, ContentPos, Depth)
{
    var ContentLen = this.Content.length;

    if ( true === BehindEnd )
        ContentPos.Update( ContentLen, Depth );
    else
    {
        for ( var CurPos = 0; CurPos < ContentLen; CurPos++ )
        {
            if ( para_End === this.Content[CurPos].Type )
            {
                ContentPos.Update( CurPos, Depth );
                return;
            }
        }

        // Не нашли para_End
        ContentPos.Update( ContentLen, Depth );
    }
};
//-----------------------------------------------------------------------------------
// Функции для работы с селектом
//-----------------------------------------------------------------------------------
ParaRun.prototype.Set_SelectionContentPos = function(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag)
{
    var StartPos = 0;
    switch (StartFlag)
    {
        case  1: StartPos = 0; break;
        case -1: StartPos = this.Content.length; break;
        case  0: StartPos = StartContentPos.Get(Depth); break;
    }

    var EndPos = 0;
    switch (EndFlag)
    {
        case  1: EndPos = 0; break;
        case -1: EndPos = this.Content.length; break;
        case  0: EndPos = EndContentPos.Get(Depth); break;
    }

    var Selection = this.State.Selection;
    Selection.StartPos = StartPos;
    Selection.EndPos   = EndPos;
    Selection.Use      = true;
};

ParaRun.prototype.Set_SelectionAtEndPos = function()
{
    this.Set_SelectionContentPos(null, null, 0, -1, -1);
};

ParaRun.prototype.Set_SelectionAtStartPos = function()
{
    this.Set_SelectionContentPos(null, null, 0, 1, 1);
};

ParaRun.prototype.Selection_IsUse = function()
{
    return this.State.Selection.Use;
};

ParaRun.prototype.Is_SelectedAll = function(Props)
{
    var Selection = this.State.Selection;
    if ( false === Selection.Use && true !== this.Is_Empty( Props ) )
        return false;

    var SkipAnchor = Props.SkipAnchor;
    var SkipEnd    = Props.SkipEnd;

    var StartPos = Selection.StartPos;
    var EndPos   = Selection.EndPos;

    if ( EndPos < StartPos )
    {
        StartPos = Selection.EndPos;
        EndPos   = Selection.StartPos;
    }

    for ( var Pos = 0; Pos < StartPos; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( !( ( true === SkipAnchor && ( para_Drawing === ItemType && true !== Item.Is_Inline() ) ) || ( true === SkipEnd && para_End === ItemType ) ) )
            return false;
    }

    var Count = this.Content.length;
    for ( var Pos = EndPos; Pos < Count; Pos++ )
    {
        var Item = this.Content[Pos];
        var ItemType = Item.Type;

        if ( !( ( true === SkipAnchor && ( para_Drawing === ItemType && true !== Item.Is_Inline() ) ) || ( true === SkipEnd && para_End === ItemType ) ) )
            return false;
    }

    return true;
};

ParaRun.prototype.Selection_CorrectLeftPos = function(Direction)
{
    if ( false === this.Selection.Use || true === this.Is_Empty( { SkipAnchor : true } ) )
        return true;

    var Selection = this.State.Selection;
    var StartPos = Math.min( Selection.StartPos, Selection.EndPos );
    var EndPos   = Math.max( Selection.StartPos, Selection.EndPos );

    for ( var Pos = 0; Pos < StartPos; Pos++ )
    {
        var Item = this.Content[Pos];
        if ( para_Drawing !== Item.Type || true === Item.Is_Inline() )
            return false;
    }

    for ( var Pos = StartPos; Pos < EndPos; Pos++ )
    {
        var Item = this.Content[Pos];
        if ( para_Drawing === Item.Type && true !== Item.Is_Inline() )
        {
            if ( 1 === Direction )
                Selection.StartPos = Pos + 1;
            else
                Selection.EndPos   = Pos + 1;
        }
        else
            return false;
    }

    return true;
};

ParaRun.prototype.Selection_Stop = function()
{
};

ParaRun.prototype.Selection_Remove = function()
{
    var Selection = this.State.Selection;

    Selection.Use      = false;
    Selection.StartPos = 0;
    Selection.EndPos   = 0;
};

ParaRun.prototype.Select_All = function(Direction)
{
    var Selection = this.State.Selection;

    Selection.Use      = true;

    if ( -1 === Direction )
    {
        Selection.StartPos = this.Content.length;
        Selection.EndPos   = 0;
    }
    else
    {
        Selection.StartPos = 0;
        Selection.EndPos   = this.Content.length;
    }
};

ParaRun.prototype.Selection_DrawRange = function(_CurLine, _CurRange, SelectionDraw, PointsInfo)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange );

    var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange);
    var EndPos   = this.protected_GetRangeEndPos(CurLine, CurRange);

    var Selection = this.State.Selection;
    var SelectionUse      = Selection.Use;
    var SelectionStartPos = Selection.StartPos;
    var SelectionEndPos   = Selection.EndPos;

    if ( SelectionStartPos > SelectionEndPos )
    {
        SelectionStartPos = Selection.EndPos;
        SelectionEndPos   = Selection.StartPos;
    }

    var FindStart = SelectionDraw.FindStart;

    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];
        var ItemType = Item.Type;
        var DrawSelection = false;

        if ( true === FindStart )
        {
            if ( true === Selection.Use && CurPos >= SelectionStartPos && CurPos < SelectionEndPos )
            {
                FindStart = false;

                DrawSelection = true;
            }
            else
            {
                if(para_Math_Ampersand == ItemType)
                {
                    PointsInfo.NextAlignRange();
                    SelectionDraw.StartX += PointsInfo.GetAlign();
                }
                else if ( para_Drawing !== ItemType || true === Item.Is_Inline() )
                    SelectionDraw.StartX += Item.Get_WidthVisible();
            }
        }
        else
        {
            if ( true === Selection.Use && CurPos >= SelectionStartPos && CurPos < SelectionEndPos )
            {
                DrawSelection = true;
            }
        }

        if ( true === DrawSelection )
        {
            if (true === SelectionDraw.Draw && para_Drawing === ItemType && true !== Item.Is_Inline())
                Item.Draw_Selection();
            else if (para_Math_Ampersand === ItemType)
            {
                PointsInfo.NextAlignRange();
                SelectionDraw.W += PointsInfo.GetAlign();
            }
            else
                SelectionDraw.W += Item.Get_WidthVisible();
        }
    }

    SelectionDraw.FindStart = FindStart;
};

ParaRun.prototype.Selection_IsEmpty = function(CheckEnd)
{
    var Selection = this.State.Selection;
    if ( true !== Selection.Use )
        return true;

    if(this.Type == para_Math_Run && this.IsPlaceholder())
        return false;

    var StartPos = Selection.StartPos;
    var EndPos   = Selection.EndPos;

    if ( StartPos > EndPos )
    {
        StartPos = Selection.EndPos;
        EndPos   = Selection.StartPos;
    }

    if ( true === CheckEnd )
        return ( EndPos > StartPos ? false : true );
    else if(this.Type == para_Math_Run && this.Is_Empty())
    {
        return false;
    }
    else
    {
        for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
        {
            var ItemType = this.Content[CurPos].Type;
            if (para_End !== ItemType  && para_Math_Ampersand !== ItemType) // para_math_Ampersand имеет нулевую ширину, поэтому чтобы не случилось так что не было ни селекта, ни курсора, не учитываем para_Math_Ampersand
                return false;
        }
    }

    return true;
};

ParaRun.prototype.Selection_CheckParaEnd = function()
{
    var Selection = this.State.Selection;
    if ( true !== Selection.Use )
        return false;

    var StartPos = Selection.StartPos;
    var EndPos   = Selection.EndPos;

    if ( StartPos > EndPos )
    {
        StartPos = Selection.EndPos;
        EndPos   = Selection.StartPos;
    }

    for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ )
    {
        var Item = this.Content[CurPos];

        if ( para_End === Item.Type )
            return true;
    }

    return false;
};
//-----------------------------------------------------------------------------------
// Функции для работы с настройками текста свойств
//-----------------------------------------------------------------------------------
ParaRun.prototype.Clear_TextFormatting = function( DefHyper )
{
    // Highlight и Lang не сбрасываются при очистке текстовых настроек

    this.Set_Bold( undefined );
    this.Set_Italic( undefined );
    this.Set_Strikeout( undefined );
    this.Set_Underline( undefined );
    this.Set_FontSize( undefined );
    this.Set_Color( undefined );
    this.Set_Unifill( undefined );
    this.Set_VertAlign( undefined );
    this.Set_Spacing( undefined );
    this.Set_DStrikeout( undefined );
    this.Set_Caps( undefined );
    this.Set_SmallCaps( undefined );
    this.Set_Position( undefined );
    this.Set_RFonts2( undefined );
    this.Set_RStyle( undefined );
    this.Set_Shd( undefined );

    // Насильно заставим пересчитать стиль, т.к. как данная функция вызывается у параграфа, у которого мог смениться стиль
    this.Recalc_CompiledPr(true);
};

ParaRun.prototype.Get_TextPr = function()
{
    return this.Pr.Copy();
};

ParaRun.prototype.Get_CompiledTextPr = function(Copy)
{
    if ( true === this.State.Selection.Use && true === this.Selection_CheckParaEnd() )
    {
        var ThisTextPr = this.Get_CompiledPr( true );

        var Para       = this.Paragraph;
        var EndTextPr  = Para.Get_CompiledPr2(false).TextPr.Copy();
        EndTextPr.Merge( Para.TextPr.Value );

        ThisTextPr = ThisTextPr.Compare( EndTextPr );

        return ThisTextPr;
    }
    else
        return this.Get_CompiledPr(Copy);
};

ParaRun.prototype.Recalc_CompiledPr = function(RecalcMeasure)
{
    this.RecalcInfo.TextPr  = true;

    // Если изменение какой-то текстовой настройки требует пересчета элементов
    if ( true === RecalcMeasure )
        this.RecalcInfo.Measure = true;
};

ParaRun.prototype.Recalc_RunsCompiledPr = function()
{
    this.Recalc_CompiledPr(true);
};

ParaRun.prototype.Get_CompiledPr = function(bCopy)
{
    if ( true === this.RecalcInfo.TextPr )
    {
        this.CompiledPr = this.Internal_Compile_Pr();
        this.RecalcInfo.TextPr = false;
    }
    
    if ( false === bCopy )
        return this.CompiledPr;
    else
        return this.CompiledPr.Copy(); // Отдаем копию объекта, чтобы никто не поменял извне настройки стиля
};

ParaRun.prototype.Internal_Compile_Pr = function ()
{
    if ( undefined === this.Paragraph || null === this.Paragraph )
    {
        // Сюда мы никогда не должны попадать, но на всякий случай,
        // чтобы не выпадало ошибок сгенерим дефолтовые настройки
        var TextPr = new CTextPr();
        TextPr.Init_Default();
        return new CTextPr();
    }

    // Получим настройки текста, для данного параграфа
    var TextPr = this.Paragraph.Get_CompiledPr2(false).TextPr.Copy();

    // Если в прямых настройках задан стиль, тогда смержим настройки стиля
    if ( undefined != this.Pr.RStyle )
    {
        var Styles = this.Paragraph.Parent.Get_Styles();
        var StyleTextPr = Styles.Get_Pr( this.Pr.RStyle, styletype_Character ).TextPr;
        TextPr.Merge( StyleTextPr );
    }

    if(this.Type == para_Math_Run)
    {
        // Not Apply ArgSize !
        var oWPrp = this.Parent.Get_Default_TPrp();
        TextPr.Merge(oWPrp);

        if(this.IsPlaceholder())
        {
            /*oWPrp = this.Parent.Get_Default_TPrp();
             TextPr.Merge(oWPrp);*/
            TextPr.Merge(this.Parent.GetCtrPrp());
            TextPr.Merge( this.Pr );            // Мержим прямые настройки данного рана

            // special for placeholder

            TextPr.Italic = false;
            TextPr.Bold   = false;

            //this.Parent.ParaMath.ApplyArgSize(TextPr, this.Parent.argSize);
        }
        else
        {
            /*oWPrp = this.Parent.Get_Default_TPrp();
             TextPr.Merge(oWPrp);*/
            TextPr.Merge( this.Pr );            // Мержим прямые настройки данного рана

            if(!this.IsNormalText()) // math text
            {
                var MPrp = this.MathPrp.GetTxtPrp();
                TextPr.Merge(MPrp); // bold, italic
            }

            //this.Parent.ParaMath.ApplyArgSize(TextPr, this.Parent.argSize);
        }
    }
    else
    {
        TextPr.Merge( this.Pr ); // Мержим прямые настройки данного рана
        if(this.Pr.Color && !this.Pr.Unifill)
        {
            TextPr.Unifill = undefined;
        }
    }

    // Для совместимости со старыми версиями запишем FontFamily
    TextPr.FontFamily.Name  = TextPr.RFonts.Ascii.Name;
    TextPr.FontFamily.Index = TextPr.RFonts.Ascii.Index;

    return TextPr;
};

// В данной функции мы жестко меняем настройки на те, которые пришли (т.е. полностью удаляем старые)
ParaRun.prototype.Set_Pr = function(TextPr)
{
    var OldValue = this.Pr;
    this.Pr = TextPr;

    History.Add( this, { Type : historyitem_ParaRun_TextPr, New : TextPr, Old : OldValue } );
    this.Recalc_CompiledPr(true);

    // TODO: Орфография: пока сделаем так, в будущем надо будет переделать
    if(undefined !== this.Paragraph && this.Paragraph !== null)
        this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );
};

ParaRun.prototype.Apply_TextPr = function(TextPr, IncFontSize, ApplyToAll)
{
    if ( true === ApplyToAll )
    {
        if ( undefined === IncFontSize )
        {
            this.Apply_Pr( TextPr );
        }
        else
        {
            var _TextPr = new CTextPr();
            var CurTextPr = this.Get_CompiledPr( false );

            this.Set_FontSize( FontSize_IncreaseDecreaseValue( IncFontSize, CurTextPr.FontSize ) );
        }

        // Дополнительно проверим, если у нас para_End лежит в данном ране и попадает в выделение, тогда
        // применим заданные настроки к символу конца параграфа

        // TODO: Возможно, стоит на этапе пересчета запонимать, лежит ли para_End в данном ране. Чтобы в каждом
        //       ране потом не бегать каждый раз по всему массиву в поисках para_End.

        var bEnd = false;
        var Count = this.Content.length;
        for ( var Pos = 0; Pos < Count; Pos++ )
        {
            if ( para_End === this.Content[Pos].Type )
            {
                bEnd = true;
                break;
            }
        }

        if ( true === bEnd )
        {
            if ( undefined === IncFontSize )
                this.Paragraph.TextPr.Apply_TextPr( TextPr );
            else
            {
                var Para = this.Paragraph;

                // Выставляем настройки для символа параграфа
                var EndTextPr = Para.Get_CompiledPr2(false).TextPr.Copy();
                EndTextPr.Merge( Para.TextPr.Value );

                // TODO: Как только перенесем историю изменений TextPr в сам класс CTextPr, переделать тут
                Para.TextPr.Set_FontSize( FontSize_IncreaseDecreaseValue( IncFontSize, EndTextPr.FontSize ) );
            }
        }
    }
    else
    {
        var Result = [];
        var LRun = this, CRun = null, RRun = null;

        if ( true === this.State.Selection.Use )
        {
            var StartPos = this.State.Selection.StartPos;
            var EndPos   = this.State.Selection.EndPos;

            var Direction = 1;
            if ( StartPos > EndPos )
            {
                var Temp = StartPos;
                StartPos = EndPos;
                EndPos = Temp;
                Direction = -1;
            }

            // Если выделено не до конца, тогда разделяем по последней точке
            if ( EndPos < this.Content.length )
            {
                RRun = LRun.Split_Run( EndPos );
            }

            // Если выделено не с начала, тогда делим по начальной точке
            if ( StartPos > 0 )
            {
                CRun = LRun.Split_Run( StartPos );
            }
            else
            {
                CRun = LRun;
                LRun = null;
            }

            if ( null !== LRun )
            {
                LRun.Selection.Use      = true;
                LRun.Selection.StartPos = LRun.Content.length;
                LRun.Selection.EndPos   = LRun.Content.length;
            }

            CRun.Select_All(Direction);

            if ( undefined === IncFontSize )
                CRun.Apply_Pr( TextPr );
            else
            {
                var _TextPr = new CTextPr();
                var CurTextPr = this.Get_CompiledPr( false );

                CRun.Set_FontSize( FontSize_IncreaseDecreaseValue( IncFontSize, CurTextPr.FontSize ) );
            }

            if ( null !== RRun )
            {
                RRun.Selection.Use      = true;
                RRun.Selection.StartPos = 0;
                RRun.Selection.EndPos   = 0;
            }

            // Дополнительно проверим, если у нас para_End лежит в данном ране и попадает в выделение, тогда
            // применим заданные настроки к символу конца параграфа

            // TODO: Возможно, стоит на этапе пересчета запонимать, лежит ли para_End в данном ране. Чтобы в каждом
            //       ране потом не бегать каждый раз по всему массиву в поисках para_End.

            if ( true === this.Selection_CheckParaEnd() )
            {
                if ( undefined === IncFontSize )
                    this.Paragraph.TextPr.Apply_TextPr( TextPr );
                else
                {
                    var Para = this.Paragraph;

                    // Выставляем настройки для символа параграфа
                    var EndTextPr = Para.Get_CompiledPr2(false).TextPr.Copy();
                    EndTextPr.Merge( Para.TextPr.Value );

                    // TODO: Как только перенесем историю изменений TextPr в сам класс CTextPr, переделать тут
                    Para.TextPr.Set_FontSize( FontSize_IncreaseDecreaseValue( IncFontSize, EndTextPr.FontSize ) );
                }
            }
        }
        else
        {
            var CurPos = this.State.ContentPos;

            // Если выделено не до конца, тогда разделяем по последней точке
            if ( CurPos < this.Content.length )
            {
                RRun = LRun.Split_Run( CurPos );
            }

            if ( CurPos > 0 )
            {
                CRun = LRun.Split_Run( CurPos );
            }
            else
            {
                CRun = LRun;
                LRun = null;
            }

            if ( null !== LRun )
                LRun.Selection_Remove();

            CRun.Selection_Remove();
            CRun.Cursor_MoveToStartPos();

            if ( undefined === IncFontSize )
            {
                CRun.Apply_Pr( TextPr );
            }
            else
            {
                var _TextPr = new CTextPr();
                var CurTextPr = this.Get_CompiledPr( false );

                CRun.Set_FontSize( FontSize_IncreaseDecreaseValue( IncFontSize, CurTextPr.FontSize ) );
            }


            if ( null !== RRun )
                RRun.Selection_Remove();
        }

        Result.push( LRun );
        Result.push( CRun );
        Result.push( RRun );

        return Result;
    }
};

ParaRun.prototype.Split_Run = function(Pos)
{
    // Создаем новый ран
    var bMathRun = this.Type == para_Math_Run;
    var NewRun = new ParaRun(this.Paragraph, bMathRun);

    // Копируем настройки
    NewRun.Set_Pr( this.Pr.Copy() );

    if(bMathRun)
        NewRun.Set_MathPr(this.MathPrp.Copy());


    var OldCrPos = this.State.ContentPos;
    var OldSSPos = this.State.Selection.StartPos;
    var OldSEPos = this.State.Selection.EndPos;

    // Разделяем содержимое по ранам
    NewRun.Concat_ToContent( this.Content.slice(Pos) );
    this.Remove_FromContent( Pos, this.Content.length - Pos, true );

    // Подправим точки селекта и текущей позиции
    if ( OldCrPos >= Pos )
    {
        NewRun.State.ContentPos = OldCrPos - Pos;
        this.State.ContentPos   = this.Content.length;
    }
    else
    {
        NewRun.State.ContentPos = 0;
    }

    if ( OldSSPos >= Pos )
    {
        NewRun.State.Selection.StartPos = OldSSPos - Pos;
        this.State.Selection.StartPos   = this.Content.length;
    }
    else
    {
        NewRun.State.Selection.StartPos = 0;
    }

    if ( OldSEPos >= Pos )
    {
        NewRun.State.Selection.EndPos = OldSEPos - Pos;
        this.State.Selection.EndPos   = this.Content.length;
    }
    else
    {
        NewRun.State.Selection.EndPos = 0;
    }

    // Если были точки орфографии, тогда переместим их в новый ран
    var SpellingMarksCount = this.SpellingMarks.length;
    for ( var Index = 0; Index < SpellingMarksCount; Index++ )
    {
        var Mark    = this.SpellingMarks[Index];
        var MarkPos = ( true === Mark.Start ? Mark.Element.StartPos.Get(Mark.Depth) : Mark.Element.EndPos.Get(Mark.Depth) );

        if ( MarkPos >= Pos )
        {
            var MarkElement = Mark.Element;
            if ( true === Mark.Start )
            {
                //MarkElement.ClassesS[Mark.Depth]       = NewRun;
                MarkElement.StartPos.Data[Mark.Depth] -= Pos;
            }
            else
            {
                //MarkElement.ClassesE[Mark.Depth]     = NewRun;
                MarkElement.EndPos.Data[Mark.Depth] -= Pos;
            }

            NewRun.SpellingMarks.push( Mark );

            this.SpellingMarks.splice( Index, 1 );
            SpellingMarksCount--;
            Index--;
        }
    }


    return NewRun;
};

ParaRun.prototype.Clear_TextPr = function()
{
    // Данная функция вызывается пока только при изменении стиля параграфа. Оставляем в этой ситуации язык неизмененным.        
    var NewTextPr = new CTextPr();
    NewTextPr.Lang = this.Pr.Lang.Copy();
    this.Set_Pr( NewTextPr );
};

// В данной функции мы применяем приходящие настройки поверх старых, т.е. старые не удаляем
ParaRun.prototype.Apply_Pr = function(TextPr)
{
    if(this.Type == para_Math_Run && !this.IsNormalText())
    {
        if(null === TextPr.Bold && null === TextPr.Italic)
            this.Math_Apply_Style(undefined);
        else
        {
            if(undefined != TextPr.Bold)
            {
                if(TextPr.Bold == true)
                {
                    if(this.MathPrp.sty == STY_ITALIC || this.MathPrp.sty == undefined)
                        this.Math_Apply_Style(STY_BI);
                    else if(this.MathPrp.sty == STY_PLAIN)
                        this.Math_Apply_Style(STY_BOLD);

                }
                else if(TextPr.Bold == false || TextPr.Bold == null)
                {
                    if(this.MathPrp.sty == STY_BI || this.MathPrp.sty == undefined)
                        this.Math_Apply_Style(STY_ITALIC);
                    else if(this.MathPrp.sty == STY_BOLD)
                        this.Math_Apply_Style(STY_PLAIN);
                }
            }

            if(undefined != TextPr.Italic)
            {
                if(TextPr.Italic == true)
                {
                    if(this.MathPrp.sty == STY_BOLD)
                        this.Math_Apply_Style(STY_BI);
                    else if(this.MathPrp.sty == STY_PLAIN || this.MathPrp.sty == undefined)
                        this.Math_Apply_Style(STY_ITALIC);
                }
                else if(TextPr.Italic == false || TextPr.Italic == null)
                {
                    if(this.MathPrp.sty == STY_BI)
                        this.Math_Apply_Style(STY_BOLD);
                    else if(this.MathPrp.sty == STY_ITALIC || this.MathPrp.sty == undefined)
                        this.Math_Apply_Style(STY_PLAIN);
                }
            }
        }
    }
    else
    {
        if ( undefined != TextPr.Bold )
            this.Set_Bold( null === TextPr.Bold ? undefined : TextPr.Bold );

        if( undefined != TextPr.Italic )
            this.Set_Italic( null === TextPr.Italic ? undefined : TextPr.Italic );
    }

    if ( undefined != TextPr.Strikeout )
        this.Set_Strikeout( null === TextPr.Strikeout ? undefined : TextPr.Strikeout );

    if ( undefined !== TextPr.Underline )
        this.Set_Underline( null === TextPr.Underline ? undefined : TextPr.Underline );

    if ( undefined != TextPr.FontSize )
        this.Set_FontSize( null === TextPr.FontSize ? undefined : TextPr.FontSize );

    if ( undefined !== TextPr.Color && undefined === TextPr.Unifill )
    {
        this.Set_Color( null === TextPr.Color ? undefined : TextPr.Color );
        this.Set_Unifill( undefined );
    }

    if ( undefined !== TextPr.Unifill )
    {
        this.Set_Unifill(null === TextPr.Unifill ? undefined : TextPr.Unifill);
        this.Set_Color(undefined);
    }

    if ( undefined != TextPr.VertAlign )
        this.Set_VertAlign( null === TextPr.VertAlign ? undefined : TextPr.VertAlign );

    if ( undefined != TextPr.HighLight )
        this.Set_HighLight( null === TextPr.HighLight ? undefined : TextPr.HighLight );

    if ( undefined !== TextPr.RStyle )
        this.Set_RStyle( null === TextPr.RStyle ? undefined : TextPr.RStyle );

    if ( undefined != TextPr.Spacing )
        this.Set_Spacing( null === TextPr.Spacing ? undefined : TextPr.Spacing );

    if ( undefined != TextPr.DStrikeout )
        this.Set_DStrikeout( null === TextPr.DStrikeout ? undefined : TextPr.DStrikeout );

    if ( undefined != TextPr.Caps )
        this.Set_Caps( null === TextPr.Caps ? undefined : TextPr.Caps );

    if ( undefined != TextPr.SmallCaps )
        this.Set_SmallCaps( null === TextPr.SmallCaps ? undefined : TextPr.SmallCaps );

    if ( undefined != TextPr.Position )
        this.Set_Position( null === TextPr.Position ? undefined : TextPr.Position );

    if ( undefined != TextPr.RFonts )
        this.Set_RFonts2( TextPr.RFonts );

    if ( undefined != TextPr.Lang )
        this.Set_Lang2( TextPr.Lang );

    if ( undefined !== TextPr.Shd )
        this.Set_Shd( TextPr.Shd );
};

ParaRun.prototype.Set_Bold = function(Value)
{
    if ( Value !== this.Pr.Bold )
    {
        var OldValue = this.Pr.Bold;
        this.Pr.Bold = Value;

        History.Add( this, { Type : historyitem_ParaRun_Bold, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr(true);
    }
};

ParaRun.prototype.Get_Bold = function()
{
    return this.Get_CompiledPr(false).Bold;
};

ParaRun.prototype.Set_Italic = function(Value)
{
    if ( Value !== this.Pr.Italic )
    {
        var OldValue = this.Pr.Italic;
        this.Pr.Italic = Value;

        History.Add( this, { Type : historyitem_ParaRun_Italic, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( true );
    }
};

ParaRun.prototype.Get_Italic = function()
{
    return this.Get_CompiledPr(false).Italic;
};

ParaRun.prototype.Set_Strikeout = function(Value)
{
    if ( Value !== this.Pr.Strikeout )
    {
        var OldValue = this.Pr.Strikeout;
        this.Pr.Strikeout = Value;

        History.Add( this, { Type : historyitem_ParaRun_Strikeout, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( false );
    }
};

ParaRun.prototype.Get_Strikeout = function()
{
    return this.Get_CompiledPr(false).Strikeout;
};

ParaRun.prototype.Set_Underline = function(Value)
{
    if ( Value !== this.Pr.Underline )
    {
        var OldValue = this.Pr.Underline;
        this.Pr.Underline = Value;

        History.Add( this, { Type : historyitem_ParaRun_Underline, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( false );
    }
};

ParaRun.prototype.Get_Underline = function()
{
    return this.Get_CompiledPr(false).Underline;
};

ParaRun.prototype.Set_FontSize = function(Value)
{
    if ( Value !== this.Pr.FontSize )
    {
        var OldValue = this.Pr.FontSize;
        this.Pr.FontSize = Value;

        History.Add( this, { Type : historyitem_ParaRun_FontSize, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( true );
    }
};

ParaRun.prototype.Get_FontSize = function()
{
    return this.Get_CompiledPr(false).FontSize;
};

ParaRun.prototype.Set_Color = function(Value)
{
    if ( ( undefined === Value && undefined !== this.Pr.Color ) || ( Value instanceof CDocumentColor && ( undefined === this.Pr.Color || false === Value.Compare(this.Pr.Color) ) ) )
    {
        var OldValue = this.Pr.Color;
        this.Pr.Color = Value;

        History.Add( this, { Type : historyitem_ParaRun_Color, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( false );
    }
};

ParaRun.prototype.Set_Unifill = function(Value)
{
    if ( ( undefined === Value && undefined !== this.Pr.Unifill ) || ( Value instanceof CUniFill && ( undefined === this.Pr.Unifill || false === CompareUnifillBool(this.Pr.Unifill, Value) ) ) )
    {
        var OldValue = this.Pr.Unifill;
        this.Pr.Unifill = Value;

        History.Add( this, { Type : historyitem_ParaRun_Unifill, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( false );
    }
};


ParaRun.prototype.Get_Color = function()
{
    return this.Get_CompiledPr(false).Color;
};

ParaRun.prototype.Set_VertAlign = function(Value)
{
    if ( Value !== this.Pr.VertAlign )
    {
        var OldValue = this.Pr.VertAlign;
        this.Pr.VertAlign = Value;

        History.Add( this, { Type : historyitem_ParaRun_VertAlign, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( true );
    }
};

ParaRun.prototype.Get_VertAlign = function()
{
    return this.Get_CompiledPr(false).VertAlign;
};

ParaRun.prototype.Set_HighLight = function(Value)
{
    var OldValue = this.Pr.HighLight;
    if ( (undefined === Value && undefined !== OldValue) || ( highlight_None === Value && highlight_None !== OldValue ) || ( Value instanceof CDocumentColor && ( undefined === OldValue || highlight_None === OldValue || false === Value.Compare(OldValue) ) ) )
    {
        this.Pr.HighLight = Value;
        History.Add( this, { Type : historyitem_ParaRun_HighLight, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( false );
    }
};

ParaRun.prototype.Get_HighLight = function()
{
    return this.Get_CompiledPr(false).HighLight;
};

ParaRun.prototype.Set_RStyle = function(Value)
{
    if ( Value !== this.Pr.RStyle )
    {
        var OldValue = this.Pr.RStyle;
        this.Pr.RStyle = Value;

        History.Add( this, { Type : historyitem_ParaRun_RStyle, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( true );
    }
};

ParaRun.prototype.Set_Spacing = function(Value)
{
    if ( Value !== this.Pr.Value )
    {
        var OldValue = this.Pr.Spacing;
        this.Pr.Spacing = Value;

        History.Add( this, { Type : historyitem_ParaRun_Spacing, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( true );
    }
};

ParaRun.prototype.Get_Spacing = function()
{
    return this.Get_CompiledPr(false).Spacing;
};

ParaRun.prototype.Set_DStrikeout = function(Value)
{
    if ( Value !== this.Pr.Value )
    {
        var OldValue = this.Pr.DStrikeout;
        this.Pr.DStrikeout = Value;

        History.Add( this, { Type : historyitem_ParaRun_DStrikeout, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr( false );
    }
};

ParaRun.prototype.Get_DStrikeout = function()
{
    return this.Get_CompiledPr(false).DStrikeout;
};

ParaRun.prototype.Set_Caps = function(Value)
{
    if ( Value !== this.Pr.Caps )
    {
        var OldValue = this.Pr.Caps;
        this.Pr.Caps = Value;

        History.Add( this, { Type : historyitem_ParaRun_Caps, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr( true );
    }
};

ParaRun.prototype.Get_Caps = function()
{
    return this.Get_CompiledPr(false).Caps;
};

ParaRun.prototype.Set_SmallCaps = function(Value)
{
    if ( Value !== this.Pr.SmallCaps )
    {
        var OldValue = this.Pr.SmallCaps;
        this.Pr.SmallCaps = Value;

        History.Add( this, { Type : historyitem_ParaRun_SmallCaps, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr( true );
    }
};

ParaRun.prototype.Get_SmallCaps = function()
{
    return this.Get_CompiledPr(false).SmallCaps;
};

ParaRun.prototype.Set_Position = function(Value)
{
    if ( Value !== this.Pr.Position )
    {
        var OldValue = this.Pr.Position;
        this.Pr.Position = Value;

        History.Add( this, { Type : historyitem_ParaRun_Position, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr( false );

        this.YOffset = this.Get_Position();
    }
};

ParaRun.prototype.Get_Position = function()
{
    return this.Get_CompiledPr(false).Position;
};

ParaRun.prototype.Set_RFonts = function(Value)
{
    var OldValue = this.Pr.RFonts;
    this.Pr.RFonts = Value;

    History.Add( this, { Type : historyitem_ParaRun_RFonts, New : Value, Old : OldValue } );

    this.Recalc_CompiledPr( true );
};

ParaRun.prototype.Get_RFonts = function()
{
    return this.Get_CompiledPr(false).RFonts;
};

ParaRun.prototype.Set_RFonts2 = function(RFonts)
{
    if ( undefined != RFonts )
    {
        if ( undefined != RFonts.Ascii )
            this.Set_RFonts_Ascii( RFonts.Ascii );

        if ( undefined != RFonts.HAnsi )
            this.Set_RFonts_HAnsi( RFonts.HAnsi );

        if ( undefined != RFonts.CS )
            this.Set_RFonts_CS( RFonts.CS );

        if ( undefined != RFonts.EastAsia )
            this.Set_RFonts_EastAsia( RFonts.EastAsia );

        if ( undefined != RFonts.Hint )
            this.Set_RFonts_Hint( RFonts.Hint );
    }
    else
    {
        this.Set_RFonts_Ascii( undefined );
        this.Set_RFonts_HAnsi( undefined );
        this.Set_RFonts_CS( undefined );
        this.Set_RFonts_EastAsia( undefined );
        this.Set_RFonts_Hint( undefined );
    }
};

ParaRun.prototype.Set_RFonts_Ascii = function(Value)
{
    if ( Value !== this.Pr.RFonts.Ascii )
    {
        var OldValue = this.Pr.RFonts.Ascii;
        this.Pr.RFonts.Ascii = Value;

        History.Add( this, { Type : historyitem_ParaRun_RFonts_Ascii, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr(true);
    }
};

ParaRun.prototype.Set_RFonts_HAnsi = function(Value)
{
    if ( Value !== this.Pr.RFonts.HAnsi )
    {
        var OldValue = this.Pr.RFonts.HAnsi;
        this.Pr.RFonts.HAnsi = Value;

        History.Add( this, { Type : historyitem_ParaRun_RFonts_HAnsi, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr(true);
    }
};

ParaRun.prototype.Set_RFonts_CS = function(Value)
{
    if ( Value !== this.Pr.RFonts.CS )
    {
        var OldValue = this.Pr.RFonts.CS;
        this.Pr.RFonts.CS = Value;

        History.Add( this, { Type : historyitem_ParaRun_RFonts_CS, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr(true);
    }
};

ParaRun.prototype.Set_RFonts_EastAsia = function(Value)
{
    if ( Value !== this.Pr.RFonts.EastAsia )
    {
        var OldValue = this.Pr.RFonts.EastAsia;
        this.Pr.RFonts.EastAsia = Value;

        History.Add( this, { Type : historyitem_ParaRun_RFonts_EastAsia, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr(true);
    }
};

ParaRun.prototype.Set_RFonts_Hint = function(Value)
{
    if ( Value !== this.Pr.RFonts.Hint )
    {
        var OldValue = this.Pr.RFonts.Hint;
        this.Pr.RFonts.Hint = Value;

        History.Add( this, { Type : historyitem_ParaRun_RFonts_Hint, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr(true);
    }
};

ParaRun.prototype.Set_Lang = function(Value)
{
    var OldValue = this.Pr.Lang;

    this.Pr.Lang = new CLang();
    if ( undefined != Value )
        this.Pr.Lang.Set_FromObject( Value );

    History.Add( this, { Type : historyitem_ParaRun_Lang, New : this.Pr.Lang, Old : OldValue } );
    this.Recalc_CompiledPr(false);
};

ParaRun.prototype.Set_Lang2 = function(Lang)
{
    if ( undefined != Lang )
    {
        if ( undefined != Lang.Bidi )
            this.Set_Lang_Bidi( Lang.Bidi );

        if ( undefined != Lang.EastAsia )
            this.Set_Lang_EastAsia( Lang.EastAsia );

        if ( undefined != Lang.Val )
            this.Set_Lang_Val( Lang.Val );

        // TODO: Орфография: пока сделаем так, в будущем надо будет переделать
        this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );
    }
};

ParaRun.prototype.Set_Lang_Bidi = function(Value)
{
    if ( Value !== this.Pr.Lang.Bidi )
    {
        var OldValue = this.Pr.Lang.Bidi;
        this.Pr.Lang.Bidi = Value;

        History.Add( this, { Type : historyitem_ParaRun_Lang_Bidi, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr(false);
    }
};

ParaRun.prototype.Set_Lang_EastAsia = function(Value)
{
    if ( Value !== this.Pr.Lang.EastAsia )
    {
        var OldValue = this.Pr.Lang.EastAsia;
        this.Pr.Lang.EastAsia = Value;

        History.Add( this, { Type : historyitem_ParaRun_Lang_EastAsia, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr(false);
    }
};

ParaRun.prototype.Set_Lang_Val = function(Value)
{
    if ( Value !== this.Pr.Lang.Val )
    {
        var OldValue = this.Pr.Lang.Val;
        this.Pr.Lang.Val = Value;

        History.Add( this, { Type : historyitem_ParaRun_Lang_Val, New : Value, Old : OldValue } );
        this.Recalc_CompiledPr(false);
    }
};

ParaRun.prototype.Set_Shd = function(Shd)
{
    if ( (undefined === this.Pr.Shd && undefined === Shd) || (undefined !== this.Pr.Shd && undefined !== Shd && true === this.Pr.Shd.Compare( Shd ) ) )
        return;

    var OldShd = this.Pr.Shd;

    if ( undefined !== Shd )
    {
        this.Pr.Shd = new CDocumentShd();
        this.Pr.Shd.Set_FromObject( Shd );
    }
    else
        this.Pr.Shd = undefined;

    History.Add( this, { Type : historyitem_ParaRun_Shd, New : this.Pr.Shd, Old : OldShd } );
    this.Recalc_CompiledPr(false);
};

//-----------------------------------------------------------------------------------
// Undo/Redo функции
//-----------------------------------------------------------------------------------
ParaRun.prototype.Undo = function(Data)
{
    var Type = Data.Type;

    switch ( Type )
    {
        case historyitem_ParaRun_AddItem :
        {
            this.Content.splice( Data.Pos, Data.EndPos - Data.Pos + 1 );

            this.RecalcInfo.Measure = true;
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            if (para_Math_Run === this.Type && undefined !== this.Parent && null !== this.Parent && null !== this.Parent.ParaMath)
                this.Parent.ParaMath.SetNeedResize();

            break;
        }

        case historyitem_ParaRun_RemoveItem :
        {
            var Pos = Data.Pos;

            var Array_start = this.Content.slice( 0, Pos );
            var Array_end   = this.Content.slice( Pos );

            this.Content = Array_start.concat( Data.Items, Array_end );

            this.RecalcInfo.Measure = true;
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            if (para_Math_Run === this.Type && undefined !== this.Parent && null !== this.Parent && null !== this.Parent.ParaMath)
                this.Parent.ParaMath.SetNeedResize();

            break;
        }

        case historyitem_ParaRun_TextPr:
        {
            if ( undefined != Data.Old )
                this.Pr = Data.Old;
            else
                this.Pr = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Bold:
        {
            if ( undefined != Data.Old )
                this.Pr.Bold = Data.Old;
            else
                this.Pr.Bold = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Italic:
        {
            if ( undefined != Data.Old )
                this.Pr.Italic = Data.Old;
            else
                this.Pr.Italic = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Strikeout:
        {
            if ( undefined != Data.Old )
                this.Pr.Strikeout = Data.Old;
            else
                this.Pr.Strikeout = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_Underline:
        {
            if ( undefined != Data.Old )
                this.Pr.Underline = Data.Old;
            else
                this.Pr.Underline = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_FontSize:
        {
            if ( undefined != Data.Old )
                this.Pr.FontSize = Data.Old;
            else
                this.Pr.FontSize = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Color:
        {
            if ( undefined != Data.Old )
                this.Pr.Color = Data.Old;
            else
                this.Pr.Color = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }
        case historyitem_ParaRun_Unifill:
        {
            if ( undefined != Data.Old )
                this.Pr.Unifill = Data.Old;
            else
                this.Pr.Unifill = undefined;

            this.Recalc_CompiledPr(false);
            break;
        }

        case historyitem_ParaRun_VertAlign:
        {
            if ( undefined != Data.Old )
                this.Pr.VertAlign = Data.Old;
            else
                this.Pr.VertAlign = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_HighLight:
        {
            if ( undefined != Data.Old )
                this.Pr.HighLight = Data.Old;
            else
                this.Pr.HighLight = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_RStyle:
        {
            if ( undefined != Data.Old )
                this.Pr.RStyle = Data.Old;
            else
                this.Pr.RStyle = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Spacing:
        {
            if ( undefined != Data.Old )
                this.Pr.Spacing = Data.Old;
            else
                this.Pr.Spacing = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }
        case historyitem_ParaRun_DStrikeout:
        {
            if ( undefined != Data.Old )
                this.Pr.DStrikeout = Data.Old;
            else
                this.Pr.DStrikeout = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }
        case historyitem_ParaRun_Caps:
        {
            if ( undefined != Data.Old )
                this.Pr.Caps = Data.Old;
            else
                this.Pr.Caps = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }
        case historyitem_ParaRun_SmallCaps:
        {
            if ( undefined != Data.Old )
                this.Pr.SmallCaps = Data.Old;
            else
                this.Pr.SmallCaps = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Position:
        {
            if ( undefined != Data.Old )
                this.Pr.Position = Data.Old;
            else
                this.Pr.Position = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts:
        {
            if ( undefined != Data.Old )
                this.Pr.RFonts = Data.Old;
            else
                this.Pr.RFonts = new CRFonts();

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_Ascii:
        {
            if ( undefined != Data.Old )
                this.Pr.RFonts.Ascii = Data.Old;
            else
                this.Pr.RFonts.Ascii = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_HAnsi:
        {
            if ( undefined != Data.Old )
                this.Pr.RFonts.HAnsi = Data.Old;
            else
                this.Pr.RFonts.HAnsi = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_CS:
        {
            if ( undefined != Data.Old )
                this.Pr.RFonts.CS = Data.Old;
            else
                this.Pr.RFonts.CS = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_EastAsia:
        {
            if ( undefined != Data.Old )
                this.Pr.RFonts.EastAsia = Data.Old;
            else
                this.Pr.RFonts.EastAsia = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_Hint:
        {
            if ( undefined != Data.Old )
                this.Pr.RFonts.Hint = Data.Old;
            else
                this.Pr.RFonts.Hint = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Lang:
        {
            if ( undefined != Data.Old )
                this.Pr.Lang = Data.Old;
            else
                this.Pr.Lang = new CLang();

            this.Recalc_CompiledPr(false);
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_Bidi:
        {
            if ( undefined != Data.Old )
                this.Pr.Lang.Bidi = Data.Old;
            else
                this.Pr.Lang.Bidi = undefined;

            this.Recalc_CompiledPr(false);
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_EastAsia:
        {
            if ( undefined != Data.Old )
                this.Pr.Lang.EastAsia = Data.Old;
            else
                this.Pr.Lang.EastAsia = undefined;

            this.Recalc_CompiledPr(false);
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_Val:
        {
            if ( undefined != Data.Old )
                this.Pr.Lang.Val = Data.Old;
            else
                this.Pr.Lang.Val = undefined;

            this.Recalc_CompiledPr(false);
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Shd:
        {
            this.Pr.Shd = Data.Old;
            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_MathStyle:
        {
            this.MathPrp.sty = Data.Old;
            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_MathPrp:
        {
            this.MathPrp = Data.Old;
            this.Recalc_CompiledPr(true);

            break;
        }
    }
};

ParaRun.prototype.Redo = function(Data)
{
    var Type = Data.Type;

    switch ( Type )
    {
        case  historyitem_ParaRun_AddItem:
        {
            var Pos = Data.Pos;

            var Array_start = this.Content.slice( 0, Pos );
            var Array_end   = this.Content.slice( Pos );

            this.Content = Array_start.concat( Data.Items, Array_end );

            this.RecalcInfo.Measure = true;
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            if (para_Math_Run === this.Type && undefined !== this.Parent && null !== this.Parent && null !== this.Parent.ParaMath)
                this.Parent.ParaMath.SetNeedResize();

            break;

        }

        case historyitem_ParaRun_RemoveItem:
        {
            this.Content.splice( Data.Pos, Data.EndPos - Data.Pos + 1 );

            this.RecalcInfo.Measure = true;
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            if (para_Math_Run === this.Type && undefined !== this.Parent && null !== this.Parent && null !== this.Parent.ParaMath)
                this.Parent.ParaMath.SetNeedResize();

            break;
        }

        case historyitem_ParaRun_TextPr:
        {
            if ( undefined != Data.New )
                this.Pr = Data.New;
            else
                this.Pr = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Bold:
        {
            if ( undefined != Data.New )
                this.Pr.Bold = Data.New;
            else
                this.Pr.Bold = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Italic:
        {
            if ( undefined != Data.New )
                this.Pr.Italic = Data.New;
            else
                this.Pr.Italic = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Strikeout:
        {
            if ( undefined != Data.New )
                this.Pr.Strikeout = Data.New;
            else
                this.Pr.Strikeout = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_Underline:
        {
            if ( undefined != Data.New )
                this.Pr.Underline = Data.New;
            else
                this.Pr.Underline = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_FontSize:
        {
            if ( undefined != Data.New )
                this.Pr.FontSize = Data.New;
            else
                this.Pr.FontSize = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Color:
        {
            if ( undefined != Data.New )
                this.Pr.Color = Data.New;
            else
                this.Pr.Color = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }
        case historyitem_ParaRun_Unifill:
        {
            if ( undefined != Data.New )
                this.Pr.Unifill = Data.New;
            else
                this.Pr.Unifill = undefined;

            this.Recalc_CompiledPr(false);
            break;
        }

        case historyitem_ParaRun_VertAlign:
        {
            if ( undefined != Data.New )
                this.Pr.VertAlign = Data.New;
            else
                this.Pr.VertAlign = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_HighLight:
        {
            if ( undefined != Data.New )
                this.Pr.HighLight = Data.New;
            else
                this.Pr.HighLight = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_RStyle:
        {
            if ( undefined != Data.New )
                this.Pr.RStyle = Data.New;
            else
                this.Pr.RStyle = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Spacing:
        {
            if ( undefined != Data.New )
                this.Pr.Spacing = Data.New;
            else
                this.Pr.Spacing = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }
        case historyitem_ParaRun_DStrikeout:
        {
            if ( undefined != Data.New )
                this.Pr.DStrikeout = Data.New;
            else
                this.Pr.DStrikeout = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }
        case historyitem_ParaRun_Caps:
        {
            if ( undefined != Data.New )
                this.Pr.Caps = Data.New;
            else
                this.Pr.Caps = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }
        case historyitem_ParaRun_SmallCaps:
        {
            if ( undefined != Data.New )
                this.Pr.SmallCaps = Data.New;
            else
                this.Pr.SmallCaps = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Position:
        {
            if ( undefined != Data.New )
                this.Pr.Position = Data.New;
            else
                this.Pr.Position = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts:
        {
            if ( undefined != Data.New )
                this.Pr.RFonts = Data.New;
            else
                this.Pr.RFonts = new CRFonts();

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_Ascii:
        {
            if ( undefined != Data.New )
                this.Pr.RFonts.Ascii = Data.New;
            else
                this.Pr.RFonts.Ascii = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_HAnsi:
        {
            if ( undefined != Data.New )
                this.Pr.RFonts.HAnsi = Data.New;
            else
                this.Pr.RFonts.HAnsi = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_CS:
        {
            if ( undefined != Data.New )
                this.Pr.RFonts.CS = Data.New;
            else
                this.Pr.RFonts.CS = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_EastAsia:
        {
            if ( undefined != Data.New )
                this.Pr.RFonts.EastAsia = Data.New;
            else
                this.Pr.RFonts.EastAsia = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_Hint:
        {
            if ( undefined != Data.New )
                this.Pr.RFonts.Hint = Data.New;
            else
                this.Pr.RFonts.Hint = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Lang:
        {
            if ( undefined != Data.New )
                this.Pr.Lang = Data.New;
            else
                this.Pr.Lang = new CLang();

            this.Recalc_CompiledPr(false);
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_Bidi:
        {
            if ( undefined != Data.New )
                this.Pr.Lang.Bidi = Data.New;
            else
                this.Pr.Lang.Bidi = undefined;

            this.Recalc_CompiledPr(false);
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_EastAsia:
        {
            if ( undefined != Data.New )
                this.Pr.Lang.EastAsia = Data.New;
            else
                this.Pr.Lang.EastAsia = undefined;

            this.Recalc_CompiledPr(false);
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_Val:
        {
            if ( undefined != Data.New )
                this.Pr.Lang.Val = Data.New;
            else
                this.Pr.Lang.Val = undefined;

            this.Recalc_CompiledPr(false);
            this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Shd:
        {
            this.Pr.Shd = Data.New;
            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_MathStyle:
        {
            this.MathPrp.sty = Data.New;
            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_MathPrp:
        {
            this.MathPrp = Data.New;
            this.Recalc_CompiledPr(true);

            break;
        }
    }
};

ParaRun.prototype.Check_HistoryUninon = function(Data1, Data2)
{
    var Type1 = Data1.Type;
    var Type2 = Data2.Type;

    if ( historyitem_ParaRun_AddItem === Type1 && historyitem_ParaRun_AddItem === Type2 )
    {
        if ( 1 === Data1.Items.length && 1 === Data2.Items.length && Data1.Pos === Data2.Pos - 1 && para_Text === Data1.Items[0].Type && para_Text === Data2.Items[0].Type )
            return true;
    }

    return false;
};
//-----------------------------------------------------------------------------------
// Функции для совместного редактирования
//-----------------------------------------------------------------------------------
ParaRun.prototype.Save_Changes = function(Data, Writer)
{
    // Сохраняем изменения из тех, которые используются для Undo/Redo в бинарный файл.
    // Long : тип класса
    // Long : тип изменений

    Writer.WriteLong( historyitem_type_ParaRun );

    var Type = Data.Type;

    // Пишем тип
    Writer.WriteLong( Type );

    switch ( Type )
    {
        case historyitem_ParaRun_AddItem:
        {
            // Long     : Количество элементов
            // Array of :
            //  {
            //    Long     : Позиция
            //    Variable : Элемент
            //  }

            var bArray = Data.UseArray;
            var Count  = Data.Items.length;

            Writer.WriteLong( Count );

            for ( var Index = 0; Index < Count; Index++ )
            {
                if ( true === bArray )
                    Writer.WriteLong( Data.PosArray[Index] );
                else
                    Writer.WriteLong( Data.Pos + Index );

                Data.Items[Index].Write_ToBinary(Writer);
            }

            break;
        }

        case historyitem_ParaRun_RemoveItem:
        {
            // Long          : Количество удаляемых элементов
            // Array of Long : позиции удаляемых элементов

            var bArray = Data.UseArray;
            var Count  = Data.Items.length;

            var StartPos = Writer.GetCurPosition();
            Writer.Skip(4);
            var RealCount = Count;

            for ( var Index = 0; Index < Count; Index++ )
            {
                if ( true === bArray )
                {
                    if ( false === Data.PosArray[Index] )
                        RealCount--;
                    else
                        Writer.WriteLong( Data.PosArray[Index] );
                }
                else
                    Writer.WriteLong( Data.Pos );
            }

            var EndPos = Writer.GetCurPosition();
            Writer.Seek( StartPos );
            Writer.WriteLong( RealCount );
            Writer.Seek( EndPos );

            break;
        }

        case historyitem_ParaRun_TextPr:
        {
            // CTextPr
            this.Pr.Write_ToBinary( Writer );

            break;
        }

        case historyitem_ParaRun_Bold:
        case historyitem_ParaRun_Italic:
        case historyitem_ParaRun_Strikeout:
        case historyitem_ParaRun_Underline:
        {
            // Bool : IsUndefined
            // Bool : Value

            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Writer.WriteBool( Data.New );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_FontSize:
        {
            // Bool   : IsUndefined
            // Double : FontSize

            if ( undefined != Data.New )
            {
                Writer.WriteBool(false);
                Writer.WriteDouble( Data.New );
            }
            else
                Writer.WriteBool(true);

            break;
        }

        case historyitem_ParaRun_Color:
        {
            // Bool     : IsUndefined
            // Variable : Color (CDocumentColor)

            if ( undefined != Data.New )
            {
                Writer.WriteBool(false);
                Data.New.Write_ToBinary( Writer );
            }
            else
                Writer.WriteBool(true);

            break;
        }

        case historyitem_ParaRun_Unifill:
        {
            if ( undefined != Data.New )
            {
                Writer.WriteBool(false);
                Data.New.Write_ToBinary( Writer );
            }
            else
                Writer.WriteBool(true);

            break;
        }

        case historyitem_ParaRun_VertAlign:
        {
            // Bool  : IsUndefined
            // Long  : VertAlign

            if ( undefined != Data.New )
            {
                Writer.WriteBool(false);
                Writer.WriteLong(Data.New);
            }
            else
                Writer.WriteBool(true);

            break;
        }

        case historyitem_ParaRun_HighLight:
        {
            // Bool  : IsUndefined
            // Если false
            //   Bool  : IsNone
            //   Если false
            //     Variable : Color (CDocumentColor)

            if ( undefined != Data.New )
            {
                Writer.WriteBool(false);
                if ( highlight_None != Data.New )
                {
                    Writer.WriteBool( false );
                    Data.New.Write_ToBinary( Writer );
                }
                else
                    Writer.WriteBool( true );
            }
            else
                Writer.WriteBool(true);

            break;
        }

        case historyitem_ParaRun_RStyle:
        {
            // Bool : IsUndefined
            // Если false
            //   String : RStyle

            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Writer.WriteString2( Data.New );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_Spacing:
        case historyitem_ParaRun_Position:
        {
            // Bool : IsUndefined
            // Если false
            //   Double : Spacing

            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Writer.WriteDouble( Data.New );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_DStrikeout:
        case historyitem_ParaRun_Caps:
        case historyitem_ParaRun_SmallCaps:
        {
            // Bool : IsUndefined
            // Если false
            //   Bool : value

            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Writer.WriteBool( Data.New );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_RFonts:
        {
            // Bool : undefined ?
            // false -> CRFonts
            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Data.New.Write_ToBinary( Writer );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_RFonts_Ascii:
        case historyitem_ParaRun_RFonts_HAnsi:
        case historyitem_ParaRun_RFonts_CS:
        case historyitem_ParaRun_RFonts_EastAsia:
        {
            // Bool : undefined?
            // false -> String

            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Writer.WriteString2( Data.New.Name );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_RFonts_Hint:
        {
            // Bool : undefined?
            // false -> Long

            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Writer.WriteLong( Data.New );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_Lang:
        {
            // Bool : undefined ?
            // false -> CLang
            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Data.New.Write_ToBinary( Writer );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_Lang_Bidi:
        case historyitem_ParaRun_Lang_EastAsia:
        case historyitem_ParaRun_Lang_Val:
        {
            // Bool : undefined ?
            // false -> Long
            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Writer.WriteLong( Data.New );
            }
            else
                Writer.WriteBool( true );

            break;
        }

        case historyitem_ParaRun_Shd:
        {
            // Bool : undefined
            // false - >
            // Variable : CDocumentShd

            if ( undefined !== Data.New )
            {
                Writer.WriteBool(false);
                Data.New.Write_ToBinary(Writer);
            }
            else
                Writer.WriteBool(true);

            break;
        }
        case historyitem_ParaRun_MathStyle:
        {
            // Bool : undefined ?
            // false -> Long
            if ( undefined != Data.New )
            {
                Writer.WriteBool( false );
                Writer.WriteLong( Data.New );
            }
            else
                Writer.WriteBool( true );
            break;
        }
        case historyitem_ParaRun_MathPrp:
        {
            var StartPos = Writer.GetCurPosition();
            Writer.Skip(4);
            var Flags = 0;
            if ( undefined != this.MathPrp.aln )
            {
                Writer.WriteBool( this.MathPrp.aln );
                Flags |= 1;
            }
            if ( undefined != this.MathPrp.brk )
            {
                Writer.WriteBool( this.MathPrp.brk );
                Flags |= 2;
            }
            if ( undefined != this.MathPrp.lit )
            {
                Writer.WriteBool( this.MathPrp.lit );
                Flags |= 4;
            }
            if ( undefined != this.MathPrp.nor )
            {
                Writer.WriteBool( this.MathPrp.nor );
                Flags |= 8;
            }
            if ( undefined != this.MathPrp.scr )
            {
                Writer.WriteLong( this.MathPrp.scr );
                Flags |= 16;
            }
            if ( undefined != this.MathPrp.sty )
            {
                Writer.WriteLong( this.MathPrp.sty );
                Flags |= 32;
            }
            var EndPos = Writer.GetCurPosition();
            Writer.Seek( StartPos );
            Writer.WriteLong( Flags );
            Writer.Seek( EndPos );
            break;
        }
    }

    return Writer;
};

ParaRun.prototype.Load_Changes = function(Reader, Reader2, Color)
{
    // Сохраняем изменения из тех, которые используются для Undo/Redo в бинарный файл.
    // Long : тип класса
    // Long : тип изменений

    var ClassType = Reader.GetLong();
    if ( historyitem_type_ParaRun != ClassType )
        return;

    var Type = Reader.GetLong();

    switch ( Type )
    {
        case historyitem_ParaRun_AddItem :
        {
            // Long     : Количество элементов
            // Array of :
            //  {
            //    Long     : Позиция
            //    Variable : Id Элемента
            //  }

            var Count = Reader.GetLong();

            for ( var Index = 0; Index < Count; Index++ )
            {
                var Pos     = this.m_oContentChanges.Check( contentchanges_Add, Reader.GetLong() );
                var Element = ParagraphContent_Read_FromBinary(Reader);

                if ( null != Element )
                {
                    if (null !== Color)
                    {
                        this.CollaborativeMarks.Update_OnAdd( Pos );
                        this.CollaborativeMarks.Add( Pos, Pos + 1, Color );
                        CollaborativeEditing.Add_ChangedClass(this);
                    }

                    this.Content.splice( Pos, 0, Element );
                }
            }

            this.RecalcInfo.Measure = true;

            if ( undefined !== this.Paragraph && null !== this.Paragraph )
                this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            if (para_Math_Run === this.Type && undefined !== this.Parent && null !== this.Parent && null !== this.Parent.ParaMath)
                this.Parent.ParaMath.SetNeedResize();

            break;
        }

        case historyitem_ParaRun_RemoveItem:
        {
            // Long          : Количество удаляемых элементов
            // Array of Long : позиции удаляемых элементов

            var Count = Reader.GetLong();

            for ( var Index = 0; Index < Count; Index++ )
            {
                var ChangesPos = this.m_oContentChanges.Check( contentchanges_Remove, Reader.GetLong() );

                // действие совпало, не делаем его
                if ( false === ChangesPos )
                    continue;

                this.CollaborativeMarks.Update_OnRemove( ChangesPos, 1 );
                this.Content.splice( ChangesPos, 1 );
            }

            this.RecalcInfo.Measure = true;

            if (undefined !== this.Paragraph && null !== this.Paragraph)
                this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            if (para_Math_Run === this.Type && undefined !== this.Parent && null !== this.Parent && null !== this.Parent.ParaMath)
                this.Parent.ParaMath.SetNeedResize();

            break;
        }

        case historyitem_ParaRun_TextPr:
        {
            // CTextPr
            this.Pr = new CTextPr();
            this.Pr.Read_FromBinary( Reader );

            break;
        }

        case historyitem_ParaRun_Bold:
        {
            // Bool : IsUndefined
            // Bool : Bold

            if ( true === Reader.GetBool() )
                this.Pr.Bold = undefined;
            else
                this.Pr.Bold = Reader.GetBool();

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Italic:
        {
            // Bool : IsUndefined
            // Bool : Italic

            if ( true === Reader.GetBool() )
                this.Pr.Italic = undefined;
            else
                this.Pr.Italic = Reader.GetBool();

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Strikeout:
        {
            // Bool : IsUndefined
            // Bool : Strikeout

            if ( true === Reader.GetBool() )
                this.Pr.Strikeout = undefined;
            else
                this.Pr.Strikeout = Reader.GetBool();

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_Underline:
        {
            // Bool   : IsUndefined?
            // Bool   : Underline

            if ( true != Reader.GetBool() )
                this.Pr.Underline = Reader.GetBool();
            else
                this.Pr.Underline = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_FontSize:
        {
            // Bool   : IsUndefined
            // Double : FontSize

            if ( true != Reader.GetBool() )
                this.Pr.FontSize = Reader.GetDouble();
            else
                this.Pr.FontSize = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Color:
        {
            // Bool     : IsUndefined
            // Variable : Color (CDocumentColor)

            if ( true != Reader.GetBool() )
            {
                this.Pr.Color = new CDocumentColor(0, 0, 0, false);
                this.Pr.Color.Read_FromBinary(Reader);
            }
            else
                this.Pr.Color = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }


        case historyitem_ParaRun_Unifill:
        {

            if ( true != Reader.GetBool() )
            {
                var unifill = new CUniFill();
                unifill.Read_FromBinary(Reader);
                this.Pr.Unifill = unifill;
            }
            else
                this.Pr.Unifill = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_VertAlign:
        {
            // Bool  : IsUndefined
            // Long  : VertAlign

            if ( true != Reader.GetBool() )
                this.Pr.VertAlign = Reader.GetLong();
            else
                this.Pr.VertAlign = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_HighLight:
        {
            // Bool  : IsUndefined
            // Если false
            //   Bool  : IsNull
            //   Если false
            //     Variable : Color (CDocumentColor)

            if ( true != Reader.GetBool() )
            {
                if ( true != Reader.GetBool() )
                {
                    this.Pr.HighLight = new CDocumentColor(0,0,0);
                    this.Pr.HighLight.Read_FromBinary(Reader);
                }
                else
                    this.Pr.HighLight = highlight_None;
            }
            else
                this.Pr.HighLight = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_RStyle:
        {
            // Bool : IsUndefined
            // Если false
            //   String : RStyle

            if ( true != Reader.GetBool() )
                this.Pr.RStyle = Reader.GetString2();
            else
                this.Pr.RStyle = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Spacing:
        {
            // Bool : IsUndefined
            // Если false
            //   Double : Spacing

            if ( true != Reader.GetBool() )
                this.Pr.Spacing = Reader.GetDouble();
            else
                this.Pr.Spacing = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_DStrikeout:
        {
            // Bool : IsUndefined
            // Если false
            //   Bool : DStrikeout

            if ( true != Reader.GetBool() )
                this.Pr.DStrikeout = Reader.GetBool();
            else
                this.Pr.DStrikeout = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }

        case historyitem_ParaRun_Caps:
        {
            // Bool : IsUndefined
            // Если false
            //   Bool : Caps

            if ( true != Reader.GetBool() )
                this.Pr.Caps = Reader.GetBool();
            else
                this.Pr.Caps = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_SmallCaps:
        {
            // Bool : IsUndefined
            // Если false
            //   Bool : SmallCaps

            if ( true != Reader.GetBool() )
                this.Pr.SmallCaps = Reader.GetBool();
            else
                this.Pr.SmallCaps = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Position:
        {
            // Bool : IsUndefined
            // Если false
            //   Double : Position

            if ( true != Reader.GetBool() )
                this.Pr.Position = Reader.GetDouble();
            else
                this.Pr.Position = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts:
        {
            // Bool : undefined ?
            // false -> CRFonts
            if ( false === Reader.GetBool() )
            {
                this.Pr.RFonts = new CRFonts();
                this.Pr.RFonts.Read_FromBinary( Reader );
            }
            else
                this.Pr.RFonts = new CRFonts();

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_Ascii:
        {
            // Bool : undefined ?
            // false -> String
            if ( false === Reader.GetBool() )
            {
                this.Pr.RFonts.Ascii =
                {
                    Name  : Reader.GetString2(),
                    Index : -1
                };
            }
            else
                this.Pr.RFonts.Ascii = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_HAnsi:
        {
            // Bool : undefined ?
            // false -> String
            if ( false === Reader.GetBool() )
            {
                this.Pr.RFonts.HAnsi =
                {
                    Name  : Reader.GetString2(),
                    Index : -1
                };
            }
            else
                this.Pr.RFonts.HAnsi = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_CS:
        {
            // Bool : undefined ?
            // false -> String
            if ( false === Reader.GetBool() )
            {
                this.Pr.RFonts.CS =
                {
                    Name  : Reader.GetString2(),
                    Index : -1
                };
            }
            else
                this.Pr.RFonts.CS = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_EastAsia:
        {
            // Bool : undefined ?
            // false -> String
            if ( false === Reader.GetBool() )
            {
                this.Pr.RFonts.EastAsia =
                {
                    Name  : Reader.GetString2(),
                    Index : -1
                };
            }
            else
                this.Pr.RFonts.EastAsia = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_RFonts_Hint:
        {
            // Bool : undefined ?
            // false -> Long
            if ( false === Reader.GetBool() )
                this.Pr.RFonts.Hint = Reader.GetLong();
            else
                this.Pr.RFonts.Hint = undefined;

            this.Recalc_CompiledPr(true);

            break;
        }

        case historyitem_ParaRun_Lang:
        {
            // Bool : undefined ?
            // false -> Lang
            if ( false === Reader.GetBool() )
            {
                this.Pr.Lang = new CLang();
                this.Pr.Lang.Read_FromBinary( Reader );
            }
            else
                this.Pr.Lang = new CLang();

            this.Recalc_CompiledPr(true);

            if ( undefined !== this.Paragraph && null !== this.Paragraph )
                this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_Bidi:
        {
            // Bool : undefined ?
            // false -> Long

            if ( false === Reader.GetBool() )
                this.Pr.Lang.Bidi = Reader.GetLong();
            else
                this.Pr.Lang.Bidi = undefined;

            this.Recalc_CompiledPr(true);

            if ( undefined !== this.Paragraph && null !== this.Paragraph )
                this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_EastAsia:
        {
            // Bool : undefined ?
            // false -> Long

            if ( false === Reader.GetBool() )
                this.Pr.Lang.EastAsia = Reader.GetLong();
            else
                this.Pr.Lang.EastAsia = undefined;

            this.Recalc_CompiledPr(true);

            if ( undefined !== this.Paragraph && null !== this.Paragraph )
                this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Lang_Val:
        {
            // Bool : undefined ?
            // false -> Long

            if ( false === Reader.GetBool() )
                this.Pr.Lang.Val = Reader.GetLong();
            else
                this.Pr.Lang.Val = undefined;

            this.Recalc_CompiledPr(true);

            if ( undefined !== this.Paragraph && null !== this.Paragraph )
                this.Paragraph.RecalcInfo.Set_Type_0_Spell( pararecalc_0_Spell_All );

            break;
        }

        case historyitem_ParaRun_Shd:
        {
            // Bool : undefined
            // false - >
            // Variable : CDocumentShd

            if ( false === Reader.GetBool() )
            {
                this.Pr.Shd = new CDocumentShd();
                this.Pr.Shd.Read_FromBinary( Reader );
            }
            else
                this.Pr.Shd = undefined;

            this.Recalc_CompiledPr(false);

            break;
        }
        case historyitem_ParaRun_MathStyle:
        {
            // Bool : undefined ?
            // false -> Long
            if ( false === Reader.GetBool() )
                this.MathPrp.sty = Reader.GetLong();
            else
                this.MathPrp.sty = undefined;

            this.Recalc_CompiledPr(true);
            break;
        }
        case historyitem_ParaRun_MathPrp:
        {
            var Flags = Reader.GetLong();
            if ( Flags & 1 )
                this.MathPrp.aln = Reader.GetBool();
            if ( Flags & 2 )
                this.MathPrp.brk = Reader.GetBool();
            if ( Flags & 4 )
                this.MathPrp.lit = Reader.GetBool();
            if ( Flags & 8 )
                this.MathPrp.nor = Reader.GetBool();
            if ( Flags & 16 )
                this.MathPrp.scr = Reader.GetLong();
            if ( Flags & 32 )
                this.MathPrp.sty = Reader.GetLong();

            this.Recalc_CompiledPr(true);
            break;
        }
    }
};

ParaRun.prototype.Write_ToBinary2 = function(Writer)
{
    Writer.WriteLong( historyitem_type_ParaRun );

    // Long     : Type
    // String   : Id
    // String   : Paragraph Id
    // Variable : CTextPr
    // Long     : Количество элементов
    // Array of variable : массив с элементами

    Writer.WriteLong(this.Type);
    var ParagraphToWrite, PrToWrite, ContentToWrite;
    if(this.StartState)
    {
        ParagraphToWrite = this.StartState.Paragraph;
        PrToWrite = this.StartState.Pr;
        ContentToWrite = this.StartState.Content;
    }
    else
    {
        ParagraphToWrite = this.Paragraph;
        PrToWrite = this.Pr;
        ContentToWrite = this.Content;
    }

    Writer.WriteString2( this.Id );
    Writer.WriteString2( null !== ParagraphToWrite && undefined !== ParagraphToWrite ? ParagraphToWrite.Get_Id() : "" );
    PrToWrite.Write_ToBinary( Writer );

    var Count = ContentToWrite.length;
    Writer.WriteLong( Count );
    for ( var Index = 0; Index < Count; Index++ )
    {
        var Item = ContentToWrite[Index];
        Item.Write_ToBinary( Writer );
    }
};

ParaRun.prototype.Read_FromBinary2 = function(Reader)
{
    // Long     : Type
    // String   : Id
    // String   : Paragraph Id
    // Variable : CTextPr
    // Long     : Количество элементов
    // Array of variable : массив с элементами

    this.Type      = Reader.GetLong();
    this.Id        = Reader.GetString2();
    this.Paragraph = g_oTableId.Get_ById( Reader.GetString2() );
    this.Pr        = new CTextPr();
    this.Pr.Read_FromBinary( Reader );

    if (para_Math_Run == this.Type)
	{
        this.MathPrp = new CMPrp();
		this.size    = new CMathSize();
	}

    if(undefined !== editor && true === editor.isDocumentEditor)
    {
        var Count = Reader.GetLong();
        this.Content = [];
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Element = ParagraphContent_Read_FromBinary( Reader );
            if ( null !== Element )
                this.Content.push( Element );
        }
    }
};

ParaRun.prototype.Clear_CollaborativeMarks = function()
{
    this.CollaborativeMarks.Clear();
};

function CParaRunSelection()
{
    this.Use      = false;
    this.StartPos = 0;
    this.EndPos   = 0;
}

function CParaRunState()
{
    this.Selection  = new CParaRunSelection();
    this.ContentPos = 0;
}

function CParaRunRecalcInfo()
{
    this.TextPr  = true; // Нужно ли пересчитать скомпилированные настройки
    this.Measure = true; // Нужно ли перемерять элементы
    this.Recalc  = true; // Нужно ли пересчитывать (только если текстовый ран)
    this.RunLen  = 0;

    // Далее идут параметры, которые выставляются после пересчета данного Range, такие как пересчитывать ли нумерацию
    this.NumberingItem = null;
    this.NumberingUse  = false; // Используется ли нумерация в данном ране
    this.NumberingAdd  = true;  // Нужно ли в следующем ране использовать нумерацию
}

CParaRunRecalcInfo.prototype =
{
    Reset : function()
    {
        this.TextPr  = true;
        this.Measure = true;
        this.Recalc  = true;
        this.RunLen  = 0;
    }

};

function CParaRunRange(StartPos, EndPos)
{
    this.StartPos = StartPos; // Начальная позиция в контенте, с которой начинается данный отрезок
    this.EndPos   = EndPos;   // Конечная позиция в контенте, на которой заканчивается данный отрезок (перед которой)
}

function CParaRunLine()
{
    this.Ranges       = [];
    this.Ranges[0]    = new CParaRunRange( 0, 0 );
    this.RangesLength = 0;
}

CParaRunLine.prototype =
{
    Add_Range : function(RangeIndex, StartPos, EndPos)
    {
        if ( 0 !== RangeIndex )
        {
            this.Ranges[RangeIndex] = new CParaRunRange( StartPos, EndPos );
            this.RangesLength  = RangeIndex + 1;
        }
        else
        {
            this.Ranges[0].StartPos = StartPos;
            this.Ranges[0].EndPos   = EndPos;
            this.RangesLength = 1;
        }

        if ( this.Ranges.length > this.RangesLength )
            this.Ranges.legth = this.RangesLength;
    },

    Copy : function()
    {
        var NewLine = new CParaRunLine();

        NewLine.RangesLength = this.RangesLength;

        for ( var CurRange = 0; CurRange < this.RangesLength; CurRange++ )
        {
            var Range = this.Ranges[CurRange];
            NewLine.Ranges[CurRange] = new CParaRunRange( Range.StartPos, Range.EndPos );
        }

        return NewLine;
    },

    Compare : function(OtherLine, CurRange)
    {
        // Сначала проверим наличие данного отрезка в обеих строках
        if ( this.RangesLength <= CurRange || OtherLine.RangesLength <= CurRange )
            return false;

        var OtherRange = OtherLine.Ranges[CurRange];
        var ThisRange  = this.Ranges[CurRange];

        if ( OtherRange.StartPos !== ThisRange.StartPos || OtherRange.EndPos !== ThisRange.EndPos )
            return false;

        return true;
    }


};

// Метка о конце или начале изменений пришедших от других соавторов документа
var pararun_CollaborativeMark_Start = 0x00;
var pararun_CollaborativeMark_End   = 0x01;

function CParaRunCollaborativeMark(Pos, Type)
{
    this.Pos  = Pos;
    this.Type = Type;
}

function FontSize_IncreaseDecreaseValue(bIncrease, Value)
{
    // Закон изменения размеров :
    // 1. Если значение меньше 8, тогда мы увеличиваем/уменьшаем по 1 (от 1 до 8)
    // 2. Если значение больше 72, тогда мы увеличиваем/уменьшаем по 10 (от 80 до бесконечности
    // 3. Если значение в отрезке [8,72], тогда мы переходим по следующим числам 8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72

    var Sizes = [8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72];

    var NewValue = Value;
    if ( true === bIncrease )
    {
        if ( Value < Sizes[0] )
        {
            if ( Value >= Sizes[0] - 1 )
                NewValue = Sizes[0];
            else
                NewValue = Math.floor(Value + 1);
        }
        else if ( Value >= Sizes[Sizes.length - 1] )
        {
            NewValue = Math.min( 300, Math.floor( Value / 10 + 1 ) * 10 );
        }
        else
        {
            for ( var Index = 0; Index < Sizes.length; Index++ )
            {
                if ( Value < Sizes[Index] )
                {
                    NewValue = Sizes[Index];
                    break;
                }
            }
        }
    }
    else
    {
        if ( Value <= Sizes[0] )
        {
            NewValue = Math.max( Math.floor( Value - 1 ), 1 );
        }
        else if ( Value > Sizes[Sizes.length - 1] )
        {
            if ( Value <= Math.floor( Sizes[Sizes.length - 1] / 10 + 1 ) * 10 )
                NewValue = Sizes[Sizes.length - 1];
            else
                NewValue = Math.floor( Math.ceil(Value / 10) - 1 ) * 10;
        }
        else
        {
            for ( var Index = Sizes.length - 1; Index >= 0; Index-- )
            {
                if ( Value > Sizes[Index] )
                {
                    NewValue = Sizes[Index];
                    break;
                }
            }
        }
    }

    return NewValue;
}


function CRunCollaborativeMarks()
{
    this.Ranges = [];
    this.DrawingObj = {};
}

CRunCollaborativeMarks.prototype =
{
    Add : function(PosS, PosE, Color)
    {
        var Count = this.Ranges.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Range = this.Ranges[Index];

            if ( PosS > Range.PosE )
                continue;
            else if ( PosS >= Range.PosS && PosS <= Range.PosE && PosE >= Range.PosS && PosE <= Range.PosE )
            {
                if ( true !== Color.Compare(Range.Color) )
                {            
                    var _PosE = Range.PosE;
                    Range.PosE = PosS;
                    this.Ranges.splice( Index + 1, 0, new CRunCollaborativeRange(PosS, PosE, Color) );
                    this.Ranges.splice( Index + 2, 0, new CRunCollaborativeRange(PosE, _PosE, Range.Color) );                    
                }
                
                return;
            }
            else if ( PosE < Range.PosS )
            {
                this.Ranges.splice( Index, 0, new CRunCollaborativeRange(PosS, PosE, Color) );
                return;
            }
            else if ( PosS < Range.PosS && PosE > Range.PosE )
            {
                Range.PosS = PosS;
                Range.PosE = PosE;
                Range.Color = Color;
                return;
            }
            else if ( PosS < Range.PosS ) // && PosE <= Range.PosE )
            {
                if ( true === Color.Compare(Range.Color) )
                    Range.PosS = PosS;
                else
                {
                    Range.PosS = PosE;
                    this.Ranges.splice( Index, 0, new CRunCollaborativeRange(PosS, PosE, Color) );
                }
                
                return;
            }
            else //if ( PosS >= Range.PosS && PosE > Range.Pos.E )
            {
                if ( true === Color.Compare(Range.Color) )
                    Range.PosE = PosE;
                else
                {
                    Range.PosE = PosS;
                    this.Ranges.splice( Index + 1, 0, new CRunCollaborativeRange(PosS, PosE, Color) );
                }
                
                return;
            }
        }

        this.Ranges.push( new CRunCollaborativeRange(PosS, PosE, Color) );
    },

    Update_OnAdd : function(Pos)
    {
        var Count = this.Ranges.length;
        for ( var Index = 0; Index < Count; Index++ )
        {
            var Range = this.Ranges[Index];

            if ( Pos <= Range.PosS )
            {
                Range.PosS++;
                Range.PosE++;
            }
            else if ( Pos > Range.PosS && Pos < Range.PosE )
            {
                var NewRange = new CRunCollaborativeRange( Pos + 1, Range.PosE + 1, Range.Color.Copy() );
                this.Ranges.splice( Index + 1, 0, NewRange );
                Range.PosE = Pos;
                Count++;
                Index++;
            }
            //else if ( Pos < Range.PosE )
            //    Range.PosE++;
        }
    },

    Update_OnRemove : function(Pos, Count)
    {
        var Len = this.Ranges.length;
        for ( var Index = 0; Index < Len; Index++ )
        {
            var Range = this.Ranges[Index];

            var PosE = Pos + Count;
            if ( Pos < Range.PosS )
            {
                if ( PosE <= Range.PosS )
                {
                    Range.PosS -= Count;
                    Range.PosE -= Count;
                }
                else if ( PosE >= Range.PosE )
                {
                    this.Ranges.splice( Index, 1 );
                    Len--;
                    Index--;continue;
                }
                else
                {
                    Range.PosS = Pos;
                    Range.PosE -= Count;
                }
            }
            else if ( Pos >= Range.PosS && Pos < Range.PosE )
            {
                if ( PosE >= Range.PosE )
                    Range.PosE = Pos;
                else
                    Range.PosE -= Count;
            }
            else
                continue;
        }
    },

    Clear : function()
    {
        this.Ranges = [];
    },

    Init_Drawing  : function()
    {
        this.DrawingObj = {};

        var Count = this.Ranges.length;
        for ( var CurPos = 0; CurPos < Count; CurPos++ )
        {
            var Range = this.Ranges[CurPos];

            for ( var Pos = Range.PosS; Pos < Range.PosE; Pos++ )
                this.DrawingObj[Pos] = Range.Color;
        }
    },

    Check : function(Pos)
    {
        if ( undefined !== this.DrawingObj[Pos] )
            return this.DrawingObj[Pos];

        return null;
    }
};

function CRunCollaborativeRange(PosS, PosE, Color)
{
    this.PosS  = PosS;
    this.PosE  = PosE;
    this.Color = Color;
}


ParaRun.prototype.Math_SetPosition = function(PosInfo)
{
    var NewPos;

    if(this.bEqqArray)
    {
        for(var Pos = 0; Pos < this.Content.length; Pos++)
        {
            var CurrElem = this.Content[Pos];

            NewPos = new CMathPosition();

            if(this.Content[Pos].Type == para_Math_Ampersand)
            {
                PosInfo.NextAlignRange();
                PosInfo.ApplyAlign();

                NewPos.x = PosInfo.x;
                NewPos.y = PosInfo.y - this.size.ascent;
                CurrElem.setPosition(NewPos);
            }
            else
            {
                NewPos.x = PosInfo.x;
                NewPos.y = PosInfo.y - this.size.ascent;

                CurrElem.setPosition(NewPos);
            }

            PosInfo.UpdateX(CurrElem.size.width);

        }
    }
    else
    {
        for(var i = 0; i < this.Content.length; i++)
        {
            NewPos = new CMathPosition();

            NewPos.x = PosInfo.x;
            NewPos.y = PosInfo.y - this.size.ascent;

            this.Content[i].setPosition(NewPos);
            PosInfo.x += this.Content[i].size.width;
        }
    }

}
ParaRun.prototype.Math_Draw = function(x, y, pGraphics)
{
    var X = x;
    var Y = y + this.size.ascent;

    var oWPrp = this.Get_CompiledPr(false);
    var Bold = oWPrp.Bold,
        Italic = oWPrp.Italic;

    var FontFamily = oWPrp.FontFamily,
        FontSize   = oWPrp.FontSize,
        FontSizeCS = oWPrp.FontSizeCS,
        RFonts     = oWPrp.RFonts.Copy();

    this.Parent.ParaMath.ApplyArgSize_2(oWPrp, this.Parent.Compiled_ArgSz.value);

    if(!this.IsNormalText()) // выставляем false, чтобы не применился наклон к спец символам
    {
        oWPrp.Italic = false;
        oWPrp.Bold   = false;

        // TO DO
        // реализовать получше
        // пока так

        var defaultTxtPrp = this.Parent.ParaMath.Get_Default_TPrp();

        oWPrp.FontFamily = defaultTxtPrp.FontFamily;
        oWPrp.RFonts.Set_All(defaultTxtPrp.FontFamily.Name, defaultTxtPrp.FontFamily.Index);
    }

    pGraphics.SetFont(oWPrp);
    pGraphics.b_color1(0,0,0,255);

    for(var i=0; i < this.Content.length;i++)
        this.Content[i].draw(X, Y, pGraphics);

    oWPrp.RFonts     = RFonts;
    oWPrp.FontFamily = FontFamily;
    oWPrp.Bold     = Bold;
    oWPrp.Italic   = Italic;
    oWPrp.FontSize = FontSize;
    oWPrp.FontSizeCS = FontSizeCS;

}
ParaRun.prototype.Math_Recalculate = function(oMeasure, Parent, Paragraph, RPI, ArgSize, WidthPoints)
{
    // пересчет элементов контента в Run
    // Recalculate_MeasureContent

    // ParaText (ParagraphContent.js)
    // для настройки TextPr
    // Measure

    // FontClassification.js
    // Get_FontClass

    var RangeStartPos = 0;
    var RangeEndPos = this.Content.length;


    this.Paragraph = Paragraph;
    this.Parent    = Parent;

    // обновляем позиции start и end для Range
    //this.Lines[0].Add_Range(0, RangeStartPos, RangeEndPos);
    this.protected_AddRange(0, 0);
    this.protected_FillRange(0, 0, RangeStartPos, RangeEndPos);


    if(RPI.NeedResize)
    {
        //RPI.UpdateMathPr = this.UpdateMathPr;

        var oWPrp = this.Get_CompiledPr(false);
        var Bold = oWPrp.Bold;
        var Italic = oWPrp.Italic;

        var FontFamily = oWPrp.FontFamily,
            FontSize   = oWPrp.FontSize,
            FontSizeCS = oWPrp.FontSizeCS,
            RFonts     = oWPrp.RFonts.Copy();

        this.Parent.ParaMath.ApplyArgSize_2(oWPrp, this.Parent.Compiled_ArgSz.value);


        if(!this.IsNormalText()) // выставляем false, чтобы не применился наклон к спец символам
        {
            oWPrp.Italic = false;
            oWPrp.Bold   = false;


            var defaultTxtPrp = this.Parent.ParaMath.Get_Default_TPrp();

            oWPrp.FontFamily  = defaultTxtPrp.FontFamily;

            oWPrp.RFonts.Set_All(defaultTxtPrp.FontFamily.Name, defaultTxtPrp.FontFamily.Index);
        }

        g_oTextMeasurer.SetFont(oWPrp);


        this.bEqqArray = RPI.bEqqArray;


        this.size.SetZero();

        var widthCurr = 0,
            ascent = 0, descent = 0;

        var Lng = this.Content.length;


        for (var i = 0 ; i < Lng; i++)
        {
            this.Content[i].Resize(oMeasure, this, RPI);

            var oSize = this.Content[i].size;

            widthCurr = oSize.width;
            this.size.width += widthCurr;

            var oDescent = oSize.height - oSize.ascent;

            ascent = ascent > oSize.ascent ? ascent : oSize.ascent;
            descent = descent < oDescent ? oDescent : descent;

            if(RPI.bEqqArray)
            {
                if(this.Content[i].Type !== para_Math_Ampersand)
                    WidthPoints.UpdatePoint(widthCurr);
                else
                    WidthPoints.AddNewAlignRange();
            }
        }

        this.size.ascent = ascent;
        this.size.height = ascent + descent;


        oWPrp.RFonts     = RFonts;
        oWPrp.FontFamily = FontFamily;
        oWPrp.Bold       = Bold;
        oWPrp.Italic     = Italic;
        oWPrp.FontSize   = FontSize;
        oWPrp.FontSizeCS = FontSizeCS;


        //this.UpdateMathPr = false;
    }
}
ParaRun.prototype.Math_Update_Cursor = function(X, Y, CurPage, UpdateTarget)
{
    // TODO
    // поставить заглушку на плейсхолдер, когда при перемещении всегда будет отрисовываться селект на плейсхолдере
    var runPrp = this.Get_CompiledPr(false);
    //this.Parent.ParaMath.ApplyArgSize(runPrp, this.Parent.argSize);

    var sizeCursor = runPrp.FontSize*g_dKoef_pt_to_mm;

    Y -= sizeCursor*0.8;

    for(var i = 0; i < this.State.ContentPos; i++)
        X += this.Content[i].size.width;


    if ( null !== this.Paragraph && undefined !== this.Paragraph && UpdateTarget == true)
    {
        this.Paragraph.DrawingDocument.SetTargetSize(sizeCursor);
        //Para.DrawingDocument.UpdateTargetFromPaint = true;
        this.Paragraph.DrawingDocument.UpdateTarget(X, Y, this.Paragraph.Get_StartPage_Absolute() + CurPage );
        //Para.DrawingDocument.UpdateTargetFromPaint = false;
    }

    return {X: X, Y: Y, Height: sizeCursor};
}
ParaRun.prototype.Math_Apply_Style = function(Value)
{
    if(Value !== this.MathPrp.sty)
    {
        var OldValue     = this.MathPrp.sty;
        this.MathPrp.sty = Value;

        History.Add( this, { Type : historyitem_ParaRun_MathStyle, New : Value, Old : OldValue } );

        this.Recalc_CompiledPr(true);
    }
}
ParaRun.prototype.IsNormalText = function()
{
    var comp_MPrp = this.MathPrp.GetCompiled_ScrStyles();
    return (comp_MPrp.nor === true);
}
ParaRun.prototype.getPropsForWrite = function()
{
    var wRPrp = this.Pr.Copy(),
        mathRPrp = this.MathPrp.getPropsForWrite();

    return {wRPrp: wRPrp, mathRPrp: mathRPrp};
}
ParaRun.prototype.Math_SetGaps = function(GapsInfo)
{
    this.Parent = GapsInfo.Parent;
    this.Paragraph = GapsInfo.ParaMath.Paragraph;

    var oWPrp = this.Get_CompiledPr(false);

    for (var Pos = 0 ; Pos < this.Content.length; Pos++ )
    {
        if( !this.Content[Pos].IsAlignPoint() )
        {
            GapsInfo.leftRunPrp = GapsInfo.currRunPrp;
            GapsInfo.Left       = GapsInfo.Current;

            GapsInfo.currRunPrp = oWPrp;
            GapsInfo.Current = this.Content[Pos];
            GapsInfo.setGaps();
        }
    }
}
ParaRun.prototype.IsPlaceholder = function()
{
    return this.Content.length == 1 && this.Content[0].IsPlaceholder();
}
ParaRun.prototype.fillPlaceholders = function()
{
    var placeholder = new CMathText(false);
    placeholder.fillPlaceholders();

    this.Add_ToContent(0, placeholder, false);
}
ParaRun.prototype.Math_Correct_Content = function()
{
    for(var i = 0; i < this.Content.length; i++)
    {
        if(this.Content[i].Type == para_Math_Placeholder)
            this.Remove_FromContent(i, 1, true);
    }
}
ParaRun.prototype.Set_MathPr = function(MPrp)
{
    var OldValue = this.MathPrp;
    this.MathPrp = MPrp;

    History.Add( this, { Type : historyitem_ParaRun_MathPrp, New : MPrp, Old : OldValue } );
    this.Recalc_CompiledPr(true);

    //this.UpdateMathPr = true;
}
ParaRun.prototype.IsAccent = function()
{
    return this.Parent.IsAccent();
}
ParaRun.prototype.GetCompiled_ScrStyles = function()
{
    return this.MathPrp.GetCompiled_ScrStyles();
}
ParaRun.prototype.IsEqqArray = function()
{
    return this.Parent.IsEqqArray();
}
ParaRun.prototype.Math_GetInfoLetter = function(Info)
{
    if(this.Content.length == 1)
    {
        var Compiled_MPrp = this.MathPrp.GetCompiled_ScrStyles();
        Info.sty = Compiled_MPrp.sty;
        Info.scr = Compiled_MPrp.scr;
        this.Content[0].getInfoLetter(Info);
    }
    else
        Info.Result = false;
}

function CParaRunStartState(Run)
{
    this.Paragraph = Run.Paragraph;
    this.Pr = Run.Pr.Copy();
    this.Content = [];
    for(var i = 0; i < Run.Content.length; ++i)
    {
        this.Content.push(Run.Content[i]);
    }
}