From e3ad3b3e12d918fa9c342a442cb05129248185fd Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Mon, 13 May 2019 00:05:53 +0200 Subject: [PATCH] Enable media rules --- README.md | 14 ++++++++ src/AngleSharp.Css.Tests/Styling/CssSheet.cs | 1 - .../Styling/HtmlCssIntegration.cs | 32 +++++++++++++++++++ .../CssConfigurationExtensions.cs | 13 ++++++-- src/AngleSharp.Css/Dom/Internal/MediaList.cs | 8 +++-- .../Dom/StyleCollectionExtensions.cs | 6 ++-- .../Extensions/MediaListExtensions.cs | 3 +- .../Parser/Micro/MediaParser.cs | 10 +++--- .../Parser/Micro/MediumParser.cs | 10 +++--- 9 files changed, 75 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 48820769..326c302f 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,20 @@ This will register a parser for CSS related content. The CSS parsing options and For an interactive DOM (i.e., to handle `style` attribute changes in the HTML document) an observer needs to be registered as well. +Furthermore, for some CSSOM features (e.g., media queries) a render device is required. + +```cs +var config = Configuration.Default + .WithCss() + .WithRenderDevice(new DefaultRenderDevice + { + DeviceHeight = 768, + DeviceWidth = 1024, + }); +``` + +If no specific `IRenderDevice` (e.g., via creating an `DefaultRenderDevice` object) instance is created a default implementation will be set. + ## Advantages of AngleSharp.Css The core library already contains the CSS selector parser and the most basic classes and interfaces for dealing with the CSSOM. AngleSharp.Css brings the following advantages and use cases to life: diff --git a/src/AngleSharp.Css.Tests/Styling/CssSheet.cs b/src/AngleSharp.Css.Tests/Styling/CssSheet.cs index b10be6b4..e7dff851 100644 --- a/src/AngleSharp.Css.Tests/Styling/CssSheet.cs +++ b/src/AngleSharp.Css.Tests/Styling/CssSheet.cs @@ -3,7 +3,6 @@ namespace AngleSharp.Css.Tests.Styling using AngleSharp.Css.Converters; using AngleSharp.Css.Dom; using AngleSharp.Css.Parser; - using AngleSharp.Css.Values; using NUnit.Framework; using System; using System.IO; diff --git a/src/AngleSharp.Css.Tests/Styling/HtmlCssIntegration.cs b/src/AngleSharp.Css.Tests/Styling/HtmlCssIntegration.cs index e0b13c3a..754a36f5 100644 --- a/src/AngleSharp.Css.Tests/Styling/HtmlCssIntegration.cs +++ b/src/AngleSharp.Css.Tests/Styling/HtmlCssIntegration.cs @@ -460,5 +460,37 @@ public void MediaRuleCssCausesException_Issue20() var style = document.Body.ComputeCurrentStyle(); Assert.IsNotNull(style); } + + [Test] + public void MediaRuleIsCalculatedIfScreenIsOkay() + { + var config = Configuration.Default + .WithCss() + .WithRenderDevice(new DefaultRenderDevice + { + ViewPortWidth = 1000, + }); + var browsingContext = BrowsingContext.New(config); + var htmlParser = browsingContext.GetService(); + var document = htmlParser.ParseDocument(""); + var style = document.Body.ComputeCurrentStyle(); + Assert.AreEqual("rgba(0, 128, 0, 1)", style.GetColor()); + } + + [Test] + public void MediaRuleIsNotCalculatedIfScreenIsNotWideEnough() + { + var config = Configuration.Default + .WithCss() + .WithRenderDevice(new DefaultRenderDevice + { + ViewPortWidth = 599, + }); + var browsingContext = BrowsingContext.New(config); + var htmlParser = browsingContext.GetService(); + var document = htmlParser.ParseDocument(""); + var style = document.Body.ComputeCurrentStyle(); + Assert.AreEqual("rgba(255, 0, 0, 1)", style.GetColor()); + } } } diff --git a/src/AngleSharp.Css/CssConfigurationExtensions.cs b/src/AngleSharp.Css/CssConfigurationExtensions.cs index 5f544ed0..d0795928 100644 --- a/src/AngleSharp.Css/CssConfigurationExtensions.cs +++ b/src/AngleSharp.Css/CssConfigurationExtensions.cs @@ -18,9 +18,7 @@ public static class CssConfigurationExtensions /// The new instance with the service. public static IConfiguration WithCss(this IConfiguration configuration, CssParserOptions options = default(CssParserOptions)) { - if (configuration == null) - throw new ArgumentNullException(nameof(configuration)); - + configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); var service = new CssStylingService(); if (!configuration.Has()) @@ -57,5 +55,14 @@ public static class CssConfigurationExtensions .WithOnly(Factory.Observer) .WithOnly(service); } + + /// + /// Registers the render device for the given configuration. + /// + /// The configuration to extend. + /// The custom device to register, if any. + /// The new instance with the render device. + public static IConfiguration WithRenderDevice(this IConfiguration configuration, IRenderDevice renderDevice = null) => + configuration.WithOnly(renderDevice ?? new DefaultRenderDevice()); } } diff --git a/src/AngleSharp.Css/Dom/Internal/MediaList.cs b/src/AngleSharp.Css/Dom/Internal/MediaList.cs index ca9e3354..0081e0fe 100644 --- a/src/AngleSharp.Css/Dom/Internal/MediaList.cs +++ b/src/AngleSharp.Css/Dom/Internal/MediaList.cs @@ -41,6 +41,8 @@ internal MediaList(IBrowsingContext context) public ICssParser Parser => _context.GetService(); + public IFeatureValidatorFactory ValidatorFactory => _context.GetService(); + public String MediaText { get => this.ToCss(); @@ -54,7 +56,7 @@ public String MediaText public void SetMediaText(String value, Boolean throwOnError) { _media.Clear(); - var media = MediaParser.Parse(value); + var media = MediaParser.Parse(value, ValidatorFactory); if (media != null) { @@ -73,13 +75,13 @@ public void SetMediaText(String value, Boolean throwOnError) public void Add(String newMedium) { - var medium = MediumParser.Parse(newMedium) ?? throw new DomException(DomError.Syntax); + var medium = MediumParser.Parse(newMedium, ValidatorFactory) ?? throw new DomException(DomError.Syntax); _media.Add(medium); } public void Remove(String oldMedium) { - var medium = MediumParser.Parse(oldMedium) ?? throw new DomException(DomError.Syntax); + var medium = MediumParser.Parse(oldMedium, ValidatorFactory) ?? throw new DomException(DomError.Syntax); for (var i = 0; i < _media.Count; i++) { diff --git a/src/AngleSharp.Css/Dom/StyleCollectionExtensions.cs b/src/AngleSharp.Css/Dom/StyleCollectionExtensions.cs index b4ec369d..3c5953c4 100644 --- a/src/AngleSharp.Css/Dom/StyleCollectionExtensions.cs +++ b/src/AngleSharp.Css/Dom/StyleCollectionExtensions.cs @@ -96,10 +96,8 @@ public static ICssStyleDeclaration ComputeCascadedStyle(this StyleCollection sty #region Helpers - private static IEnumerable SortBySpecificity(this IEnumerable rules, IElement element) - { - return rules.Where(m => m.Selector.Match(element)).OrderBy(m => m.Selector.Specificity); - } + private static IEnumerable SortBySpecificity(this IEnumerable rules, IElement element) => + rules.Where(m => m.Selector.Match(element)).OrderBy(m => m.Selector.Specificity); #endregion } diff --git a/src/AngleSharp.Css/Extensions/MediaListExtensions.cs b/src/AngleSharp.Css/Extensions/MediaListExtensions.cs index 9b58d9ef..8ed669c3 100644 --- a/src/AngleSharp.Css/Extensions/MediaListExtensions.cs +++ b/src/AngleSharp.Css/Extensions/MediaListExtensions.cs @@ -27,8 +27,7 @@ public static void AssociateValidator(this IMediaFeature feature, IFeatureValida public static Boolean Validate(this IMediaFeature feature, IRenderDevice device) { - var validator = default(IFeatureValidator); - AssociatedValidators.TryGetValue(feature, out validator); + AssociatedValidators.TryGetValue(feature, out var validator); return validator?.Validate(feature, device) ?? false; } diff --git a/src/AngleSharp.Css/Parser/Micro/MediaParser.cs b/src/AngleSharp.Css/Parser/Micro/MediaParser.cs index c21c17b1..8c35872d 100644 --- a/src/AngleSharp.Css/Parser/Micro/MediaParser.cs +++ b/src/AngleSharp.Css/Parser/Micro/MediaParser.cs @@ -1,4 +1,4 @@ -namespace AngleSharp.Css.Parser +namespace AngleSharp.Css.Parser { using AngleSharp.Css.Dom; using AngleSharp.Text; @@ -7,14 +7,14 @@ static class MediaParser { - public static IEnumerable Parse(String str) + public static IEnumerable Parse(String str, IFeatureValidatorFactory factory) { var source = new StringSource(str); - var result = source.ParseMedia(); + var result = source.ParseMedia(factory); return source.IsDone ? result : null; } - public static IEnumerable ParseMedia(this StringSource source) + public static IEnumerable ParseMedia(this StringSource source, IFeatureValidatorFactory factory) { var current = source.SkipSpacesAndComments(); var media = new List(); @@ -29,7 +29,7 @@ public static IEnumerable ParseMedia(this StringSource source) source.SkipCurrentAndSpaces(); } - var medium = source.ParseMedium(); + var medium = source.ParseMedium(factory); if (medium == null) return null; diff --git a/src/AngleSharp.Css/Parser/Micro/MediumParser.cs b/src/AngleSharp.Css/Parser/Micro/MediumParser.cs index 834677d6..6eb566f9 100644 --- a/src/AngleSharp.Css/Parser/Micro/MediumParser.cs +++ b/src/AngleSharp.Css/Parser/Micro/MediumParser.cs @@ -1,4 +1,4 @@ -namespace AngleSharp.Css.Parser +namespace AngleSharp.Css.Parser { using AngleSharp.Css.Dom; using AngleSharp.Text; @@ -7,14 +7,14 @@ static class MediumParser { - public static CssMedium Parse(String str) + public static CssMedium Parse(String str, IFeatureValidatorFactory factory) { var source = new StringSource(str); - var result = source.ParseMedium(); + var result = source.ParseMedium(factory); return source.IsDone ? result : null; } - public static CssMedium ParseMedium(this StringSource source) + public static CssMedium ParseMedium(this StringSource source, IFeatureValidatorFactory factory) { source.SkipSpacesAndComments(); var ident = source.ParseIdent(); @@ -70,6 +70,8 @@ public static CssMedium ParseMedium(this StringSource source) return null; } + var validator = factory?.Create(feature.Name); + feature.AssociateValidator(validator); features.Add(feature); source.SkipCurrentAndSpaces(); var position = source.Index;