示例#1
0
        private static void FillStyleSheet(TextReader reader, CssStyleSheet styleSheet, Func <string, TextReader> getImport)
        {
            using (var enumerator = CssReader.Read(reader).GetEnumerator())
            {
                if (!enumerator.MoveNext())
                {
                    return;
                }
                CssRule rule;
                while (enumerator.Current.Type == CssChunkTypes.Directive &&
                       enumerator.Current.Data != null && enumerator.Current.Data.StartsWith("import "))
                {
                    var dirrective = enumerator.Current.Data;
                    var import     = dirrective.Substring(7);
                    Import(styleSheet, import, getImport);
                    enumerator.MoveNext();
                }

                while (CreateRule(styleSheet, enumerator, out rule))
                {
                    if (rule != null)
                    {
                        styleSheet.CssRules.Add(rule);
                    }
                }
                if (rule != null)
                {
                    styleSheet.CssRules.Add(rule);
                }
            }
        }
        public void Parse(CssReader reader, GradientBuilder builder)
        {
            var isRepeating    = reader.Read().Trim() == CssToken.RepeatingRadialGradient;
            var token          = reader.ReadNext().Trim();
            var internalReader = new CssReader(token, ' ');

            var flags = None;

            var(hasShape, shape)   = GetShape(internalReader);
            var(hasSize, size)     = GetSize(internalReader);
            var(hasRadius, radius) = GeRadius(internalReader, shape, ref flags);
            var(hasPos, position)  = GetPosition(internalReader, ref flags);

            builder.UseBuilder(new RadialGradientBuilder
            {
                Center      = position,
                Shape       = shape,
                Size        = size,
                RadiusX     = radius.Width,
                RadiusY     = radius.Height,
                Flags       = flags,
                IsRepeating = isRepeating
            });

            if (!hasShape && !hasSize && !hasRadius && !hasPos)
            {
                reader.Rollback();
            }
        }
示例#3
0
        public void Parse(CssReader reader, GradientBuilder builder)
        {
            var isRepeating    = reader.Read().Trim() == CssToken.RepeatingRadialGradient;
            var token          = reader.ReadNext().Trim();
            var internalReader = new CssReader(token, ' ');

            var(hasShape, shape)     = GetShape(internalReader);
            var(hasStretch, stretch) = GetStretch(internalReader);
            var(hasRadius, radius)   = GeRadius(internalReader, shape);
            var(hasPos, position)    = GetPosition(internalReader);

            builder.UseBuilder(new RadialGradientBuilder
            {
                Center      = position,
                Shape       = shape,
                Stretch     = stretch,
                Radius      = radius,
                IsRepeating = isRepeating
            });

            if (!hasShape && !hasStretch && !hasRadius && !hasPos)
            {
                reader.Rollback();
            }
        }
示例#4
0
        internal bool TryConvertNamedDirectionToAngle(string token, out double angle)
        {
            var reader = new CssReader(token, ' ');

            if (reader.CanRead && reader.Read() == "to")
            {
                var defaultVector   = Vector2.Down; // By default gradient is drawn top-down
                var directionVector = Vector2.Zero;

                reader.MoveNext();

                while (reader.CanRead)
                {
                    directionVector.SetNamedDirection(reader.Read());
                    reader.MoveNext();
                }

                angle = Vector2.Angle(ref defaultVector, ref directionVector);

                // We start rotation from Vector(0, -1) clockwise
                // If gradient ends in I or II quarter of coordinate system
                // we use angle to calculate actual rotation

                if (directionVector.X > 0)
                {
                    angle = 360 - angle;
                }

                return(true);
            }

            angle = 0;
            return(false);
        }
        private Point GetPosition(CssReader reader)
        {
            if (reader.CanRead)
            {
                var token = reader.Read().Trim();

                if (token == "at")
                {
                    var tokenX = reader.ReadNext();
                    var tokenY = reader.ReadNext();

                    var isPosX = tokenX.TryConvertOffset(out var posX);
                    var isPosY = tokenY.TryConvertOffset(out var posY);

                    var direction = Vector2.Zero;

                    if (!isPosX && !string.IsNullOrEmpty(tokenX))
                    {
                        direction.SetNamedDirection(tokenX);
                    }

                    if (!isPosY && !string.IsNullOrEmpty(tokenY))
                    {
                        direction.SetNamedDirection(tokenY);
                    }

                    return(new Point(
                               isPosX ? posX : (direction.X + 1) / 2,
                               isPosY ? posY : (direction.Y + 1) / 2));
                }
            }

            return(new Point(0.5, 0.5));
        }
        private (bool, Size) GeRadius(CssReader reader, RadialGradientShape shape, ref RadialGradientFlags flags)
        {
            if (reader.CanRead)
            {
                var size = Dimensions.Zero;

                if (shape == RadialGradientShape.Circle)
                {
                    var radiusToken = reader.Read();
                    var isRadius    = OffsetConverter.TryExtractOffset(radiusToken, out var radius);

                    if (isRadius)
                    {
                        size = new Dimensions(radius, radius);
                        reader.MoveNext();
                    }
                }

                if (shape == RadialGradientShape.Ellipse)
                {
                    var radiusHToken = reader.Read();
                    var radiusVToken = reader.ReadNext();

                    var isRadiusH = OffsetConverter.TryExtractOffset(radiusHToken, out var radiusH);
                    var isRadiusV = OffsetConverter.TryExtractOffset(radiusVToken, out var radiusV);

                    if (isRadiusH && isRadiusV)
                    {
                        size = new Dimensions(radiusH, radiusV);
                        reader.MoveNext();
                    }
                    else
                    {
                        // Revert radiusVToken
                        reader.Rollback();
                    }
                }

                if (size != Dimensions.Zero)
                {
                    if (size.Width.Type == OffsetType.Proportional)
                    {
                        FlagsHelper.Set(ref flags, WidthProportional);
                    }

                    if (size.Height.Type == OffsetType.Proportional)
                    {
                        FlagsHelper.Set(ref flags, HeightProportional);
                    }

                    return(true, new Size(size.Width.Value, size.Height.Value));
                }
            }

            // Value -1 means undefined for RadialGradientShader
            return(false, new Size(-1, -1));
        }
        public void GetColorString_ReadFromCssReader_CorrectColorStringReturned(string colorInCss)
        {
            // Arrange
            var definition = new ColorChannelDefinition();
            var reader     = new CssReader(colorInCss);

            // Act
            var colorInString = definition.GetColorString(reader);

            // Assert
            colorInString.Should().Be(colorInCss);
        }
        public void Parse_HslAndHsla_WithDoubleValues_NoExceptionsThrown(string color)
        {
            // Arrange
            var reader     = new CssReader(color);
            var builder    = new GradientBuilder();
            var definition = new ColorChannelDefinition();

            // Act
            Action action = () => definition.Parse(reader, builder);

            // Assert
            action.Should().NotThrow <Exception>();
        }
        public void Parse(CssReader reader, LinearGradientBuilder builder)
        {
            var color = (Color)ColorConverter.ConvertFromInvariantString(GetColorString(reader));

            if (TryConvertPercentToOffset(reader.ReadNext(), out var offset))
            {
                builder.AddStop(color, offset);
            }
            else
            {
                builder.AddStop(color);
                reader.Rollback();
            }
        }
        public void Parse(CssReader reader, GradientBuilder builder)
        {
            var isRepeating = reader.Read().Trim() == CssToken.RepeatingRadialGradient;

            var token          = reader.ReadNext().Trim();
            var internalReader = new CssReader(token, ' ');

            var shape     = GetShape(internalReader);
            var shapeSize = GetShapeSize(internalReader);

            var(position, flags) = GetPositionWithFlags(internalReader);

            builder.AddRadialGradient(position, shape, shapeSize, flags, isRepeating);
        }
        public void Parse(CssReader reader, GradientBuilder builder)
        {
            var parts = reader.Read().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            var color = (Color)ColorConverter.ConvertFromInvariantString(parts[0]);

            if (parts.TryConvertOffsets(out var offsets))
            {
                builder.AddStops(color, offsets);
            }
            else
            {
                builder.AddStop(color);
            }
        }
        private RadialGradientShape GetShape(CssReader reader)
        {
            if (reader.CanRead)
            {
                var token = reader.Read().Trim();

                if (Enum.TryParse <RadialGradientShape>(token, true, out var shape))
                {
                    reader.MoveNext();
                    return(shape);
                }
            }

            return(RadialGradientShape.Ellipse);
        }
示例#13
0
        public void Parse(CssReader reader, GradientBuilder builder)
        {
            var parts   = reader.Read().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            var color   = GetNamedColor(parts[0]);
            var offsets = GetOffsets(parts);

            if (offsets.Any())
            {
                builder.AddStops(color, offsets);
            }
            else
            {
                builder.AddStop(color);
            }
        }
        private RadialGradientSize GetShapeSize(CssReader reader)
        {
            if (reader.CanRead)
            {
                var token = reader.Read().Replace("-", "").Trim();

                if (Enum.TryParse <RadialGradientSize>(token, true, out var shapeSize))
                {
                    reader.MoveNext();
                    return(shapeSize);
                }
            }

            return(RadialGradientSize.FarthestCorner);
        }
示例#15
0
        private (bool, RadialGradientStretch) GetStretch(CssReader reader)
        {
            if (reader.CanRead)
            {
                var token = reader.Read().Replace("-", "").Trim();

                if (Enum.TryParse <RadialGradientStretch>(token, true, out var stretch))
                {
                    reader.MoveNext();
                    return(true, stretch);
                }
            }

            return(false, RadialGradientStretch.FarthestCorner);
        }
        private (Point, RadialGradientFlags) GetPositionWithFlags(CssReader reader)
        {
            if (reader.CanRead)
            {
                var token = reader.Read().Trim();

                if (token == "at")
                {
                    var tokenX = reader.ReadNext();
                    var tokenY = reader.ReadNext();

                    var isPosX = OffsetConverter.TryExtractOffset(tokenX, out var posX);
                    var isPosY = OffsetConverter.TryExtractOffset(tokenY, out var posY);

                    var direction = Vector2.Zero;

                    if (!isPosX && !string.IsNullOrEmpty(tokenX))
                    {
                        direction.SetNamedDirection(tokenX);
                    }

                    if (!isPosY && !string.IsNullOrEmpty(tokenY))
                    {
                        direction.SetNamedDirection(tokenY);
                    }

                    var flags = None;

                    if (!isPosX || posX.Type == OffsetType.Proportional)
                    {
                        flags |= XProportional;
                    }

                    if (!isPosY || posY.Type == OffsetType.Proportional)
                    {
                        flags |= YProportional;
                    }

                    var center = new Point(
                        isPosX ? posX.Value : (direction.X + 1) / 2,
                        isPosY ? posY.Value : (direction.Y + 1) / 2);

                    return(center, flags);
                }
            }

            return(new Point(0.5, 0.5), PositionProportional);
        }
        private (bool, Point) GetPosition(CssReader reader, ref RadialGradientFlags flags)
        {
            if (reader.CanRead)
            {
                var token = reader.Read().Trim();

                if (token == "at")
                {
                    var tokenX = reader.ReadNext();
                    var tokenY = reader.ReadNext();

                    var isPosX = OffsetConverter.TryExtractOffset(tokenX, out var posX);
                    var isPosY = OffsetConverter.TryExtractOffset(tokenY, out var posY);

                    var direction = Vector2.Zero;

                    if (!isPosX && !string.IsNullOrEmpty(tokenX))
                    {
                        direction.SetNamedDirection(tokenX);
                    }

                    if (!isPosY && !string.IsNullOrEmpty(tokenY))
                    {
                        direction.SetNamedDirection(tokenY);
                    }

                    if (!isPosX || posX.Type == OffsetType.Proportional)
                    {
                        FlagsHelper.Set(ref flags, XProportional);
                    }

                    if (!isPosY || posY.Type == OffsetType.Proportional)
                    {
                        FlagsHelper.Set(ref flags, YProportional);
                    }

                    var center = new Point(
                        isPosX ? posX.Value : (direction.X + 1) / 2,
                        isPosY ? posY.Value : (direction.Y + 1) / 2);

                    return(true, center);
                }
            }

            FlagsHelper.Set(ref flags, PositionProportional);
            return(false, new Point(0.5, 0.5));
        }
        public void Parse(CssReader reader, GradientBuilder builder)
        {
            var colorString = GetColorString(reader);
            var color       = (Color)ColorConverter.ConvertFromInvariantString(colorString);
            var parts       = reader.ReadNext().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            var offsets     = GetOffsets(parts);

            if (offsets.Any())
            {
                builder.AddStops(color, offsets);
            }
            else
            {
                builder.AddStop(color);
                reader.Rollback();
            }
        }
示例#19
0
        private (bool, Dimensions) GeRadius(CssReader reader, RadialGradientShape shape)
        {
            if (reader.CanRead)
            {
                var size = Dimensions.Zero;

                if (shape == RadialGradientShape.Circle)
                {
                    var radiusToken = reader.Read();
                    var isRadius    = Offset.TryParseWithUnit(radiusToken, out var radius);

                    if (isRadius)
                    {
                        size = new Dimensions(radius, radius);
                        reader.MoveNext();
                    }
                }

                if (shape == RadialGradientShape.Ellipse)
                {
                    var radiusHToken = reader.Read();
                    var radiusVToken = reader.ReadNext();

                    var isRadiusH = Offset.TryParseWithUnit(radiusHToken, out var radiusH);
                    var isRadiusV = Offset.TryParseWithUnit(radiusVToken, out var radiusV);

                    if (isRadiusH && isRadiusV)
                    {
                        size = new Dimensions(radiusH, radiusV);
                        reader.MoveNext();
                    }
                    else
                    {
                        // Revert radiusVToken
                        reader.Rollback();
                    }
                }

                if (size != Dimensions.Zero)
                {
                    return(true, size);
                }
            }

            return(false, Dimensions.Zero);
        }
示例#20
0
        public void Parse(CssReader reader, LinearGradientBuilder builder)
        {
            var parts = reader.Read().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            var color = parts.Length > 0
                ? (Color)ColorConverter.ConvertFromInvariantString(parts[0])
                : Color.Black;

            if (parts.Length > 1 && TryConvertPercentToOffset(parts[1], out var offset))
            {
                builder.AddStop(color, offset);
            }
            else
            {
                builder.AddStop(color);
            }
        }
示例#21
0
        public void Parse(CssReader reader, LinearGradientBuilder builder)
        {
            var direction = reader.ReadNext().Trim();

            if (TryConvertDegreeToAngle(direction, out var degreeToAngle))
            {
                builder.AddGradient(degreeToAngle);
            }
            else if (TryConvertNamedDirectionToAngle(direction, out var directionToAngle))
            {
                builder.AddGradient(directionToAngle);
            }
            else
            {
                builder.AddGradient(0);
                reader.Rollback();
            }
        }
示例#22
0
        public void Parse(CssReader reader, GradientBuilder builder)
        {
            var repeating = reader.Read().Trim() == CssToken.RepeatingLinearGradient;
            var direction = reader.ReadNext().Trim();
            var angle     = 0d;

            var hasAngle = TryConvertDegreeToAngle(direction, out angle) ||
                           TryConvertTurnToAngle(direction, out angle) ||
                           TryConvertNamedDirectionToAngle(direction, out angle);

            if (hasAngle)
            {
                builder.AddLinearGradient(angle, repeating);
            }
            else
            {
                builder.AddLinearGradient(0, repeating);
                reader.Rollback();
            }
        }
示例#23
0
        public void Parse(CssReader reader, GradientBuilder builder)
        {
            var repeating = reader.Read().Trim() == CssToken.RepeatingLinearGradient;
            var direction = reader.ReadNext().Trim();
            var angle     = 0d;

            var hasAngle = TryConvertDegreeToAngle(direction, out angle) ||
                           TryConvertTurnToAngle(direction, out angle) ||
                           TryConvertNamedDirectionToAngle(direction, out angle);

            builder.UseBuilder(new LinearGradientBuilder
            {
                Angle       = angle,
                IsRepeating = repeating
            });

            if (!hasAngle)
            {
                reader.Rollback();
            }
        }
        public void Parse_ValidGradientCss_ExpectedGradientReturned(string css, LinearGradient expectedGradient)
        {
            // Arrange
            var reader     = new CssReader(css);
            var builder    = new GradientBuilder();
            var definition = new LinearGradientDefinition();

            // Act
            definition.Parse(reader, builder);

            // Assert
            var result = builder.Build();

            using (new AssertionScope())
            {
                result.Should().HaveCount(1);
                var linearGradient = result[0] as LinearGradient;
                linearGradient.Should().NotBeNull();
                linearGradient.Should().BeEquivalentTo(expectedGradient);
            }
        }
        public void Parse_ValidColor_SingleStopWithColorAndOffset(string color, Color expectedColor, float expectedOffset)
        {
            // Arrange
            var reader     = new CssReader(color);
            var builder    = new LinearGradientBuilder();
            var definition = new ColorChannelDefinition();

            // Act
            definition.Parse(reader, builder);

            // Assert
            var result = builder.Build();

            using (new AssertionScope())
            {
                var stops = result.SelectMany(x => x.Stops).ToArray();
                stops.Should().HaveCount(1);

                stops[0].Color.Should().Be(expectedColor);
                stops[0].Offset.Should().Be(expectedOffset);
            }
        }
        internal string GetColorString(CssReader reader)
        {
            var token   = reader.Read().Trim();
            var builder = new StringBuilder(token);

            builder.Append('(');
            builder.Append(reader.ReadNext());
            builder.Append(',');
            builder.Append(reader.ReadNext());
            builder.Append(',');
            builder.Append(reader.ReadNext());

            if (token == CssToken.Rgba || token == CssToken.Hsla)
            {
                builder.Append(',');
                builder.Append(reader.ReadNext());
            }

            builder.Append(')');

            return(builder.ToString());
        }
示例#27
0
        private (bool, Position) GetPosition(CssReader reader)
        {
            if (reader.CanRead)
            {
                var token = reader.Read().Trim();

                if (token == "at")
                {
                    var tokenX = reader.ReadNext();
                    var tokenY = reader.ReadNext();

                    var isPosX = Offset.TryParseWithUnit(tokenX, out var posX);
                    var isPosY = Offset.TryParseWithUnit(tokenY, out var posY);

                    var direction = Vector2.Zero;

                    if (!isPosX && !string.IsNullOrEmpty(tokenX))
                    {
                        direction.SetNamedDirection(tokenX);
                    }

                    if (!isPosY && !string.IsNullOrEmpty(tokenY))
                    {
                        direction.SetNamedDirection(tokenY);
                    }

                    var center = new Position(
                        isPosX ? posX : Offset.Prop((direction.X + 1) / 2),
                        isPosY ? posY : Offset.Prop((direction.Y + 1) / 2));

                    return(true, center);
                }
            }

            return(false, Position.Prop(0.5, 0.5));
        }
示例#28
0
        public static void FillStyle(CssStyleDeclaration style, string str)
        {
            if (str[0] != '{')
            {
                str = '{' + str;
            }
            str = "toskip" + str;

            if (str.Last() != '}')
            {
                str += '}';
            }

            using (var enumerator = CssReader.Read(new StringReader(str)).GetEnumerator())
            {
                //skip selector
                while (enumerator.MoveNext() && enumerator.Current.Type == CssChunkTypes.Selector)
                {
                    ;
                }

                FillStyle(style, enumerator);
            }
        }
示例#29
0
        public void ReadCss(string css, string result)
        {
            var res = CssReader.Read(new StringReader(css)).Select(x => x.Type.ToString() + ":" + (x.Data ?? "")).ToArray();

            Assert.AreEqual(result, string.Join(" ", res));
        }