internal static bool TryGetBackgroundDeclaration(this IEnumerable <DeclarationNode> declarationAstNodes, AstNode parentAstNode, out Background backgroundNode, out BackgroundImage backgroundImageNode, out BackgroundPosition backgroundPositionNode, out DeclarationNode backgroundSize, List <string> imageReferencesInInvalidDeclarations, HashSet <string> imageReferencesToIgnore, ImageAssemblyAnalysisLog imageAssemblyAnalysisLog, string outputUnit, double outputUnitFactor, bool ignoreImagesWithNonDefaultBackgroundSize = false) { // Initialize the nodes to null backgroundNode = null; backgroundImageNode = null; backgroundPositionNode = null; backgroundSize = null; // With CSS3 multiple urls can be present in a single rule, this is not yet supported // background: url(flower.png), url(ball.png), url(grass.png) no-repeat; if (BackgroundImage.HasMultipleUrls(parentAstNode.MinifyPrint())) { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, null, FailureReason.MultipleUrls); return(false); } // This will check if the selector hash -wg-spriting: ignore. If it does we will ignore the sprite. var webGreaseSpritingProperty = declarationAstNodes.FirstOrDefault(d => d.Property == "-wg-spriting"); if (webGreaseSpritingProperty != null && webGreaseSpritingProperty.ExprNode.TermNode.StringBasedValue == "ignore") { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, null, FailureReason.SpritingIgnore); return(false); } // The list of declarations should not have the duplicate declaration // properties. Validate and get the dictionary of declarations. var declarationProperties = declarationAstNodes.LoadDeclarationPropertiesDictionary(); // The selector design is inefficient if the shorthand notation and long name is defined // in a scope of ruleset declaration, media ruleset declaration or page declaration. This // would be a great feature to add to Optimization visitor but would require a full table // scanning which is not yet implemented. // Per MSN CSS standards, the practice of defining the shorthand notation and long name // in scope of same selector is not allowed. DeclarationNode declarationAstNode; if (declarationProperties.TryGetValue(ImageAssembleConstants.Background, out declarationAstNode)) { // There should not be any short and long notation simultaneosuly used in these set of declarations. // For example: Such a list of declarations end up in inefficient CSS. // #selector // { // background:url(foo.gif); // background-image:url(../../i/D5/DF5D9B4EFD5CFF9122942A67A1EEC5.gif); // background-position:500px 500px; // background-repeat:no-repeat // } // By design, we are not computing cascade here. // TODO: RTUIT: Add support to override some of these with extra values depending on the order, or use optimization to do this when merging styles. if (declarationProperties.ContainsKey(ImageAssembleConstants.BackgroundRepeat) || declarationProperties.ContainsKey(ImageAssembleConstants.BackgroundImage) || declarationProperties.ContainsKey(ImageAssembleConstants.BackgroundPosition)) { throw new ImageAssembleException(CssStrings.DuplicateBackgroundFormatError); } // Load the model for the "background" declaration var parsedBackground = new Background(declarationAstNode, outputUnit, outputUnitFactor); //// //// The url should be present //// bool shouldIgnore; if (!parsedBackground.BackgroundImage.VerifyBackgroundUrl(parentAstNode, imageReferencesToIgnore, imageAssemblyAnalysisLog, out shouldIgnore) || shouldIgnore) { return(false); } //// //// The "no-repeat" term should be explicitly configured on the "background" declaration //// if (!parsedBackground.BackgroundRepeat.VerifyBackgroundNoRepeat()) { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackground.Url, FailureReason.BackgroundRepeatInvalid); UpdateFailedUrlsList(parsedBackground.Url, imageReferencesInInvalidDeclarations); return(false); } //// //// The background position should only be empty, x = any value and y = 0, top or px //// if (!parsedBackground.BackgroundPosition.IsVerticalSpriteCandidate()) { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackground.Url, FailureReason.IncorrectPosition); UpdateFailedUrlsList(parsedBackground.Url, imageReferencesInInvalidDeclarations); return(false); } //// Try to get the background size, returns false if we want to ignore images with background sizes and the background size is set to a non-default value. if (!TryGetBackgroundSize(ignoreImagesWithNonDefaultBackgroundSize, declarationProperties, out backgroundSize)) { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackground.Url, FailureReason.BackgroundSizeIsSetToNonDefaultValue); UpdateFailedUrlsList(parsedBackground.Url, imageReferencesInInvalidDeclarations); return(false); } backgroundNode = parsedBackground; imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackground.Url); //// SUCCESS - This is the candidate! return(true); } // Now there should be declaration for "background-image" or "background-repeat" or both if (declarationProperties.TryGetValue(ImageAssembleConstants.BackgroundImage, out declarationAstNode)) { // Load the property model for the "background-image" declaration var parsedBackgroundImage = new BackgroundImage(declarationAstNode); //// //// The url should be present //// bool shouldIgnore; if (!parsedBackgroundImage.VerifyBackgroundUrl(parentAstNode, imageReferencesToIgnore, imageAssemblyAnalysisLog, out shouldIgnore) || shouldIgnore) { return(false); } //// //// There is a "background-repeat" declaration found //// DeclarationNode backgroundRepeat; if (!declarationProperties.TryGetValue(ImageAssembleConstants.BackgroundRepeat, out backgroundRepeat)) { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackgroundImage.Url, FailureReason.NoRepeat); UpdateFailedUrlsList(parsedBackgroundImage.Url, imageReferencesInInvalidDeclarations); return(false); } //// //// Now make sure that "background-repeat" is "no-repeat" //// if (!new BackgroundRepeat(backgroundRepeat).VerifyBackgroundNoRepeat()) { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackgroundImage.Url, FailureReason.BackgroundRepeatInvalid); UpdateFailedUrlsList(parsedBackgroundImage.Url, imageReferencesInInvalidDeclarations); return(false); } //// Try to get the background size, returns false if we want to ignore images with background sizes and the background size is set to a non-default value. if (!TryGetBackgroundSize(ignoreImagesWithNonDefaultBackgroundSize, declarationProperties, out backgroundSize)) { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackgroundImage.Url, FailureReason.BackgroundSizeIsSetToNonDefaultValue); UpdateFailedUrlsList(parsedBackgroundImage.Url, imageReferencesInInvalidDeclarations); return(false); } //// //// The background position should only be empty, x = any value and y = 0, top or px //// DeclarationNode backgroundPosition; if (declarationProperties.TryGetValue(ImageAssembleConstants.BackgroundPosition, out backgroundPosition)) { // Now if there is a "background-position" declaration (optional), lets make // it should only be empty, px or left/top or right/px var parsedBackgroundPosition = new BackgroundPosition(backgroundPosition, outputUnit, outputUnitFactor); if (!parsedBackgroundPosition.IsVerticalSpriteCandidate()) { imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackgroundImage.Url, FailureReason.IncorrectPosition); UpdateFailedUrlsList(parsedBackgroundImage.Url, imageReferencesInInvalidDeclarations); return(false); } backgroundImageNode = parsedBackgroundImage; backgroundPositionNode = parsedBackgroundPosition; imageAssemblyAnalysisLog.SafeAdd(parentAstNode, parsedBackgroundImage.Url); //// SUCCESS - This is the candidate! return(true); } backgroundImageNode = parsedBackgroundImage; imageAssemblyAnalysisLog.SafeAdd(parentAstNode, backgroundImageNode.Url); //// SUCCESS - This is the candidate! return(true); } return(false); }