Esempio n. 1
0
        private void WriteUIContainerChild(DocumentNode documentNode)
        {
            _rtfBuilder.Append("{");
 
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
 
            // Write child contents 
            int nStart = documentNode.Index + 1;
            int nEnd = documentNode.Index + documentNode.ChildCount; 

            for (; nStart <= nEnd; nStart++)
            {
                DocumentNode documentNodeChild = dna.EntryAt(nStart); 

                // Ignore non-direct children - they get written out by their parent 
                if (documentNodeChild.Parent == documentNode && documentNodeChild.Type == DocumentNodeType.dnImage) 
                {
                    // Write image control and image hex data to the rtf content 
                    WriteImage(documentNodeChild);
                }
            }
 
            if (documentNode.Type == DocumentNodeType.dnBlockUIContainer)
            { 
                _rtfBuilder.Append("\\par"); 
            }
 
            // Close Section writing
            _rtfBuilder.Append("}");
            _rtfBuilder.Append("\r\n");
        } 
        private void ConvertSymbolCharValueToText(DocumentNode dn, int nChar, EncodeType encodeType)
        {
            switch (encodeType)
            {
                case EncodeType.Unicode:
                    if (nChar < 0xFFFF)
                    {
                        char[] unicodeChar = new char[1];

                        unicodeChar[0] = (char)nChar;
                        dn.AppendXamlEncoded(new string(unicodeChar));
                    }
                    break;

                case EncodeType.ShiftJis:
                    if (nChar < 0xFFFF)
                    {
                        // NB: How to interpret this numeric value as Shift-JIS?
                        Encoding ec = Encoding.GetEncoding(932);
                        int nChars = nChar > 256 ? 2 : 1;
                        byte[] ba = new byte[2];
                        if (nChars == 1)
                        {
                            ba[0] = (byte)nChar;
                        }
                        else
                        {
                            ba[0] = (byte)((nChar >> 8) & 0xFF);
                            ba[1] = (byte)(nChar & 0xFF);
                        }
                        dn.AppendXamlEncoded(ec.GetString(ba, 0, nChars));
                    }
                    break;

                default:
                    if (nChar < 256)
                    {
                        // Keep the byte char value as the unicode
                        char singleChar = (char) nChar;
                        dn.AppendXamlEncoded(new string(singleChar, 1));
                    }
                    break;
            }
        }
        internal void HandleParagraphFromText(FormatState formatState)
        {
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
            DocumentNode dn;

            // Insert the paragraph before any text or inline nodes at the top of the stack.
            int nInsertAt = dna.Count;    // Default insertion location
            for (; nInsertAt > 0; nInsertAt--)
            {
                dn = dna.EntryAt(nInsertAt - 1);
                if (!dn.IsInline
                    || (dn.ClosedParent != null && !dn.ClosedParent.IsInline)
                    || !dn.IsMatched)
                {
                    break;
                }
            }

            dn = new DocumentNode(DocumentNodeType.dnParagraph);
            dn.FormatState = new FormatState(formatState);
            dn.ConstrainFontPropagation(formatState);
            dna.InsertNode(nInsertAt, dn);

            // Now close immediately.
            dna.CloseAt(nInsertAt);
            dna.CoalesceOnlyChildren(_converterState, nInsertAt);
        }
        internal DocumentNode ProcessHyperlinkField(string instr)
        {
            DocumentNode dn = new DocumentNode(DocumentNodeType.dnHyperlink);
            dn.FormatState = new FormatState(_converterState.PreviousTopFormatState(0));
            string sUri = null;
            string sTarget = null;
            string sBookmark = null;

            bool bTargetNext = false;
            bool bBookmarkNext = false;

            // iterate, starting past " HYPERLINK"
            int i = 10;
            while (i < instr.Length)
            {
                // Skip spaces
                if (instr[i] == ' ')
                {
                    i++;
                }

                // NavigateUri?
                else if (instr[i] == '"')
                {
                    i++;
                    if (i < instr.Length)
                    {
                        int iStart = i;
                        int iEnd = i;

                        for (; iEnd < instr.Length; iEnd++)
                        {
                            if (instr[iEnd] == '"')
                            {
                                break;
                            }
                        }

                        string param = instr.Substring(iStart, iEnd - iStart);
                        if (bTargetNext)
                        {
                            sTarget = param;
                            bTargetNext = false;
                        }
                        else if (bBookmarkNext)
                        {
                            sBookmark = param;
                            bBookmarkNext = false;
                        }
                        else if (sUri == null)
                            sUri = param;
                        // else eat the string

                        i = iEnd + 1;
                    }
                }

                // Instructions
                else if (instr[i] == '\\')
                {
                    i++;
                    if (i < instr.Length)
                    {
                        switch (instr[i])
                        {
                            case 'l':   // bookmark
                                bBookmarkNext = true; bTargetNext = false;
                                break;
                            case 't':   // target
                                bBookmarkNext = false; bTargetNext = true;
                                break;
                        }
                        i++;
                    }
                }

                // Ignore other characters
                else
                    i++;
            }

            StringBuilder sb = new StringBuilder();
            if (sUri != null)
            {
                sb.Append(sUri);
            }
            if (sBookmark != null)
            {
                sb.Append("#");
                sb.Append(sBookmark);
            }

            // Remove the second backslash(which rtf specified) to keep only single backslash
            for (int uriIndex = 0; uriIndex < sb.Length; uriIndex++)
            {
                if (sb[uriIndex] == '\\' && uriIndex + 1 < sb.Length && sb[uriIndex + 1] == '\\')
                {
                    // Remove the sceond backslash
                    sb.Remove(uriIndex + 1, 1);
                }
            }

            dn.NavigateUri = sb.ToString();

            return dn.NavigateUri.Length > 0 ? dn : null;
        }
        private void ProcessSymbolFieldInstruction(DocumentNode dn, string instr, ref int i, ref EncodeType encodeType)
        {
            int iStart = 0;

            switch (instr[i++])
            {
                case 'a':
                    encodeType = EncodeType.Ansi;
                    break;
                case 'u':
                    encodeType = EncodeType.Unicode;
                    break;
                case 'j':
                    encodeType = EncodeType.ShiftJis;
                    break;
                case 'h':
                    // linespacing instruction: ignore
                    break;
                case 's':
                    if (i < instr.Length && instr[i] == ' ')
                        i++;
                    // font size in points, not half-points
                    iStart = i;
                    for (; i < instr.Length && instr[i] != ' '; i++)
                    {
                        continue;
                    }
                    string ptString = instr.Substring(iStart, i - iStart);

                    // Now convert number part
                    bool ret = true;
                    double d = 0f;

                    try
                    {
                        d = System.Convert.ToDouble(ptString, CultureInfo.InvariantCulture);
                    }
                    catch (System.OverflowException)
                    {
                        ret = false;
                    }
                    catch (System.FormatException)
                    {
                        ret = false;
                    }

                    if (ret)
                    {
                        dn.FormatState.FontSize = (long)((d * 2) + 0.5);
                    }
                    break;
                case 'f':
                    // Font Name
                    if (i < instr.Length && instr[i] == ' ')
                    {
                        i++;
                    }
                    if (i < instr.Length && instr[i] == '"')
                    {
                        i++;
                    }
                    iStart = i;
                    for (; i < instr.Length && instr[i] != '"'; i++)
                    {
                        continue;
                    }
                    string name = instr.Substring(iStart, i - iStart);
                    // Move past trailing double-quote
                    i++;
                    if (name != null && name.Length > 0)
                    {
                        dn.FormatState.Font = _converterState.FontTable.DefineEntryByName(name);
                    }
                    break;
            }
        }
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------

        #region Private Methods

        // <Summary>
        //      The PreCoalesce process for a ListItem involves seeing if I can migrate the left indent
        //      from contained paragraphs to the ListItem itself.  This results in better bullet placement
        //      in the generated XAML.
        // </Summary>

        private void PreCoalesceListItem(DocumentNode dn)
        {
            int nAt = dn.Index;
            long nMargin = -1;
            int nEndItem = nAt + dn.ChildCount;

            for (int nnAt = nAt + 1; nnAt <= nEndItem; nnAt++)
            {
                DocumentNode ddn = EntryAt(nnAt);

                if (ddn.Type == DocumentNodeType.dnParagraph)
                {
                    if (nMargin == -1)
                    {
                        nMargin = ddn.NearMargin;
                    }
                    else if (ddn.NearMargin < nMargin && ddn.IsNonEmpty)
                    {
                        nMargin = ddn.NearMargin;
                    }
                }
            }
            dn.NearMargin = nMargin;
            for (int nnAt = nAt; nnAt <= nEndItem; nnAt++)
            {
                DocumentNode ddn = EntryAt(nnAt);

                if (ddn.Type == DocumentNodeType.dnParagraph)
                {
                    ddn.NearMargin = ddn.NearMargin - nMargin;
                }
            }
        }
        // <Summary>
        //      Table column handling.  RTF tables allow each row to be arbitrarily aligned.  XAML (like HTML)
        //      doesn't allow that.  You can achieve that effect in HTML by inserting extra rows with spurious
        //      cells propped to a specific width, but I'm not going to do that.  Instead, I'm going to split
        //      the rows into separate tables when combining some set of rows into a table would force me
        //      to fabricate a column that doesn't contain any defined cell.
        // </Summary>

        private int PreCoalesceTable(DocumentNode dn)
        {
            int nInserted = 0;
            int nAt = dn.Index;
            ColumnStateArray cols = dn.ComputeColumns();

            // OK, now I have a set of columns and information about which row caused the column to
            // be instantiated.  The naive algorithm is to strip the first N rows from the table until
            // the row that caused an uninstantiated column, break the table there, and then run the
            // algorithm again on the trailing table.
            int nUnfilledRowIndex = cols.GetMinUnfilledRowIndex();

            if (nUnfilledRowIndex > 0)
            {
                // OK, Need to insert a new table and table group around the remaining rows.
                DocumentNode dnNewTable = new DocumentNode(DocumentNodeType.dnTable);
                DocumentNode dnNewTableBody = new DocumentNode(DocumentNodeType.dnTableBody);
                dnNewTable.FormatState = new FormatState(dn.FormatState);
                dnNewTable.FormatState.RowFormat = EntryAt(nUnfilledRowIndex).FormatState.RowFormat;
                int nChildrenOldTable = nUnfilledRowIndex - dn.Index - 1;
                int nChildrenNewTable = dn.ChildCount - nChildrenOldTable;
                dn.ChildCount = nChildrenOldTable;  // Update old table child count
                EntryAt(nAt + 1).ChildCount = nChildrenOldTable - 1;    // Update old TableBody child count
                InsertNode(nUnfilledRowIndex, dnNewTableBody);
                CloseAtHelper(nUnfilledRowIndex, nChildrenNewTable);
                InsertNode(nUnfilledRowIndex, dnNewTable);
                CloseAtHelper(nUnfilledRowIndex, nChildrenNewTable + 1);

                // Adjust parent pointers
                dnNewTableBody.Parent = dnNewTable;
                dnNewTable.Parent = dn.ClosedParent;
                for (DocumentNode dnPa = dnNewTable.ClosedParent; dnPa != null; dnPa = dnPa.ClosedParent)
                {
                    dnPa.ChildCount = dnPa.ChildCount + 2;
                }

                // Adjust the loop end to account for the newly inserted elements
                nInserted = 2;

                // Need to recompute the ColumnStateArray for the newly truncated table.
                dn.ColumnStateArray = dn.ComputeColumns();
            }
            else
            {
                dn.ColumnStateArray = cols;
            }

            return nInserted;
        }
        internal void HandleTableNesting(FormatState formatState)
        {
            DocumentNodeArray dna = _converterState.DocumentNodeArray;

            // If we're in a throw-away destination, just return.
            if (!formatState.IsContentDestination || formatState.IsHidden)
            {
                return;
            }

            // Make sure proper number of tables are open to reflect this paragraphs nest level
            int nTables = dna.CountOpenNodes(DocumentNodeType.dnTable);
            int nLevel = (int)formatState.TableLevel;

            // If we're not in a table, end early
            if (nTables == nLevel && nTables == 0)
            {
                return;
            }

            if (nTables > nLevel)
            {
                DocumentNode dnPara = dna.Pop();

                bool bInField = dna.FindUnmatched(DocumentNodeType.dnFieldBegin) >= 0;
                while (nTables > nLevel)
                {

                    int nOpen = dna.FindPending(DocumentNodeType.dnTable);
                    if (nOpen >= 0)
                    {
                        dna.CloseAt(nOpen);
                        if (!bInField)
                        {
                            dna.CoalesceChildren(_converterState, nOpen);
                        }
                    }
                    nTables--;
                }
                dna.Push(dnPara);
            }
            else
            {
                // Before opening the table, let's close any open lists.  Word (RTF) allows somewhat
                // arbitrary interleaving (because there's no explicit nesting), but when converting to
                // XAML we have to choose an explicit nesting.  We never create a table *inside* a list, so
                // let's just terminate any open lists right now.
                if (nTables < nLevel)
                {
                    int nListAt = dna.FindPending(DocumentNodeType.dnList);
                    if (nListAt >= 0)
                    {
                        // I want the currently pending paragraph to be part of the table, not part of the list
                        // I'm going to close.  So I temporarily pop it off while closing off the list and then
                        // push it back on before inserting the table(s).
                        DocumentNode dnPara = dna.Pop();

                        while (nListAt >= 0)
                        {
                            dna.CloseAt(nListAt);
                            nListAt = dna.FindPending(DocumentNodeType.dnList);
                        }

                        dna.Push(dnPara);
                    }
                }

                // Ensure sufficient tables are open - this may be our first indication
                // Insert the table nodes right before the current paragraph.
                Debug.Assert(dna.Count > 0 && dna.EntryAt(dna.Count - 1).Type == DocumentNodeType.dnParagraph);

                int nInsertAt = dna.Count - 1;

                // Ensure row is open
                int nTable = dna.FindPending(DocumentNodeType.dnTable);
                if (nTable >= 0)
                {
                    int nRow = dna.FindPending(DocumentNodeType.dnRow, nTable);
                    if (nRow == -1)
                    {
                        DocumentNode dnRow = new DocumentNode(DocumentNodeType.dnRow);
                        dna.InsertNode(nInsertAt++, dnRow);
                        nRow = nInsertAt - 1;
                    }

                    int nCell = dna.FindPending(DocumentNodeType.dnCell, nRow);
                    if (nCell == -1)
                    {
                        DocumentNode dnCell = new DocumentNode(DocumentNodeType.dnCell);
                        dna.InsertNode(nInsertAt, dnCell);
                    }
                }

                nInsertAt = dna.Count - 1;
                while (nTables < nLevel)
                {
                    DocumentNode dnTable = new DocumentNode(DocumentNodeType.dnTable);
                    DocumentNode dnTableBody = new DocumentNode(DocumentNodeType.dnTableBody);
                    DocumentNode dnRow = new DocumentNode(DocumentNodeType.dnRow);
                    DocumentNode dnCell = new DocumentNode(DocumentNodeType.dnCell);

                    dna.InsertNode(nInsertAt, dnCell);
                    dna.InsertNode(nInsertAt, dnRow);
                    dna.InsertNode(nInsertAt, dnTableBody);
                    dna.InsertNode(nInsertAt, dnTable);

                    nTables++;
                }
            }

            dna.AssertTreeSemanticInvariants();
        }
        internal void HandleNormalTextRaw(string text, FormatState formatState)
        {
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
            DocumentNode dnTop = dna.Top;

            // See if I can just append the text content if the format is the same.
            if (dnTop != null && (dnTop.Type == DocumentNodeType.dnText))
            {
                // If the format is not equal, close this text element and we'll open a new one.
                if (!dnTop.FormatState.IsEqual(formatState))
                {
                    dna.CloseAt(dna.Count - 1);
                    dnTop = null;
                }
            }

            // OK, create a text node if necessary
            if (dnTop == null || dnTop.Type != DocumentNodeType.dnText)
            {
                dnTop = new DocumentNode(DocumentNodeType.dnText);
                dnTop.FormatState = new FormatState(formatState);
                dna.Push(dnTop);
            }

            Debug.Assert(!dnTop.IsTerminated);
            dnTop.AppendXamlEncoded(text);
            dnTop.IsPending = false;
        }
        internal void HandleOldListTokens(RtfToken token, FormatState formatState)
        {
            FormatState fsCur = _converterState.PreviousTopFormatState(0);
            FormatState fsOld = _converterState.PreviousTopFormatState(1);
            if (fsCur == null || fsOld == null)
            {
                return;
            }

            // If we're in the PN destination, we push marker setting into the previous format state.
            if (formatState.RtfDestination == RtfDestination.DestPN)
            {
                formatState = fsOld;
            }

            switch (token.RtfControlWordInfo.Control)
            {
                case RtfControlWord.Ctrl_PNLVL:
                    formatState.PNLVL = token.Parameter;
                    break;
                case RtfControlWord.Ctrl_PNLVLBLT:
                    formatState.Marker = MarkerStyle.MarkerBullet;
                    formatState.IsContinue = false;
                    break;
                case RtfControlWord.Ctrl_PNLVLBODY:
                    formatState.Marker = MarkerStyle.MarkerArabic;
                    formatState.IsContinue = false;
                    break;
                case RtfControlWord.Ctrl_PNLVLCONT:
                    formatState.IsContinue = true;
                    break;
                case RtfControlWord.Ctrl_PNCARD:
                    formatState.Marker = MarkerStyle.MarkerCardinal;
                    break;
                case RtfControlWord.Ctrl_PNDEC:
                    formatState.Marker = MarkerStyle.MarkerArabic;
                    break;
                case RtfControlWord.Ctrl_PNUCLTR:
                    formatState.Marker = MarkerStyle.MarkerUpperAlpha;
                    break;
                case RtfControlWord.Ctrl_PNUCRM:
                    formatState.Marker = MarkerStyle.MarkerUpperRoman;
                    break;
                case RtfControlWord.Ctrl_PNLCLTR:
                    formatState.Marker = MarkerStyle.MarkerLowerAlpha;
                    break;
                case RtfControlWord.Ctrl_PNLCRM:
                    formatState.Marker = MarkerStyle.MarkerLowerRoman;
                    break;
                case RtfControlWord.Ctrl_PNORD:
                    formatState.Marker = MarkerStyle.MarkerOrdinal;
                    break;
                case RtfControlWord.Ctrl_PNORDT:
                    formatState.Marker = MarkerStyle.MarkerOrdinal;
                    break;
                case RtfControlWord.Ctrl_PNBIDIA:
                    formatState.Marker = MarkerStyle.MarkerArabic;
                    break;
                case RtfControlWord.Ctrl_PNBIDIB:
                    formatState.Marker = MarkerStyle.MarkerArabic;
                    break;
                case RtfControlWord.Ctrl_PN:
                    formatState.RtfDestination = RtfDestination.DestPN;
                    fsOld.Marker = MarkerStyle.MarkerBullet;
                    break;
                case RtfControlWord.Ctrl_PNTXTA:
                    // Leave with unknown destination so text is tossed.
                    break;
                case RtfControlWord.Ctrl_PNTXTB:
                    // Leave with unknown destination so text is tossed.
                    break;
                case RtfControlWord.Ctrl_PNTEXT:
                    if (fsOld.IsContentDestination || formatState.IsHidden)
                    {
                        fsCur.RtfDestination = RtfDestination.DestListText;
                        DocumentNodeArray dna = _converterState.DocumentNodeArray;
                        DocumentNode dnl = new DocumentNode(DocumentNodeType.dnListText);

                        dnl.FormatState = new FormatState(formatState);
                        dna.Push(dnl);
                    }
                    break;
                case RtfControlWord.Ctrl_PNSTART:
                    formatState.StartIndex = token.Parameter;
                    break;

                default:
                    formatState.Marker = MarkerStyle.MarkerBullet;
                    break;
            }
        }
        internal void HandleFieldTokens(RtfToken token, FormatState formatState)
        {
            // Don't start processing fields in non-normal destinatations
            FormatState fsCur = _converterState.PreviousTopFormatState(0);
            FormatState fsOld = _converterState.PreviousTopFormatState(1);
            if (fsCur == null || fsOld == null)
            {
                return;
            }

            switch (token.RtfControlWordInfo.Control)
            {
                case RtfControlWord.Ctrl_FIELD:
                    // Process fields in normal content or nested fields
                    if (!fsOld.IsContentDestination || formatState.IsHidden)
                    {
                        return;
                    }
                    formatState.RtfDestination = RtfDestination.DestField;
                    break;
                case RtfControlWord.Ctrl_FLDRSLT:
                    if (fsOld.RtfDestination != RtfDestination.DestField)
                    {
                        return;
                    }
                    formatState.RtfDestination = RtfDestination.DestFieldResult;
                    break;
                case RtfControlWord.Ctrl_FLDPRIV:
                    if (fsOld.RtfDestination != RtfDestination.DestField)
                    {
                        return;
                    }
                    formatState.RtfDestination = RtfDestination.DestFieldPrivate;
                    break;
                case RtfControlWord.Ctrl_FLDINST:
                    if (fsOld.RtfDestination != RtfDestination.DestField)
                    {
                        return;
                    }
                    formatState.RtfDestination = RtfDestination.DestFieldInstruction;
                    break;
                default:
                    return;
            }

            DocumentNodeArray dna = _converterState.DocumentNodeArray;
            DocumentNode dnf = new DocumentNode(DocumentNodeType.dnFieldBegin);

            dnf.FormatState = new FormatState(formatState);
            dnf.IsPending = false;  // Field start mark should not impact other tags open/close behavior
            dnf.IsTerminated = true;
            dna.Push(dnf);
        }
        internal void HandleShapeTokens(RtfToken token, FormatState formatState)
        {
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
            FormatState fsCur = _converterState.PreviousTopFormatState(0);
            FormatState fsOld = _converterState.PreviousTopFormatState(1);
            if (fsCur == null || fsOld == null)
            {
                return;
            }

            switch (token.RtfControlWordInfo.Control)
            {
                case RtfControlWord.Ctrl_DO:
                    // Just propagate destination through this keyword.
                    fsCur.RtfDestination = fsOld.RtfDestination;
                    break;
                case RtfControlWord.Ctrl_SHPRSLT:
                    if (fsOld.IsContentDestination)
                    {
                        fsCur.RtfDestination = RtfDestination.DestShape;
                    }
                    break;
                case RtfControlWord.Ctrl_DPTXBXTEXT:
                    if (fsOld.IsContentDestination)
                    {
                        // Track the destination so I can recognize when we leave this scope.
                        fsCur.RtfDestination = RtfDestination.DestShapeResult;

                        // Wrap any inline content that occurs before this shape anchor in a paragraph,
                        // since the shape content itself will be block level.
                        WrapPendingInlineInParagraph(token, formatState);

                        DocumentNodeType t = dna.GetTableScope();
                        if (t != DocumentNodeType.dnParagraph)
                        {
                            if (t == DocumentNodeType.dnTableBody)
                            {
                                // If row has been closed, close overall table as well.
                                int nAt = dna.FindPending(DocumentNodeType.dnTable);
                                if (nAt >= 0)
                                {
                                    dna.CloseAt(nAt);
                                    dna.CoalesceChildren(_converterState, nAt);
                                }
                            }
                            else
                            {
                                // If I'm inside a table, reopen last cell to insert shape contents.  Otherwise
                                // table gets torqued.
                                dna.OpenLastCell();
                            }
                        }

                        // The shape node generates no output but plays a large role in changing the
                        // behavior of the "FindPending" routines to keep from looking outside this scope.
                        DocumentNode dn = new DocumentNode(DocumentNodeType.dnShape);
                        formatState.SetParaDefaults();
                        formatState.SetCharDefaults();
                        dn.FormatState = new FormatState(formatState);
                        dna.Push(dn);
                    }
                    break;
                case RtfControlWord.Ctrl_SHPPICT:
                    // If this occurs in listtext context, mark listtext as non-empty.
                    int ndnListText = dna.FindPending(DocumentNodeType.dnListText);
                    if (ndnListText >= 0)
                    {
                        DocumentNode dnListText = dna.EntryAt(ndnListText);

                        dnListText.HasMarkerContent = true;
                    }

                    // Keep the rtf destination as the list picture to skip the list picture
                    if (fsOld.RtfDestination == RtfDestination.DestListPicture)
                    {
                        formatState.RtfDestination = RtfDestination.DestListPicture;
                    }
                    else
                    {
                        formatState.RtfDestination = RtfDestination.DestShapePicture;
                    }

                    break;
                case RtfControlWord.Ctrl_NONSHPPICT:
                    formatState.RtfDestination = RtfDestination.DestNoneShapePicture;
                    break;
            }
        }
        internal void HandleListTokens(RtfToken token, FormatState formatState)
        {
            ListTable listTable = _converterState.ListTable;
            ListOverrideTable listOverrideTable = _converterState.ListOverrideTable;

            FormatState fsCur = _converterState.PreviousTopFormatState(0);
            FormatState fsOld = _converterState.PreviousTopFormatState(1);
            if (fsCur == null || fsOld == null)
            {
                return;
            }

            switch (token.RtfControlWordInfo.Control)
            {
                case RtfControlWord.Ctrl_LIST:
                    if (formatState.RtfDestination == RtfDestination.DestListTable)
                    {
                        ListTableEntry listTableEntry = listTable.AddEntry();
                    }
                    break;

                case RtfControlWord.Ctrl_LISTTEMPLATEID:
                    {
                        ListTableEntry listTableEntry = listTable.CurrentEntry;
                        if (listTableEntry != null)
                        {
                            listTableEntry.TemplateID = token.Parameter;
                        }
                    }
                    break;

                case RtfControlWord.Ctrl_LISTHYBRID:
                case RtfControlWord.Ctrl_LISTSIMPLE:
                    {
                        ListTableEntry listTableEntry = listTable.CurrentEntry;
                        if (listTableEntry != null)
                        {
                            listTableEntry.Simple = token.RtfControlWordInfo.Control == RtfControlWord.Ctrl_LISTSIMPLE;
                        }
                    }
                    break;

                case RtfControlWord.Ctrl_LISTLEVEL:
                    {
                        formatState.RtfDestination = RtfDestination.DestListLevel;
                        ListLevelTable levels = GetControllingLevelTable();
                        if (levels != null)
                        {
                            ListLevel listLevel = levels.AddEntry();
                        }
                    }
                    break;

                case RtfControlWord.Ctrl_LISTTEXT:
                    if (fsOld.IsContentDestination || formatState.IsHidden)
                    {
                        formatState.RtfDestination = RtfDestination.DestListText;
                        DocumentNodeArray dna = _converterState.DocumentNodeArray;
                        DocumentNode dnl = new DocumentNode(DocumentNodeType.dnListText);

                        dnl.FormatState = new FormatState(formatState);
                        dna.Push(dnl);
                    }
                    break;

                case RtfControlWord.Ctrl_LEVELNFC:
                case RtfControlWord.Ctrl_LEVELNFCN:
                    {
                        ListLevelTable levels = GetControllingLevelTable();
                        if (levels != null)
                        {
                            ListLevel listLevel = levels.CurrentEntry;
                            if (listLevel != null)
                            {
                                listLevel.Marker = (MarkerStyle)token.Parameter;
                            }
                        }
                    }
                    break;
                case RtfControlWord.Ctrl_LEVELJC:
                case RtfControlWord.Ctrl_LEVELJCN:
                    // NB: Marker alignment not supported in XAML.
                    break;

                case RtfControlWord.Ctrl_LEVELFOLLOW:
                    break;

                case RtfControlWord.Ctrl_LEVELSTARTAT:
                    {
                        ListLevelTable levels = GetControllingLevelTable();
                        if (levels != null)
                        {
                            ListLevel listLevel = levels.CurrentEntry;
                            if (listLevel != null)
                            {
                                listLevel.StartIndex = token.Parameter;
                            }
                            else
                            {
                                // This is the case where the list override *only* specifies startat override.
                                ListOverride lo = GetControllingListOverride();

                                if (lo != null)
                                {
                                    lo.StartIndex = token.Parameter;
                                }
                            }
                        }
                    }
                    break;

                case RtfControlWord.Ctrl_LEVELSPACE:
                    break;
                case RtfControlWord.Ctrl_LEVELINDENT:
                    break;
                case RtfControlWord.Ctrl_LEVELTEXT:
                    break;
                case RtfControlWord.Ctrl_LEVELTEMPLATEID:
                    break;

                case RtfControlWord.Ctrl_LISTID:
                    {
                        if (formatState.RtfDestination == RtfDestination.DestListOverride)
                        {
                            ListOverride listOverride = listOverrideTable.CurrentEntry;
                            if (listOverride != null)
                            {
                                listOverride.ID = token.Parameter;
                            }
                        }
                        else
                        {
                            ListTableEntry listTableEntry = listTable.CurrentEntry;
                            if (listTableEntry != null)
                            {
                                listTableEntry.ID = token.Parameter;
                            }
                        }
                    }
                    break;

                case RtfControlWord.Ctrl_LEVELNUMBERS:
                    break;

                case RtfControlWord.Ctrl_LISTOVERRIDE:
                    {
                        FormatState previousFormatState = _converterState.PreviousTopFormatState(1);

                        if (previousFormatState.RtfDestination == RtfDestination.DestListOverrideTable)
                        {
                            formatState.RtfDestination = RtfDestination.DestListOverride;

                            ListOverride listOverride = listOverrideTable.AddEntry();
                        }
                    }
                    break;

                case RtfControlWord.Ctrl_LS:
                    if (formatState.RtfDestination == RtfDestination.DestListOverride)
                    {
                        ListOverride listOverride = listOverrideTable.CurrentEntry;
                        if (listOverride != null)
                        {
                            listOverride.Index = token.Parameter;
                        }

                    }
                    break;
            }
        }
Esempio n. 14
0
        private void WriteSection(DocumentNode dnThis) 
        { 
            int nStart = dnThis.Index + 1;
            int nEnd = dnThis.Index + dnThis.ChildCount; 
            int nAt;

            FormatState fsThis = dnThis.FormatState;
            FormatState fsParent = dnThis.Parent != null ? dnThis.Parent.FormatState : FormatState.EmptyFormatState; 
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
 
            _rtfBuilder.Append("{"); 

            // CultureInfo 
            if (fsThis.Lang != fsParent.Lang && fsThis.Lang > 0)
            {
                _rtfBuilder.Append("\\lang");
                _rtfBuilder.Append(fsThis.Lang.ToString(CultureInfo.InvariantCulture)); 
            }
 
            // FlowDirection 
            if (fsThis.DirPara == DirState.DirRTL)
            { 
                _rtfBuilder.Append("\\rtlpar");
            }

            // Write the font information 
            if (WriteParagraphFontInfo(dnThis, fsThis, fsParent))
            { 
                _rtfBuilder.Append(" "); 
            }
 
            // Foreground
            if (fsThis.CF != fsParent.CF)
            {
                _rtfBuilder.Append("\\cf"); 
                _rtfBuilder.Append(fsThis.CF.ToString(CultureInfo.InvariantCulture));
            } 
 
            // TextAlignment
            switch (fsThis.HAlign) 
            {
                case HAlign.AlignLeft:
                    if (fsThis.DirPara != DirState.DirRTL)
                    { 
                        _rtfBuilder.Append("\\ql");
                    } 
                    else 
                    {
                        _rtfBuilder.Append("\\qr"); 
                    }
                    break;

                case HAlign.AlignRight: 
                    if (fsThis.DirPara != DirState.DirRTL)
                    { 
                        _rtfBuilder.Append("\\qr"); 
                    }
                    else 
                    {
                        _rtfBuilder.Append("\\ql");
                    }
                    break; 

                case HAlign.AlignCenter: 
                    _rtfBuilder.Append("\\qc"); 
                    break;
 
                case HAlign.AlignJustify:
                    _rtfBuilder.Append("\\qj");
                    break;
            } 

            // LineHeight 
            if (fsThis.SL != 0) 
            {
                _rtfBuilder.Append("\\sl"); 
                _rtfBuilder.Append(fsThis.SL.ToString(CultureInfo.InvariantCulture));
                _rtfBuilder.Append("\\slmult0");
            }
 
            // Now write out the direct children.
            for (nAt = nStart; nAt <= nEnd; nAt++) 
            { 
                DocumentNode dnChild = dna.EntryAt(nAt);
 
                // Ignore non-direct children - they get written out by their parent
                if (dnChild.Parent == dnThis)
                {
                    WriteStructure(dnChild); 
                }
            } 
 
            // Close Section writing
            _rtfBuilder.Append("}"); 
            _rtfBuilder.Append("\r\n");
        }
        internal void InsertNode(int nAt, DocumentNode dn)
        {
            Insert(nAt, dn);

            // Match sure Index values remain up-to-date.
            if (_fMain)
            {
                dn.Index = nAt;
                dn.DNA = this;
                for (nAt++; nAt < Count; nAt++)
                {
                    EntryAt(nAt).Index = nAt;
                }

                // Track open nodes
                if (dn.IsTrackedAsOpen)
                {
                    if (_dnaOpen == null)
                    {
                        _dnaOpen = new DocumentNodeArray();
                    }
                    _dnaOpen.InsertOpenNode(dn);
                }
            }
        }
        internal void ProcessNormalHardLine(FormatState formatState)
        {
            // Close out pending text nodes
            DocumentNodeArray dna = _converterState.DocumentNodeArray;

            if (dna.TestTop(DocumentNodeType.dnText))
            {
                dna.CloseAt(dna.Count - 1);
            }

            DocumentNode documentNode = new DocumentNode(DocumentNodeType.dnLineBreak);
            documentNode.FormatState = new FormatState(formatState);
            dna.Push(documentNode);
            dna.CloseAt(dna.Count - 1);
            dna.CoalesceChildren(_converterState, dna.Count - 1);
        }
        internal void InsertChildAt(DocumentNode dnParent, DocumentNode dnNew, int nInsertAt, int nChild)
        {
            Debug.Assert(_fMain);

            InsertNode(nInsertAt, dnNew);
            CloseAtHelper(nInsertAt, nChild);

            // Parent's parent shouldn't be the child document node
            if (dnParent != null && dnParent.Parent == dnNew)
            {
                Invariant.Assert(false, "Parent's Parent node shouldn't be the child node!");
            }

            // Patch the child count of the ancestors
            dnNew.Parent = dnParent;
            for (; dnParent != null; dnParent = dnParent.ClosedParent)
            {
                dnParent.ChildCount += 1;
            }

            AssertTreeInvariants();
        }
        private void EnsureListAndListItem(FormatState formatState, DocumentNodeArray dna, MarkerList mlHave, MarkerList mlWant, int nMatch)
        {
            int nInsertAt;

            bool added = false;

            int nLists = mlHave.Count;
            int nLevel = mlWant.Count;

            // Close any open lists that don't match the ones we want.
            bool bInField = dna.FindUnmatched(DocumentNodeType.dnFieldBegin) >= 0;
            if (nLists > nMatch)
            {
                DocumentNode documentNodePara = dna.Pop();
                while (nLists > nMatch)
                {
                    int nOpen = dna.FindPending(DocumentNodeType.dnList);
                    if (nOpen >= 0)
                    {
                        dna.CloseAt(nOpen);

                        // Only coalesce if this is a top-level list.  Otherwise I want to get
                        // the full structure to use for margin fixups so I delay coalescing.
                        // No, don't coalesce since a later list may need to get merged with this one.
                        // if (!bInField && dna.FindPending(DocumentNodeType.dnList) < 0)
                        //    dna.CoalesceChildren(_converterState, nOpen);
                    }
                    nLists--;
                    mlHave.RemoveRange(mlHave.Count - 1, 1);
                }
                dna.Push(documentNodePara);
            }

            if (nLists < nLevel)
            {
                // Multiple immediately nested lists are handled poorly in Avalon and are usually an indication
                // of bad input from Word (or some other word processor).  Clip the number of lists we'll create here.
                if (nLevel != nLists + 1)
                {
                    // I'm going to truncate, but make the list I create here of the specific type at this level.
                    if (nLevel <= mlWant.Count)
                    {
                        mlWant[nLists] = mlWant[mlWant.Count - 1];
                    }
                    nLevel = nLists + 1;
                }

                // Ensure sufficient lists are open - this may be our first indication
                // Insert the list nodes right before the current paragraph
                nInsertAt = dna.Count - 1;

                while (nLists < nLevel)
                {
                    added = true;

                    DocumentNode dnList = new DocumentNode(DocumentNodeType.dnList);
                    DocumentNode dnLI = new DocumentNode(DocumentNodeType.dnListItem);

                    dna.InsertNode(nInsertAt, dnLI);
                    dna.InsertNode(nInsertAt, dnList);

                    // Set the list properties
                    MarkerListEntry mle = mlWant.EntryAt(nLists);
                    dnList.FormatState.Marker = mle.Marker;
                    dnList.FormatState.StartIndex = mle.StartIndexToUse;
                    dnList.FormatState.StartIndexDefault = mle.StartIndexDefault;
                    dnList.VirtualListLevel = mle.VirtualListLevel;
                    dnList.FormatState.ILS = mle.ILS;
                    nLists++;
                }
            }

            // Ensure listitem is open
            nInsertAt = dna.Count - 1;
            int nList = dna.FindPending(DocumentNodeType.dnList);
            if (nList >= 0)
            {
                int nLI = dna.FindPending(DocumentNodeType.dnListItem, nList);

                if (nLI >= 0 && !added && !formatState.IsContinue)
                {
                    DocumentNode documentNodePara = dna.Pop();
                    dna.CloseAt(nLI);
                    // Don't coalesce - I may need to do margin fixup.
                    // dna.CoalesceChildren(_converterState, nLI);
                    dna.Push(documentNodePara);

                    nLI = -1;
                    nInsertAt = dna.Count - 1;
                }
                if (nLI == -1)
                {
                    DocumentNode dnLI = new DocumentNode(DocumentNodeType.dnListItem);

                    dna.InsertNode(nInsertAt, dnLI);
                }
            }
        }
        // <Summary>
        //      The PreCoalesce process for a List involves promoting the flowdirection if at all possible
        //      from contained paragraphs to the list itself.  This ensures that Avalon displays the list
        //      bullets in the proper location.
        // </Summary>

        private void PreCoalesceList(DocumentNode dn)
        {
            int nAt = dn.Index;
            bool bConflict = false;
            DirState ds = DirState.DirDefault;
            int nEndItem = nAt + dn.ChildCount;
            for (int nnAt = nAt + 1; !bConflict && nnAt <= nEndItem; nnAt++)
            {
                DocumentNode ddn = EntryAt(nnAt);

                if (ddn.Type == DocumentNodeType.dnParagraph && ddn.IsNonEmpty)
                {
                    if (ds == DirState.DirDefault)
                    {
                        ds = ddn.FormatState.DirPara;
                    }
                    else if (ds != ddn.FormatState.DirPara)
                    {
                        bConflict = true;
                    }
                }
            }

            // OK, promote if possible.
            if (!bConflict && ds != DirState.DirDefault)
            {
                for (int nnAt = nAt; nnAt <= nEndItem; nnAt++)
                {
                    DocumentNode ddn = EntryAt(nnAt);

                    if (ddn.Type == DocumentNodeType.dnList || ddn.Type == DocumentNodeType.dnListItem)
                    {
                        ddn.FormatState.DirPara = ds;
                    }
                }
            }
        }
        internal bool IsAncestorOf(DocumentNode documentNode)
        {
            int parentIndex = Index;
            int parentLastChild = Index + ChildCount;

            return documentNode.Index > parentIndex && documentNode.Index <= parentLastChild;
        }
        private void PreCoalesceRow(DocumentNode dn, ref bool fVMerged)
        {
            DocumentNodeArray dnaCells = dn.GetRowsCells();
            RowFormat rf = dn.FormatState.RowFormat;
            DocumentNode dnTable = dn.GetParentOfType(DocumentNodeType.dnTable);
            ColumnStateArray csa = (dnTable != null) ? dnTable.ColumnStateArray : null;

            // Normally number of cells and cell definitions are equal, but be careful.
            int nCount = dnaCells.Count < rf.CellCount ? dnaCells.Count : rf.CellCount;

            // Non-unary colspan can arise both because I have "merged" cells specified
            // as well as because I just have cells that exactly span some other cols.
            // The code in PreCoalesce enforces that the cells line up, so I can just
            // test for that here.

            int nColsSeen = 0;
            int i = 0;
            while (i < nCount)
            {
                DocumentNode dnCell = dnaCells.EntryAt(i);
                CellFormat cf = rf.NthCellFormat(i);
                long cellx = cf.CellX;

                // optimization - record if we encountered a vmerged cell
                if (cf.IsVMerge)
                {
                    fVMerged = true;
                }

                // Determine colspan based on cells we will eliminate through the merge flags
                if (cf.IsHMergeFirst)
                {
                    for (i++; i < nCount; i++)
                    {
                        cf = rf.NthCellFormat(i);
                        if (cf.IsVMerge)
                        {
                            fVMerged = true;
                        }
                        if (cf.IsHMerge)
                        {
                            dnaCells.EntryAt(i).ColSpan = 0;    // zero means omit this cell
                        }
                    }
                }
                else
                {
                    i++;
                }

                // Determine actual colspan based on cellx value
                if (csa != null)
                {
                    int nColStart = nColsSeen;

                    while (nColsSeen < csa.Count)
                    {
                        ColumnState cs = csa.EntryAt(nColsSeen);
                        nColsSeen++;

                        // This is the normal case
                        if (cs.CellX == cellx)
                        {
                            break;
                        }

                        // This is anomalous, but can occur with odd \cellx values (non-monotonically increasing).
                        if (cs.CellX > cellx)
                        {
                            break;
                        }
                    }

                    if (nColsSeen - nColStart > dnCell.ColSpan)
                    {
                        dnCell.ColSpan = nColsSeen - nColStart;
                    }
                }
            }
        }
 internal void Push(DocumentNode documentNode)
 {
     InsertNode(Count, documentNode);
 }
        internal DocumentNode ProcessSymbolField(string instr)
        {
            DocumentNode dn = new DocumentNode(DocumentNodeType.dnText);
            dn.FormatState = new FormatState(_converterState.PreviousTopFormatState(0));

            int nChar = -1;
            EncodeType encodeType = EncodeType.Ansi;

            // iterate, starting past " SYMBOL"
            int i = 7;
            while (i < instr.Length)
            {
                // Skip spaces
                if (instr[i] == ' ')
                {
                    i++;
                }
                // Is this the character code?
                else if (nChar == -1 && instr[i] >= '0' && instr[i] <= '9')
                {
                    // Hex or decimal?
                    if (instr[i] == '0' && i < instr.Length - 1 && instr[i + 1] == 'x')
                    {
                        i += 2;

                        nChar = 0;
                        for (; i < instr.Length && instr[i] != ' ' && instr[i] != '\\'; i++)
                        {
                            if (nChar < 0xFFFF)
                            {
                                nChar = (nChar * 16) + HexToInt(instr[i]);
                            }
                        }
                    }
                    else
                    {
                        nChar = 0;
                        for (; i < instr.Length && instr[i] != ' ' && instr[i] != '\\'; i++)
                        {
                            if (nChar < 0xFFFF)
                            {
                                nChar = (nChar * 10) + DecToInt(instr[i]);
                            }
                        }
                    }
                }
                // Instructions
                else if (instr[i] == '\\')
                {
                    i++;
                    if (i < instr.Length)
                    {
                        ProcessSymbolFieldInstruction(dn, instr, ref i, ref encodeType);
                    }
                }
                else
                {
                    i++;
                }
            }

            // If no character code was specified, just bail
            if (nChar == -1)
            {
                return null;
            }

            // Otherwise, convert it to text
            ConvertSymbolCharValueToText(dn, nChar, encodeType);

            return (dn.Xaml != null && dn.Xaml.Length > 0) ? dn : null;
        }
        internal void PreCoalesceChildren(ConverterState converterState, int nStart, bool bChild)
        {
            // We process tables twice to handle first colspan, then rowspan
            DocumentNodeArray dnaTables = new DocumentNodeArray();
            bool fVMerged = false;

            // Try to move paragraph margin to containing list items
            DocumentNode dnCoalesce = EntryAt(nStart);
            int nChild = dnCoalesce.ChildCount;
            Debug.Assert(nStart + nChild < Count);
            if (nStart + nChild >= Count)
            {
                nChild = Count - nStart - 1;
            }

            int nEnd = nStart + nChild;

            // If bChild specified, we don't process parent
            if (bChild)
            {
                nStart++;
            }

            // This is vaguely N^2 in the sense that for each list item, I process all containing paragraphs,
            // including ones contained in other list items.  But it's only a problem for very deep, very long
            // lists, so we can live with it.
            for (int nAt = nStart; nAt <= nEnd; nAt++)
            {
                DocumentNode dn = EntryAt(nAt);

                // Inline direction merging
                if (dn.IsInline && dn.RequiresXamlDir && dn.ClosedParent != null)
                {
                    int nnAt = nAt + 1;
                    for (; nnAt <= nEnd; nnAt++)
                    {
                        DocumentNode dnn = EntryAt(nnAt);

                        if (!dnn.IsInline
                            || dnn.Type == DocumentNodeType.dnHyperlink
                            || dnn.FormatState.DirChar != dn.FormatState.DirChar
                            || dnn.ClosedParent != dn.ClosedParent)
                        {
                            break;
                        }
                    }

                    int nChildHere = nnAt - nAt;
                    if (nChildHere > 1)
                    {

                        DocumentNode dnNewDir = new DocumentNode(DocumentNodeType.dnInline);
                        dnNewDir.FormatState = new FormatState(dn.Parent.FormatState);
                        dnNewDir.FormatState.DirChar = dn.FormatState.DirChar;

                        InsertChildAt(dn.ClosedParent, dnNewDir, nAt, nChildHere);

                        // Adjust the loop end to account for the newly inserted element
                        nEnd += 1;
                    }
                }

                else if (dn.Type == DocumentNodeType.dnListItem)
                {
                    PreCoalesceListItem(dn);
                }

                else if (dn.Type == DocumentNodeType.dnList)
                {
                    PreCoalesceList(dn);
                }

                else if (dn.Type == DocumentNodeType.dnTable)
                {
                    dnaTables.Add(dn);
                    nEnd += PreCoalesceTable(dn);
                }

                // Compute colspan
                else if (dn.Type == DocumentNodeType.dnRow)
                {
                    PreCoalesceRow(dn, ref fVMerged);
                }
            }

            // Process tables to examine rowspan
            if (fVMerged)
            {
                ProcessTableRowSpan(dnaTables);
            }
        }
        internal void ProcessImage(FormatState formatState)
        {
            string contentType;
            string imagePartUriString;

            switch (formatState.ImageFormat)
            {
                case RtfImageFormat.Wmf:
                case RtfImageFormat.Png:
                    contentType = "image/png";
                    break;

                case RtfImageFormat.Jpeg:
                    contentType = "image/jpeg";
                    break;

                default:
                    contentType = string.Empty;
                    break;
            }

            bool skipImage = (formatState.ImageScaleWidth < 0) || (formatState.ImageScaleHeight < 0);

            if (_wpfPayload != null && contentType != string.Empty && !skipImage)
            {
                // Get image part URI string and image binary steam to write Rtf image data
                // into the container of WpfPayload
                Stream imageStream = _wpfPayload.CreateImageStream(_imageCount, contentType, out imagePartUriString);

                using (imageStream)
                {
                    if (formatState.ImageFormat != RtfImageFormat.Wmf)
                    {
                        // Write the image binary data on the container from Rtf image data
                        _lexer.WriteImageData(imageStream, formatState.IsImageDataBinary);
                    }
                    else
                    {
                        // Read the windows metafile from the rtf content and then convert it
                        // to bitmap data then save it as PNG on the container image part
                        MemoryStream metafileStream = new MemoryStream(); ;

                        using (metafileStream)
                        {
                            // Get Windows Metafile from rtf content
                            _lexer.WriteImageData(metafileStream, formatState.IsImageDataBinary);

                            metafileStream.Position = 0;

                            SystemDrawingHelper.SaveMetafileToImageStream(metafileStream, imageStream);
                        }
                    }
                }

                // Increase the image count to generate the image source name
                _imageCount++;

                formatState.ImageSource = imagePartUriString;

                // Create the image document node
                DocumentNode dnImage = new DocumentNode(DocumentNodeType.dnImage);

                dnImage.FormatState = formatState;

                StringBuilder imageStringBuilder = new StringBuilder();

                // Add the xaml image element
                imageStringBuilder.Append("<Image ");

                // Add the xaml image width property
                imageStringBuilder.Append(" Width=\"");
                double width;
                if (formatState.ImageScaleWidth != 0)
                {
                    width = formatState.ImageWidth * (formatState.ImageScaleWidth / 100);
                }
                else
                {
                    width = formatState.ImageWidth;
                }
                imageStringBuilder.Append(width.ToString(CultureInfo.InvariantCulture));
                imageStringBuilder.Append("\"");

                // Add the xaml image height property
                imageStringBuilder.Append(" Height=\"");
                double height = formatState.ImageHeight * (formatState.ImageScaleHeight / 100);
                if (formatState.ImageScaleHeight != 0)
                {
                    height = formatState.ImageHeight * (formatState.ImageScaleHeight / 100);
                }
                else
                {
                    height = formatState.ImageHeight;
                }
                imageStringBuilder.Append(height.ToString(CultureInfo.InvariantCulture));
                imageStringBuilder.Append("\"");

                // Add the xaml image stretch property
                imageStringBuilder.Append(" Stretch=\"Fill");
                imageStringBuilder.Append("\"");


                // Add the xaml image close tag
                imageStringBuilder.Append(">");

                // Add the image source property as the complex property
                // This is for specifying BitmapImage.CacheOption as OnLoad instead of
                // the default OnDemand option.
                imageStringBuilder.Append("<Image.Source>");
                imageStringBuilder.Append("<BitmapImage ");
                imageStringBuilder.Append("UriSource=\"");
                imageStringBuilder.Append(imagePartUriString);
                imageStringBuilder.Append("\" ");
                imageStringBuilder.Append("CacheOption=\"OnLoad\" ");
                imageStringBuilder.Append("/>");
                imageStringBuilder.Append("</Image.Source>");
                imageStringBuilder.Append("</Image>");

                // Set Xaml for image element
                dnImage.Xaml = imageStringBuilder.ToString();

                // Insert the image document node to the document node array
                DocumentNodeArray dna = _converterState.DocumentNodeArray;
                dna.Push(dnImage);
                dna.CloseAt(dna.Count - 1);
            }
            else
            {
                // Skip the image data if the image type is unknown or WpfPayload is null
                _lexer.AdvanceForImageData();
            }
        }
        internal DocumentNode GetOpenParentWhileParsing(DocumentNode dn)
        {
            if (_dnaOpen != null)
            {
                _dnaOpen.CullOpen();
                for (int i = _dnaOpen.Count - 1; i >= 0; i--)
                {
                    DocumentNode dnPa = _dnaOpen.EntryAt(i);

                    if (dnPa.IsPending && dnPa.Index < dn.Index)
                    {
                        return dnPa;
                    }
                }
            }

            return null;
        }
        private void ProcessRtfDestination(FormatState fsCur)
        {
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
            int nAt;

            switch (fsCur.RtfDestination)
            {
                case RtfDestination.DestField:
                    nAt = dna.FindUnmatched(DocumentNodeType.dnFieldBegin);
                    if (nAt >= 0)
                    {
                        DocumentNode dnEnd = new DocumentNode(DocumentNodeType.dnFieldEnd);
                        dnEnd.FormatState = new FormatState(fsCur);
                        dnEnd.IsPending = false;
                        dna.Push(dnEnd);
                        dna.EntryAt(nAt).IsMatched = true;
                        ProcessField();
                    }
                    break;
                case RtfDestination.DestFieldInstruction:
                case RtfDestination.DestFieldPrivate:
                case RtfDestination.DestFieldResult:
                    nAt = dna.FindUnmatched(DocumentNodeType.dnFieldBegin);
                    if (nAt >= 0)
                    {
                        DocumentNode dnEnd = new DocumentNode(DocumentNodeType.dnFieldEnd);
                        dnEnd.FormatState = new FormatState(fsCur);
                        dnEnd.IsPending = false;
                        dna.Push(dnEnd);
                        dna.EntryAt(nAt).IsMatched = true;
                    }
                    break;

                // The DestShape destination is only to distinguish the case of leaving a shaperesult destination
                // when shapes were nested.  No processing is actually necessary here.
                case RtfDestination.DestShape:
                    break;

                case RtfDestination.DestShapeResult:
                    ProcessShapeResult();
                    break;

                case RtfDestination.DestListText:
                    ProcessListText();
                    break;

                case RtfDestination.DestListLevel:
                    {
                        ListTableEntry listTableEntry = _converterState.ListTable.CurrentEntry;
                        if (listTableEntry != null)
                        {
                            ListLevel listLevel = listTableEntry.Levels.CurrentEntry;
                            listLevel.FormatState = new FormatState(fsCur);
                        }
                    }
                    break;

                case RtfDestination.DestListOverride:
                    break;

                case RtfDestination.DestList:
                    break;

                case RtfDestination.DestFontName:
                    FontTableEntry entry = _converterState.FontTable.CurrentEntry;
                    if (entry != null)
                    {
                        entry.IsNameSealed = true;
                        entry.IsPending = false;
                    }
                    break;

                case RtfDestination.DestFontTable:
                    _converterState.FontTable.MapFonts();
                    break;
            }
        }
        internal void InsertOpenNode(DocumentNode dn)
        {
            CullOpen();

            int i = Count;
            for (; i > 0; i--)
            {
                if (dn.Index > EntryAt(i - 1).Index)
                {
                    break;
                }
            }
            Insert(i, dn);
        }
        internal void WrapInlineInParagraph(int nInsertAt, int nChildren)
        {
            DocumentNodeArray dna = _converterState.DocumentNodeArray;

            Debug.Assert(nInsertAt >= 0 && nChildren > 0 && nInsertAt + nChildren - 1 < dna.Count);

            DocumentNode dnChild = dna.EntryAt(nInsertAt + nChildren - 1);
            DocumentNode dn = new DocumentNode(DocumentNodeType.dnParagraph);
            dn.FormatState = new FormatState(dnChild.FormatState);
            dn.ConstrainFontPropagation(dn.FormatState);

            DocumentNode dnParent = null;

            // Parent shouldn't be the child of new inserted document node
            // to avoid the infinite loop on InsertChildAt()
            if (dnChild.ClosedParent != null
                && dnChild.ClosedParent.Index < nInsertAt
                && dnChild.ClosedParent.Index > (nInsertAt + nChildren - 1))
            {
                dnParent = dnChild.ClosedParent;
            }

            dna.InsertChildAt(dnParent, dn, nInsertAt, nChildren);
            dna.CoalesceOnlyChildren(_converterState, nInsertAt);
        }
Esempio n. 30
0
        private void WriteInlineChild(DocumentNode documentNode)
        { 
            // Handle empty nodes first
            if (documentNode.IsEmptyNode)
            {
                WriteEmptyChild(documentNode); 
                return;
            } 
 
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
            FormatState fsThis = documentNode.FormatState; 
            FormatState fsParent = documentNode.Parent != null
                                        ? documentNode.Parent.FormatState
                                        : FormatState.EmptyFormatState;
 
            bool outFont = fsThis.Font != fsParent.Font;
            bool outBold = fsThis.Bold != fsParent.Bold; 
            bool outItalic = fsThis.Italic != fsParent.Italic; 
            bool outUL = fsThis.UL != fsParent.UL;
            bool outFontSize = fsThis.FontSize != fsParent.FontSize; 
            bool outCF = fsThis.CF != fsParent.CF;
            bool outCB = fsThis.CB != fsParent.CB;
            bool outS = fsThis.Strike != fsParent.Strike;
            bool outSuper = fsThis.Super != fsParent.Super; 
            bool outSub = fsThis.Sub != fsParent.Sub;
            bool outLang = fsThis.Lang != fsParent.Lang && fsThis.Lang > 0; 
            bool outDir = fsThis.DirChar != DirState.DirDefault 
                            && (documentNode.Parent == null
                                || !documentNode.Parent.IsInline 
                                || fsThis.Lang != fsParent.Lang);
            bool outAny = outFont || outBold || outItalic || outUL || outLang || outDir ||
                          outFontSize || outCF || outCB || outS || outSuper || outSub;
 
            // Start a context so any properties only apply here
            if (outAny) 
            { 
                _rtfBuilder.Append("{");
            } 

            // Write properties
            if (outLang)
            { 
                _rtfBuilder.Append("\\lang");
                _rtfBuilder.Append(fsThis.Lang.ToString(CultureInfo.InvariantCulture)); 
            } 
            if (outFont)
            { 
                _rtfBuilder.Append("\\loch");
                _rtfBuilder.Append("\\f");
                _rtfBuilder.Append(fsThis.Font.ToString(CultureInfo.InvariantCulture));
            } 
            if (outBold)
            { 
                if (fsThis.Bold) 
                {
                    _rtfBuilder.Append("\\b"); 
                }
                else
                {
                    _rtfBuilder.Append("\\b0"); 
                }
            } 
            if (outItalic) 
            {
                if (fsThis.Italic) 
                {
                    _rtfBuilder.Append("\\i");
                }
                else 
                {
                    _rtfBuilder.Append("\\i0"); 
                } 
            }
            if (outUL) 
            {
                if (fsThis.UL != ULState.ULNone)
                {
                    _rtfBuilder.Append("\\ul"); 
                }
                else 
                { 
                    _rtfBuilder.Append("\\ul0");
                } 
            }
            if (outS)
            {
                if (fsThis.Strike != StrikeState.StrikeNone) 
                {
                    _rtfBuilder.Append("\\strike"); 
                } 
                else
                { 
                    _rtfBuilder.Append("\\strike0");
                }
            }
            if (outFontSize) 
            {
                _rtfBuilder.Append("\\fs"); 
                _rtfBuilder.Append(fsThis.FontSize.ToString(CultureInfo.InvariantCulture)); 
            }
            if (outCF) 
            {
                _rtfBuilder.Append("\\cf");
                _rtfBuilder.Append(fsThis.CF.ToString(CultureInfo.InvariantCulture));
            } 
            if (outCB)
            { 
                _rtfBuilder.Append("\\highlight"); 
                _rtfBuilder.Append(fsThis.CB.ToString(CultureInfo.InvariantCulture));
            } 
            if (outSuper)
            {
                if (fsThis.Super)
                { 
                    _rtfBuilder.Append("\\super");
                } 
                else 
                {
                    _rtfBuilder.Append("\\super0"); 
                }
            }
            if (outSub)
            { 
                if (fsThis.Sub)
                { 
                    _rtfBuilder.Append("\\sub"); 
                }
                else 
                {
                    _rtfBuilder.Append("\\sub0");
                }
            } 
            if (outDir)
            { 
                if (fsThis.DirChar == DirState.DirLTR) 
                {
                    _rtfBuilder.Append("\\ltrch"); 
                }
                else
                {
                    _rtfBuilder.Append("\\rtlch"); 
                }
            } 
 
            // Ensure space delimiter after control word
            if (outAny) 
            {
                _rtfBuilder.Append(" ");
            }
 
            // Write contents here
            if (documentNode.Type == DocumentNodeType.dnHyperlink && !string.IsNullOrEmpty(documentNode.NavigateUri)) 
            { 
                _rtfBuilder.Append("{\\field{\\*\\fldinst { HYPERLINK \"");
 
                // Add the additional backslash which rtf expected
                for (int i = 0; i < documentNode.NavigateUri.Length; i++)
                {
                    if (documentNode.NavigateUri[i] == '\\') 
                    {
                        _rtfBuilder.Append("\\\\"); 
                    } 
                    else
                    { 
                        _rtfBuilder.Append(documentNode.NavigateUri[i]);
                    }
                }
 
                _rtfBuilder.Append("\" }}{\\fldrslt {");
            } 
            else 
            {
                _rtfBuilder.Append(documentNode.Content); 
            }

            if (documentNode.Type == DocumentNodeType.dnImage)
            { 
                // Write image control and image hex data to the rtf content
                WriteImage(documentNode); 
            } 

            // Write child contents 
            int nStart = documentNode.Index + 1;
            int nEnd = documentNode.Index + documentNode.ChildCount;

            for (; nStart <= nEnd; nStart++) 
            {
                DocumentNode documentNodeChild = dna.EntryAt(nStart); 
 
                // Ignore non-direct children - they get written out by their parent
                if (documentNodeChild.Parent == documentNode) 
                {
                    WriteInlineChild(documentNodeChild);
                }
            } 

            // Terminate contents here 
            if (documentNode.Type == DocumentNodeType.dnHyperlink && !string.IsNullOrEmpty(documentNode.NavigateUri)) 
            {
                _rtfBuilder.Append("}}}"); 
            }

            // End context
            if (outAny) 
            {
                _rtfBuilder.Append("}"); 
            } 
        }