Esempio n. 1
0
    public static string MoveCssInline(string htmlInput, bool removeStyleElements, Uri basePath)
    {
      using (var reader = new System.IO.StringReader(htmlInput))
      {
        var web = new System.Net.WebClient();
        var sgmlReader = new Pipes.Sgml.SgmlReader();
        sgmlReader.DocType = "HTML";
        sgmlReader.WhitespaceHandling = WhitespaceHandling.All;
        sgmlReader.CaseFolding = CaseFolding.ToLower;
        sgmlReader.InputStream = reader;
        sgmlReader.SimulatedNode = "html";
        sgmlReader.StripDocType = false;
        
        var doc = new XmlDocument();
        doc.Load(sgmlReader);
        var root = doc.DocumentElement;
        if (root.ChildNodes.OfType<XmlElement>().Count() == 1) root = root.ChildNodes.OfType<XmlElement>().Single();

        var parser = new Parser();
        var engine = new HtmlQueryEngine();
        var visitor = new MatchVisitor(engine) { Comparison = StringComparison.OrdinalIgnoreCase };

        var css = new StringBuilder();
        var nodes = doc.SelectNodes("//style").OfType<System.Xml.XmlNode>().ToList();
        foreach (var node in nodes)
        {
          css.AppendLine(node.InnerText);
          if (removeStyleElements) node.ParentNode.RemoveChild(node);
        }

        nodes = doc.SelectNodes("//link[@rel='stylesheet' and @href]").OfType<System.Xml.XmlNode>().ToList();
        foreach (var node in nodes)
        {
          css.Append("@import url('").Append(node.Attributes["href"].Value).Append("')");
          if (node.Attributes["media"] != null && !string.IsNullOrEmpty(node.Attributes["media"].Value))
          {
            css.Append(" ").Append(node.Attributes["media"].Value);
          }
          css.AppendLine(";");
          if (removeStyleElements) node.ParentNode.RemoveChild(node);
        }

        var stylesheet = parser.Parse(css.ToString());
        var elements = root.SelectNodes("//*").OfType<XmlElement>().Select(e => new Pipes.Xml.XmlElementWrapper(e)).ToList();
        var settings = new GlobalStyleContext();
        settings.ResourceLoader = p => {
          var href = (basePath == null ? new Uri(p) : new Uri(basePath, p));
          return DownloadStream(href);
        };

        var rules = stylesheet.Rules.GetStyleRules(settings).ToList();
        IEnumerable<StyleRule> elemRules;
        string inlineStyle;
        IEnumerable<Property> props;
        foreach (var elem in elements)
        {
          inlineStyle = elem.Attribute<string>("style", null);
          elemRules = rules;
          if (!string.IsNullOrEmpty(inlineStyle))
          {
            elemRules = elemRules.Concat(Enumerable.Repeat(Utils.ParseInline(inlineStyle), 1));
          }
          props = elemRules.ApplicableProperties(elem, engine, StringComparison.OrdinalIgnoreCase, settings);
          if (props.Any())
          {
            inlineStyle = props.Select(p => p.ToString()).Aggregate((p, c) => p + ";" + c);
            elem.Attribute("style", inlineStyle);
          }
        }

        return doc.OuterXml;
      }
    }
Esempio n. 2
0
    public static IEnumerable<StyleRule> GetStyleRules(this IEnumerable<RuleSet> rules, GlobalStyleContext settings)
    {
      StyleRule style;
      MediaRule media;

      while (rules.Any())
      {
        var loader = new ImportLoader(rules.OfType<ImportRule>()
                                           .Where(i => !i.Media.Any() || i.Media.Any(m => MediaMatches(m, settings)))
                                           .ToList(),
                                      settings.ResourceLoader);
        loader.Start();

        foreach (var rule in rules)
        {
          style = rule as StyleRule;
          media = rule as MediaRule;
          if (style != null)
          {
            yield return style;
          }
          else if (media != null)
          {
            if (media.Media.Any(m => MediaMatches(m, settings)))
            {
              foreach (var s in media.RuleSets.GetStyleRules(settings))
              {
                yield return s;
              }
            }
          }
        }

        loader.WaitAll();
        if (loader.Sheets.Any())
        {
          rules = loader.Sheets.SelectMany(s => s.Rules);
        }
        else
        {
          rules = Enumerable.Empty<RuleSet>();
        }
      }
    }
Esempio n. 3
0
    private static bool MediaMatches(MediaDefinition d, GlobalStyleContext settings)
    {
      var context = new StyleContext();
      var result = (d.Modifier != MediaTypeModifier.Not && (d.Type & settings.Media) > 0) ||
                   (d.Modifier == MediaTypeModifier.Not && (d.Type & settings.Media) == 0);
      if (result)
      {
        var width = d.Properties.Where(p => string.Compare(p.Name, "width", StringComparison.OrdinalIgnoreCase) == 0 ||
                                            p.Name.EndsWith("-width", StringComparison.OrdinalIgnoreCase));
        var plainProps = width.OfType<MediaPropertyPlain>();
        double px;
        foreach (var plain in plainProps)
        {
          px = ToPx(plain.Value as PrimitiveTerm, context, false);
          if (plain.Name.StartsWith("max-", StringComparison.OrdinalIgnoreCase) && px > settings.MediaWidth) return false;
          if (plain.Name.StartsWith("min-", StringComparison.OrdinalIgnoreCase) && px < settings.MediaWidth) return false;
        }

        var rangeProps = width.OfType<MediaPropertyRange>();
        foreach (var range in rangeProps)
        {
          if (range.LowerBound != null)
          {
            px = ToPx(range.LowerBound as PrimitiveTerm, context, false);
            if (settings.MediaWidth < px || (settings.MediaWidth == px && !range.LowerCompare.EndsWith("="))) return false;
          }
          if (range.UpperBound != null)
          {
            px = ToPx(range.UpperBound as PrimitiveTerm, context, false);
            if (settings.MediaWidth > px || (settings.MediaWidth == px && !range.UpperCompare.EndsWith("="))) return false;
          }
        }
      }
      return result;
    }
Esempio n. 4
0
    public static IEnumerable<Property> ApplicableProperties(this IEnumerable<StyleRule> rules, IQueryableNode node, IQueryEngine engine, StringComparison comparison, GlobalStyleContext settings)
    {
      var visitor = new MatchVisitor(engine);
      visitor.Comparison = comparison;
      var terms = new Dictionary<string, TermSpecificity>();
      TermSpecificity existing;
      int specificity = 0;
      int propSpecificity;

      foreach (var style in rules)
      {
        if (style.Selector != null)
        {
          visitor.Initialize(node);
          style.Selector.Visit(visitor);
        }
        if (style.Selector == null || visitor.IsMatch())
        {
          specificity = style.Selector == null ? 0 : (visitor.MatchSpecificity > 0 ? visitor.MatchSpecificity : style.Selector.GetSpecificity());
          foreach (var prop in style.Declarations.SelectMany(p => p.Expand(settings.LeftToRight)))
          {
            propSpecificity = specificity + (prop.Important ? (1 << 20) : 0);
            if (terms.TryGetValue(prop.Name, out existing))
            {
              if (propSpecificity >= existing.Specificity)
              {
                existing.Property = prop;
              }
            }
            else
            {
              terms[prop.Name] = new TermSpecificity() { Property = prop, Specificity = propSpecificity };
            }
          }
        }
      }

      return terms.Values.Select(v => v.Property);
    }