예제 #1
0
        internal static CssSelectors Create(string selector)
        {
            CssSelectors selectors = new CssSelectors();

            selectors.AddFromText(selector);
            return(selectors);
        }
예제 #2
0
        internal void SetHtml(FrameworkElement rootElement, string htmlText, Control optionalFontTemplate)
        {
            try
            {
                // This is the main entry point, initialize everything
                _RootElement = rootElement;
                if (!(_RootElement is Panel || _RootElement is RichTextBox))
                {
                    return;
                }
                if (_RootElement is Panel)
                {
                    _CurrentRichTextBox = new RichTextBlock();
                    (_RootElement as Panel).Children.Clear();
                    (_RootElement as Panel).Children.Add(_CurrentRichTextBox);
                }
                else
                if (_RootElement is RichTextBox)
                {
                    _CurrentRichTextBox = _RootElement as RichTextBox;
                }
                _CurrentParagraph = new Paragraph();
                _CurrentRichTextBox.Blocks.Add(_CurrentParagraph);

                // Setup the initial document state
                DocumentState documentState = new DocumentState();
                if (optionalFontTemplate == null)
                {
                    optionalFontTemplate = _RootElement as Control;
                }
                if (optionalFontTemplate != null)
                {
                    documentState.Brush     = optionalFontTemplate.Foreground;
                    documentState.Face      = optionalFontTemplate.FontFamily.Source;
                    documentState.Size      = optionalFontTemplate.FontSize;
                    documentState.Italic    = (optionalFontTemplate.FontStyle == FontStyles.Italic);
                    documentState.Bold      = (optionalFontTemplate.FontWeight != FontWeights.Normal);
                    documentState.Underline = false;
                }
                else
                {
                    Run defaultRun = new Run();
                    documentState.Brush     = defaultRun.Foreground;
                    documentState.Face      = defaultRun.FontFamily.Source;
                    documentState.Size      = defaultRun.FontSize;
                    documentState.Italic    = (defaultRun.FontStyle == FontStyles.Italic);
                    documentState.Bold      = (defaultRun.FontWeight != FontWeights.Normal);
                    documentState.Underline = (defaultRun.TextDecorations == TextDecorations.Underline);
                }

                _DocumentStates = new Stack <DocumentState>();
                _DocumentStates.Push(documentState);

                _PriorLineBreaks = 2;                 // As if we are following a paragraph

                bool hasMarkup = (htmlText != null && htmlText.IndexOf("<") >= 0 && htmlText.IndexOf(">") > 0);
                if (!hasMarkup)                 // translate ampersands & and the like
                {
                    htmlText = HttpUtility.HtmlEncode(htmlText);
                }
                bool hasXmlDirective = (hasMarkup && htmlText.IndexOf("<?xml") >= 0);
                if (!hasXmlDirective)                 // add an outer <span> to ensure valid XML regardless of the text markup
                {
                    htmlText = string.Concat("<span>", htmlText, "</span>");
                }
                bool hasInvalidEntity = (htmlText.IndexOf("&nbsp;") >= 0);
                if (hasInvalidEntity)
                {
                    htmlText = htmlText.Replace("&nbsp;", "&#160;");
                }
                hasInvalidEntity = (htmlText.IndexOf("&copy;") >= 0);
                if (hasInvalidEntity)
                {
                    htmlText = htmlText.Replace("&copy;", "&#169;");
                }

                // Read the XML DOM input
                StringReader      stringReader = new StringReader(htmlText);
                XmlReaderSettings settings     = new XmlReaderSettings();
                settings.DtdProcessing                = DtdProcessing.Ignore;
                settings.IgnoreWhitespace             = false;
                settings.IgnoreProcessingInstructions = true;
                settings.IgnoreComments               = true;
                //settings.CheckCharacters = false;
                //settings.ConformanceLevel = ConformanceLevel.Auto;
                XmlReader xmlReader = XmlReader.Create(stringReader, settings);
                while (xmlReader.Read())
                {
                    string nameLower = xmlReader.Name.ToLower();
                    if (xmlReader.NodeType == XmlNodeType.Element)
                    {
                        // Process the element start
                        bool bEmpty = xmlReader.IsEmptyElement;
                        switch (nameLower)
                        {
                        // Process the following elements:
                        // "style"
                        // "a" "img" "font"
                        // "b" "strong"
                        // "h1" "h2" "h3" "h4" "h5" "h6"
                        // "i" "em" "cite"
                        // "u" "br" "pre" "code" "tt"
                        // "p" "form"
                        // "ol" "ul" "blockquote" "dir" "menu"
                        // "li" "div" "center" "span"
                        case "head":
                        case "object":
                        case "meta":
                        case "title":
                        case "script":
                        case "noscript":
                        {
                            _IgnoreText = true;
                            break;
                        }

                        case "style":
                        {
                            _InternalStyles = string.Empty;
                            break;
                        }

                        case "link":
                        {
                            string rel  = null;
                            string href = null;
                            if (xmlReader.MoveToFirstAttribute())
                            {
                                do
                                {
                                    if (xmlReader.Name.ToLower() == "rel")
                                    {
                                        rel = xmlReader.Value;
                                    }
                                    else
                                    if (xmlReader.Name.ToLower() == "href")
                                    {
                                        href = xmlReader.Value;
                                    }
                                }while (xmlReader.MoveToNextAttribute());
                            }

                            if (rel == "stylesheet" && href != null)
                            {
                                if (_DocumentUri != null)
                                {
                                    href = _DocumentUri.Site().Append(href).ToString();
                                }
                                //j	CssParser.DownloadStyles(UriHelper.MakeAbsolute(_DocumentUri.Site(), href), ref _GlobalStyles);
                            }
                            break;
                        }

                        case "a":
                        case "area":
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            string href = null;
                            if (xmlReader.MoveToFirstAttribute())
                            {
                                do
                                {
                                    if (xmlReader.Name.ToLower() == "href")
                                    {
                                        href = xmlReader.Value;
                                    }
                                }while (xmlReader.MoveToNextAttribute());
                            }

                            if (href != null)
                            {
                                if (_DocumentUri != null && !href.StartsWith("#"))
                                {
                                    href = _DocumentUri.Site().Append(href).ToString();
                                }
                                state.Href = href;
                            }

                            _DocumentStates.Push(state);
                            break;
                        }

                        case "base":
                        {
                            string href = null;
                            if (xmlReader.MoveToFirstAttribute())
                            {
                                do
                                {
                                    if (xmlReader.Name.ToLower() == "href")
                                    {
                                        href = xmlReader.Value;
                                    }
                                }while (xmlReader.MoveToNextAttribute());
                            }

                            if (href != null)
                            {
                                _DocumentUri = new Uri(href, UriKind.Absolute);
                            }
                            break;
                        }

                        case "img":
                        {
                            string        source = null;
                            DocumentState state  = _DocumentStates.Peek();
                            if (xmlReader.MoveToFirstAttribute())
                            {
                                do
                                {
                                    if (xmlReader.Name.ToLower() == "src")
                                    {
                                        source = xmlReader.Value;
                                    }
                                }while (xmlReader.MoveToNextAttribute());
                            }

                            if (source != null)
                            {
                                if (_DocumentUri != null)
                                {
                                    source = _DocumentUri.Site().Append(source).ToString();
                                }
                                AddImage(source);
                            }
                            break;
                        }

                        case "font":
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            if (xmlReader.MoveToFirstAttribute())
                            {
                                do
                                {
                                    if (xmlReader.Name.ToLower() == "face")
                                    {
                                        state.Face = xmlReader.Value;
                                    }
                                    else
                                    if (xmlReader.Name.ToLower() == "size")
                                    {
                                        state.Size = CssParser.ParseFontSize(xmlReader.Value, state.Size);
                                    }
                                    else
                                    if (xmlReader.Name.ToLower() == "color")
                                    {
                                        state.Brush = xmlReader.Value.ToColor().ToBrush();
                                    }
                                }while (xmlReader.MoveToNextAttribute());
                            }
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "big":
                        case "small":
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            double percent = (nameLower == "big" ? 1.2 : .8);
                            state.Size *= percent;
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "b":
                        case "strong":
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            state.Bold = true;
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "h1":
                        case "h2":
                        case "h3":
                        case "h4":
                        case "h5":
                        case "h6":
                        {
                            MoveToBeginLine(true);
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            // Special h? font size handling
                            if (!ProcessCommonStyles(ref state, xmlReader, nameLower))
                            {
                                state.Size = CssParser.ParseFontSize(nameLower, state.Size);
                            }
                            state.Bold = true;

                            _DocumentStates.Push(state);
                            break;
                        }

                        case "i":
                        case "em":
                        case "cite":
                        case "address":
                        case "dfn":                                 // Definition term
                        case "var":                                 // Variable
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            state.Italic = true;
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "u":
                        case "ins":
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            state.Underline = true;
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "s":
                        case "strike":
                        case "del":
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            //state.StrikeThrough = true;
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "br":
                        {
                            AddLineBreak();
                            break;
                        }

                        case "pre":
                        case "code":
                        case "samp":                                 // Sample computer code
                        case "kbd":
                        case "tt":
                        {
                            if (nameLower == "pre")
                            {
                                MoveToBeginLine(true);
                            }
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            state.Face = "Courier New";
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "ol":
                        case "ul":
                        case "dir":                                 // Same as "ul"
                        case "menu":                                // Same as "ul"
                        {
                            DocumentState state        = _DocumentStates.Peek();
                            bool          newParagraph = (bEmpty || state.BulletType == '\0');
                            MoveToBeginLine(newParagraph);
                            if (bEmpty)
                            {
                                break;
                            }

                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            state.BulletType     = (nameLower == "ol" ? 'o' : 'u');
                            state.ListItemNumber = 0;
                            state.Indent        += 8;
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "li":
                        {
                            MoveToBeginLine(false);

                            // Bump the list item number
                            DocumentState state = _DocumentStates.Pop();
                            state.ListItemNumber++;
                            _DocumentStates.Push(state);

                            //DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            _DocumentStates.Push(state);

                            AddIndent();
                            AddListItem();
                            break;
                        }

                        case "blockquote":
                        {
                            MoveToBeginLine(true);
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            state.Indent += 8;
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "div":
                        case "p":
                        case "body":
                        case "form":
                        case "center":
                        case "textarea":
                        {
                            MoveToBeginLine(true);
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "table":
                        case "caption":
                        case "tr":
                        case "td":
                        {
                            if (nameLower != "td")
                            {
                                MoveToBeginLine(false);
                            }
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "sup":
                        case "sub":
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "dl":
                        case "dt":
                        case "dd":
                        {
                            bool newParagraph = (nameLower == "dl");
                            MoveToBeginLine(newParagraph);
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            if (nameLower == "dd")
                            {
                                state.Indent += 8;
                            }
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "span":
                        case "label":
                        case "q":
                        case "abbr":
                        case "acronym":
                        {
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            _DocumentStates.Push(state);
                            break;
                        }

                        case "legend":
                        {
                            MoveToBeginLine(false);
                            if (bEmpty)
                            {
                                break;
                            }

                            DocumentState state = _DocumentStates.Peek();
                            ProcessCommonStyles(ref state, xmlReader, nameLower);
                            _DocumentStates.Push(state);
                            break;
                        }
                        }
                    }
                    else
                    if (xmlReader.NodeType == XmlNodeType.EndElement)
                    {
                        // Process the element end
                        switch (nameLower)
                        {
                        case "head":
                        case "object":
                        case "meta":
                        case "title":
                        case "script":
                        case "noscript":
                        {
                            _IgnoreText = false;
                            break;
                        }

                        case "style":
                        {
                            _GlobalSelectors = CssSelectors.Create(_InternalStyles);
                            _InternalStyles  = null;
                            break;
                        }

                        case "link":
                        {
                            _IgnoreText = false;
                            break;
                        }

                        case "a":
                        case "area":
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "base":
                        {
                            break;
                        }

                        case "img":
                        {
                            break;
                        }

                        case "font":
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "big":
                        case "small":
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "b":
                        case "strong":
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "h1":
                        case "h2":
                        case "h3":
                        case "h4":
                        case "h5":
                        case "h6":
                        {
                            MoveToBeginLine(true);
                            _DocumentStates.Pop();
                            break;
                        }

                        case "i":
                        case "em":
                        case "cite":
                        case "address":
                        case "dfn":                                 // Definition term
                        case "var":                                 // Variable
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "u":
                        case "ins":
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "s":
                        case "strike":
                        case "del":
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "br":
                        {
                            break;
                        }

                        case "pre":
                        case "code":
                        case "samp":                                 // Sample computer code
                        case "kbd":
                        case "tt":
                        {
                            if (nameLower == "pre")
                            {
                                MoveToBeginLine(true);
                            }
                            _DocumentStates.Pop();
                            break;
                        }

                        case "ol":
                        case "ul":
                        case "dir":
                        case "menu":
                        {
                            MoveToBeginLine(true);
                            _DocumentStates.Pop();
                            break;
                        }

                        case "li":
                        {
                            MoveToBeginLine(false);
                            _DocumentStates.Pop();
                            break;
                        }

                        case "blockquote":
                        {
                            MoveToBeginLine(true);
                            _DocumentStates.Pop();
                            break;
                        }

                        case "div":
                        case "p":
                        case "body":
                        case "form":
                        case "center":
                        case "textarea":
                        {
                            MoveToBeginLine(false);
                            _DocumentStates.Pop();
                            break;
                        }

                        case "table":
                        case "caption":
                        case "tr":
                        case "td":
                        {
                            if (nameLower != "td")
                            {
                                MoveToBeginLine(false);
                            }
                            _DocumentStates.Pop();
                            break;
                        }

                        case "sup":
                        case "sub":
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "dl":
                        case "dt":
                        case "dd":
                        {
                            bool newParagraph = (nameLower == "dl");
                            MoveToBeginLine(newParagraph);
                            _DocumentStates.Pop();
                            break;
                        }

                        case "span":
                        case "label":
                        case "q":
                        case "abbr":
                        case "acronym":
                        {
                            _DocumentStates.Pop();
                            break;
                        }

                        case "legend":
                        {
                            MoveToBeginLine(false);
                            _DocumentStates.Pop();
                            break;
                        }
                        }
                    }
                    else
                    if (xmlReader.NodeType == XmlNodeType.Text)
                    {
                        // Process the element text
                        string text = "";
                        try { text = xmlReader.Value; }
                        catch (Exception ex)
                        {
                            text = ex.Message;
                        }

                        if (_InternalStyles != null)
                        {
                            _InternalStyles += text;
                        }
                        else
                        if (!_IgnoreText)
                        {
                            // Remove redundant whitespace ala HTML
                            StringBuilder builder = new StringBuilder(text.Length);
                            char          cLast   = (_PriorLineBreaks > 0 ? ' ' : '\0');
                            foreach (char ch in text)
                            {
                                char c = ch;
                                if (c == '\t' || c == '\n')
                                {
                                    c = ' ';
                                }
                                bool bSkip = (cLast == ' ' && c == ' ');
                                cLast = c;
                                if (!bSkip)
                                {
                                    builder.Append(c);
                                }
                            }

                            // Output the text
                            string textRun = builder.ToString();
                            AddText(textRun);
                        }
                    }
                    else
                    if (xmlReader.NodeType == XmlNodeType.Whitespace)
                    {
                        // Process the element whitespace
                        if (_InternalStyles != null)
                        {
                            _InternalStyles += " ";
                        }
                        else
                        if (!_IgnoreText)
                        {
                            // Remove redundant whitespace ala HTML
                            bool bSkip = (_PriorLineBreaks > 0);
                            if (!bSkip)
                            {
                                AddText(" ");
                            }
                        }
                    }
                }

                FlushAll();
            }
            catch (Exception ex)
            {
                //ex.DebugOutput();
                ex.Alert();

                // Invalid XHTML; Clear any existing collection of Inlines
                if (_RootElement is RichTextBox)
                {
                    (_RootElement as RichTextBox).Blocks.Clear();
                    Paragraph paragraph = new Paragraph();
                    paragraph.Inlines.Add(new Run()
                    {
                        Text = htmlText
                    });
                    (_RootElement as RichTextBox).Blocks.Add(paragraph);
                }
            }
            finally
            {
                _DocumentStates.Clear();
                _DocumentStates = null;

                if (_GlobalSelectors != null)
                {
                    _GlobalSelectors.Dispose();
                    _GlobalSelectors = null;
                }

                _RootElement        = null;
                _CurrentRichTextBox = null;
                _CurrentParagraph   = null;
            }
        }