private SpecifiedDimensionSummary ProcessAnyBorderChanges(StylePropertyValue property, SpecifiedDimensionSummary dimensionsSummary) { if (property == null) { throw new ArgumentNullException("property"); } if (dimensionsSummary == null) { throw new ArgumentNullException("dimensionsSummary"); } // Address the "border:none" case, this is the only property / value combination that can affect width without specifying dimensions if (property.Property.Value.Equals("border", StringComparison.InvariantCultureIgnoreCase) && property.ValueSegments.Any(v => v.Equals("none", StringComparison.InvariantCultureIgnoreCase))) { return(new SpecifiedDimensionSummary(null, null, null, null)); } // Border widths can be specified with {value}{unit} or by a predefined width string (eg. "thin"), to take this complication out of the // picture any pre-defined width strings are replaced with "4px" before trying to extract measurements values from the property's value var propertyWithPreDefinedWidthReplaced = new StylePropertyValue( property.Property, property.ValueSegments.Select(s => ValueIsPreDefinedWidthValue(s) ? "4px" : s), property.SourceLineIndex ); var measurements = propertyWithPreDefinedWidthReplaced.GetValueSectionsThatAreMeasurements().ToArray(); if (!measurements.Any()) { return(dimensionsSummary); } if (property.Property.Value.Equals("border-top", StringComparison.InvariantCultureIgnoreCase) || property.Property.Value.Equals("border-top-width", StringComparison.InvariantCultureIgnoreCase)) { return(new SpecifiedDimensionSummary( (measurements.First().Value == 0) ? null : property, dimensionsSummary.PropertyWithNonZeroRightValueIfAny, dimensionsSummary.PropertyWithNonZeroBottomValueIfAny, dimensionsSummary.PropertyWithNonZeroLeftValueIfAny )); } else if (property.Property.Value.Equals("border-right", StringComparison.InvariantCultureIgnoreCase) || property.Property.Value.Equals("border-right-width", StringComparison.InvariantCultureIgnoreCase)) { return(new SpecifiedDimensionSummary( dimensionsSummary.PropertyWithNonZeroTopValueIfAny, (measurements.First().Value == 0) ? null : property, dimensionsSummary.PropertyWithNonZeroBottomValueIfAny, dimensionsSummary.PropertyWithNonZeroLeftValueIfAny )); } else if (property.Property.Value.Equals("border-bottom", StringComparison.InvariantCultureIgnoreCase) || property.Property.Value.Equals("border-bottom-width", StringComparison.InvariantCultureIgnoreCase)) { return(new SpecifiedDimensionSummary( dimensionsSummary.PropertyWithNonZeroTopValueIfAny, dimensionsSummary.PropertyWithNonZeroRightValueIfAny, (measurements.First().Value == 0) ? null : property, dimensionsSummary.PropertyWithNonZeroLeftValueIfAny )); } else if (property.Property.Value.Equals("border-left", StringComparison.InvariantCultureIgnoreCase) || property.Property.Value.Equals("border-left-width", StringComparison.InvariantCultureIgnoreCase)) { return(new SpecifiedDimensionSummary( dimensionsSummary.PropertyWithNonZeroTopValueIfAny, dimensionsSummary.PropertyWithNonZeroRightValueIfAny, dimensionsSummary.PropertyWithNonZeroBottomValueIfAny, (measurements.First().Value == 0) ? null : property )); } else if (property.Property.Value.Equals("border", StringComparison.InvariantCultureIgnoreCase)) { // The "border" property can only specify a single dimension which applies to all sides (unlike "border-width", see below) return(new SpecifiedDimensionSummary( (measurements.First().Value == 0) ? null : property, (measurements.First().Value == 0) ? null : property, (measurements.First().Value == 0) ? null : property, (measurements.First().Value == 0) ? null : property )); } else if (!property.Property.Value.Equals("border-width", StringComparison.InvariantCultureIgnoreCase)) { return(dimensionsSummary); } // The "border-width" property is like "padding" and may have between and and four dimensions var topValue = measurements[0].Value; var rightValue = (measurements.Length > 1) ? measurements[1].Value : topValue; var bottomValue = (measurements.Length > 2) ? measurements[2].Value : topValue; var leftValue = (measurements.Length > 3) ? measurements[3].Value : rightValue; return(new SpecifiedDimensionSummary( (topValue == 0) ? null : property, (rightValue == 0) ? null : property, (bottomValue == 0) ? null : property, (leftValue == 0) ? null : property )); }
public IEnumerable <BrokenRuleEncounteredException> GetAnyBrokenRules(IEnumerable <ICSSFragment> fragments) { if (fragments == null) { throw new ArgumentNullException("fragments"); } foreach (var fragment in fragments) { var containerFragment = fragment as ContainerFragment; if (containerFragment == null) { continue; } // Try to determine whether a width has been explicitly set // - If there are multiple then the last one will be applied by the browser, so consider that (if any have "!important" specified then they // may override, so the styles are ordered so that those without "!important" appear first and then those that do, it is the last entry // of this set that we want) var propertyValues = containerFragment.ChildFragments .Select((f, i) => new { Fragment = f, Index = i }) .Where(f => f.Fragment is StylePropertyValue) .Select(f => new { PropertyValueFragment = (StylePropertyValue)f.Fragment, Index = f.Index }) .OrderBy(f => f.PropertyValueFragment.ValueSegments.Any(v => v.Equals("!important", StringComparison.InvariantCultureIgnoreCase)) ? 1 : 0) .ThenBy(f => f.Index) .Select(f => f.PropertyValueFragment); var lastWidthPropertyIfAny = propertyValues.LastOrDefault(p => p.Property.Value.Equals("width", StringComparison.InvariantCultureIgnoreCase)); var isWidthDefined = ( (lastWidthPropertyIfAny != null) && !!lastWidthPropertyIfAny.GetValueSectionsThatAreMeasurements().Any() ); // If a width has been explicitly set then ensure that no properties are present that violate this rule (2014-08-28: Unless "border-box" // has been set for the "box-sizing" property and the confirmity setting has been enabled which allows this). Requiring the "border-box" // style to appear within any block that requires it means it's very easy to tell at a glance whether the block requires a modern browser // (in this case, that means *not* IE7, since IE7 doesn't support "box-sizing: border-box"). if (isWidthDefined) { var lastBorderBoxPropertyIfAny = propertyValues.LastOrDefault(p => p.Property.Value.Equals("box-sizing", StringComparison.InvariantCultureIgnoreCase)); bool isBorderBoxSizingSpecified; if (lastBorderBoxPropertyIfAny == null) { isBorderBoxSizingSpecified = false; } else { var concatenatedPropertyValue = string.Join(", ", lastBorderBoxPropertyIfAny.ValueSegments); isBorderBoxSizingSpecified = concatenatedPropertyValue.Equals("border-box", StringComparison.InvariantCultureIgnoreCase) || concatenatedPropertyValue.Equals("border-box !important", StringComparison.InvariantCultureIgnoreCase); } if (!isBorderBoxSizingSpecified || ((_conformity & ConformityOptions.IgnoreRuleIfBorderBoxSizingRulePresent) == 0)) { var paddingDimensions = new SpecifiedDimensionSummary(null, null, null, null); var borderDimensions = new SpecifiedDimensionSummary(null, null, null, null); { foreach (var property in propertyValues) { paddingDimensions = ProcessAnyPaddingChanges(property, paddingDimensions); borderDimensions = ProcessAnyBorderChanges(property, paddingDimensions); } } // Check whether any property has been identified as setting a border or padding dimension // - Unless ConformityOptions.Strict behaviour is enabled, ignore the vertial (Top/Bottom) values, the horizontal // ones are of greater importance in relation to width var invalidProperty = ((_conformity == ConformityOptions.Strict) ? paddingDimensions.PropertyWithNonZeroTopValueIfAny : null) ?? paddingDimensions.PropertyWithNonZeroRightValueIfAny ?? ((_conformity == ConformityOptions.Strict) ? paddingDimensions.PropertyWithNonZeroBottomValueIfAny : null) ?? paddingDimensions.PropertyWithNonZeroLeftValueIfAny ?? ((_conformity == ConformityOptions.Strict) ? borderDimensions.PropertyWithNonZeroTopValueIfAny : null) ?? borderDimensions.PropertyWithNonZeroRightValueIfAny ?? ((_conformity == ConformityOptions.Strict) ? borderDimensions.PropertyWithNonZeroBottomValueIfAny : null) ?? borderDimensions.PropertyWithNonZeroLeftValueIfAny; if (invalidProperty != null) { yield return(new BorderAndPaddingMayNotBeCombinedWithWidthException(invalidProperty)); } } } foreach (var brokenRule in GetAnyBrokenRules(containerFragment.ChildFragments)) { yield return(brokenRule); } } }
private SpecifiedDimensionSummary ProcessAnyPaddingChanges(StylePropertyValue property, SpecifiedDimensionSummary dimensionsSummary) { if (property == null) { throw new ArgumentNullException("property"); } if (dimensionsSummary == null) { throw new ArgumentNullException("dimensionsSummary"); } var measurements = property.GetValueSectionsThatAreMeasurements().ToArray(); if (!measurements.Any()) { return(dimensionsSummary); } if (property.Property.Value.Equals("padding-top", StringComparison.InvariantCultureIgnoreCase)) { return(new SpecifiedDimensionSummary( (measurements.First().Value == 0) ? null : property, dimensionsSummary.PropertyWithNonZeroRightValueIfAny, dimensionsSummary.PropertyWithNonZeroBottomValueIfAny, dimensionsSummary.PropertyWithNonZeroLeftValueIfAny )); } else if (property.Property.Value.Equals("padding-right", StringComparison.InvariantCultureIgnoreCase)) { return(new SpecifiedDimensionSummary( dimensionsSummary.PropertyWithNonZeroTopValueIfAny, (measurements.First().Value == 0) ? null : property, dimensionsSummary.PropertyWithNonZeroBottomValueIfAny, dimensionsSummary.PropertyWithNonZeroLeftValueIfAny )); } else if (property.Property.Value.Equals("padding-bottom", StringComparison.InvariantCultureIgnoreCase)) { return(new SpecifiedDimensionSummary( dimensionsSummary.PropertyWithNonZeroTopValueIfAny, dimensionsSummary.PropertyWithNonZeroRightValueIfAny, (measurements.First().Value == 0) ? null : property, dimensionsSummary.PropertyWithNonZeroLeftValueIfAny )); } else if (property.Property.Value.Equals("padding-left", StringComparison.InvariantCultureIgnoreCase)) { return(new SpecifiedDimensionSummary( dimensionsSummary.PropertyWithNonZeroTopValueIfAny, dimensionsSummary.PropertyWithNonZeroRightValueIfAny, dimensionsSummary.PropertyWithNonZeroBottomValueIfAny, (measurements.First().Value == 0) ? null : property )); } else if (!property.Property.Value.Equals("padding", StringComparison.InvariantCultureIgnoreCase)) { return(dimensionsSummary); } // The "padding" property may have one or four dimensions specified // - If only one then all sides have that value // - If two then the settings are for top/bottom and left/right // - If three then the settingss are for top, left/right, bottom // - If four then the settings are for top, right, bottom, left var topValue = measurements[0].Value; var rightValue = (measurements.Length > 1) ? measurements[1].Value : topValue; var bottomValue = (measurements.Length > 2) ? measurements[2].Value : topValue; var leftValue = (measurements.Length > 3) ? measurements[3].Value : rightValue; return(new SpecifiedDimensionSummary( (topValue == 0) ? null : property, (rightValue == 0) ? null : property, (bottomValue == 0) ? null : property, (leftValue == 0) ? null : property )); }