private static bool CheckPagesCounterPresence(CssDeclaration declaration) { bool pagesCounterPresent = false; // MDN: The counters() function can be used with any CSS property, but support for properties other // than content is experimental, and support for the type-or-unit parameter is sparse. // iText also does not support counter(pages) anywhere else for now if (CssConstants.CONTENT.Equals(declaration.GetProperty())) { CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(declaration.GetExpression()); CssDeclarationValueTokenizer.Token token; while ((token = tokenizer.GetNextValidToken()) != null) { if (token.IsString()) { continue; } if (token.GetValue().StartsWith(CssConstants.COUNTERS + "(")) { String paramsStr = token.GetValue().JSubstring(CssConstants.COUNTERS.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); pagesCounterPresent = pagesCounterPresent || CheckCounterFunctionParamsForPagesReferencePresence(@params); } else { if (token.GetValue().StartsWith(CssConstants.COUNTER + "(")) { String paramsStr = token.GetValue().JSubstring(CssConstants.COUNTER.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); pagesCounterPresent = pagesCounterPresent || CheckCounterFunctionParamsForPagesReferencePresence(@params); } else { if (token.GetValue().StartsWith(CssConstants.TARGET_COUNTER + "(")) { String paramsStr = token.GetValue().JSubstring(CssConstants.TARGET_COUNTER.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); pagesCounterPresent = pagesCounterPresent || (@params.Length >= TARGET_COUNTER_MIN_PARAMS_SIZE && CheckTargetCounterParamsForPageOrPagesReferencePresence (@params)); } else { if (token.GetValue().StartsWith(CssConstants.TARGET_COUNTERS + "(")) { String paramsStr = token.GetValue().JSubstring(CssConstants.TARGET_COUNTERS.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); pagesCounterPresent = pagesCounterPresent || (@params.Length >= TARGET_COUNTERS_MIN_PARAMS_SIZE && CheckTargetCounterParamsForPageOrPagesReferencePresence (@params)); } } } } } } return(pagesCounterPresent); }
/// <summary>Parses the provided linear gradient or repeating linear gradient function</summary> /// <param name="cssGradientValue">the value to parse</param> /// <param name="emValue">the current element's em value</param> /// <param name="remValue">the current element's rem value</param> /// <returns> /// the /// <see cref="iText.Kernel.Colors.Gradients.StrategyBasedLinearGradientBuilder"/> /// constructed from the parsed linear gradient /// or /// <see langword="null"/> /// if the argument value is not a linear gradient or repeating linear gradient /// function /// </returns> public static StrategyBasedLinearGradientBuilder ParseCssLinearGradient(String cssGradientValue, float emValue , float remValue) { if (IsCssLinearGradientValue(cssGradientValue)) { cssGradientValue = cssGradientValue.ToLowerInvariant().Trim(); bool isRepeating = false; String argumentsPart = null; if (cssGradientValue.StartsWith(LINEAR_GRADIENT_FUNCTION_SUFFIX)) { argumentsPart = cssGradientValue.JSubstring(LINEAR_GRADIENT_FUNCTION_SUFFIX.Length, cssGradientValue.Length - 1); isRepeating = false; } else { if (cssGradientValue.StartsWith(REPEATING_LINEAR_GRADIENT_FUNCTION_SUFFIX)) { argumentsPart = cssGradientValue.JSubstring(REPEATING_LINEAR_GRADIENT_FUNCTION_SUFFIX.Length, cssGradientValue .Length - 1); isRepeating = true; } } if (argumentsPart != null) { IList <String> argumentsList = new List <String>(); StringBuilder buff = new StringBuilder(); CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(argumentsPart); CssDeclarationValueTokenizer.Token nextToken; while ((nextToken = tokenizer.GetNextValidToken()) != null) { if (nextToken.GetType() == CssDeclarationValueTokenizer.TokenType.COMMA) { if (buff.Length != 0) { argumentsList.Add(buff.ToString().Trim()); buff = new StringBuilder(); } } else { buff.Append(" ").Append(nextToken.GetValue()); } } if (buff.Length != 0) { argumentsList.Add(buff.ToString().Trim()); } if (argumentsList.IsEmpty()) { throw new StyledXMLParserException(MessageFormatUtil.Format(StyledXMLParserException.INVALID_GRADIENT_FUNCTION_ARGUMENTS_LIST , cssGradientValue)); } return(ParseCssLinearGradient(argumentsList, isRepeating, emValue, remValue)); } } return(null); }
/// <summary>Normalizes the declaration URIs.</summary> /// <param name="declarations">the declarations</param> private void NormalizeDeclarationURIs(IList <CssDeclaration> declarations) { // This is the case when css has no location and thus urls should not be resolved against base css location if (this.uriResolver == null) { return; } foreach (CssDeclaration declaration in declarations) { if (declaration.GetExpression().Contains("url(")) { CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(declaration.GetExpression()); CssDeclarationValueTokenizer.Token token; StringBuilder normalizedDeclaration = new StringBuilder(); while ((token = tokenizer.GetNextValidToken()) != null) { String strToAppend; if (token.GetType() == CssDeclarationValueTokenizer.TokenType.FUNCTION && token.GetValue().StartsWith("url(" )) { String url = token.GetValue().Trim(); url = url.JSubstring(4, url.Length - 1).Trim(); if (CssUtils.IsBase64Data(url)) { strToAppend = token.GetValue().Trim(); } else { if (url.StartsWith("'") && url.EndsWith("'") || url.StartsWith("\"") && url.EndsWith("\"")) { url = url.JSubstring(1, url.Length - 1); } url = url.Trim(); String finalUrl = url; try { finalUrl = uriResolver.ResolveAgainstBaseUri(url).ToExternalForm(); } catch (UriFormatException) { } strToAppend = MessageFormatUtil.Format("url({0})", finalUrl); } } else { strToAppend = token.GetValue(); } if (normalizedDeclaration.Length > 0) { normalizedDeclaration.Append(' '); } normalizedDeclaration.Append(strToAppend); } declaration.SetExpression(normalizedDeclaration.ToString()); } } }
private void RunTest(String src, IList <String> tokenValues, IList <CssDeclarationValueTokenizer.TokenType> tokenTypes) { CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(src); CssDeclarationValueTokenizer.Token token = null; NUnit.Framework.Assert.IsTrue(tokenValues.Count == tokenTypes.Count, "Value and type arrays size should be equal" ); int index = 0; while ((token = tokenizer.GetNextValidToken()) != null) { NUnit.Framework.Assert.AreEqual(tokenValues[index], token.GetValue()); NUnit.Framework.Assert.AreEqual(tokenTypes[index], token.GetType()); ++index; } NUnit.Framework.Assert.IsTrue(index == tokenValues.Count); }
private TransparentColor GetColorFromAttributeValue(SvgDrawContext context, String rawColorValue, float objectBoundingBoxMargin , float parentOpacity) { if (rawColorValue == null) { return(null); } CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(rawColorValue); CssDeclarationValueTokenizer.Token token = tokenizer.GetNextValidToken(); if (token == null) { return(null); } String tokenValue = token.GetValue(); if (tokenValue.StartsWith("url(#") && tokenValue.EndsWith(")")) { Color resolvedColor = null; float resolvedOpacity = 1; String normalizedName = tokenValue.JSubstring(5, tokenValue.Length - 1).Trim(); ISvgNodeRenderer colorRenderer = context.GetNamedObject(normalizedName); if (colorRenderer is AbstractGradientSvgNodeRenderer) { resolvedColor = ((AbstractGradientSvgNodeRenderer)colorRenderer).CreateColor(context, GetObjectBoundingBox (context), objectBoundingBoxMargin, parentOpacity); } if (resolvedColor != null) { return(new TransparentColor(resolvedColor, resolvedOpacity)); } token = tokenizer.GetNextValidToken(); } // may become null after function parsing and reading the 2nd token if (token != null) { String value = token.GetValue(); if (!SvgConstants.Values.NONE.EqualsIgnoreCase(value)) { return(new TransparentColor(WebColors.GetRGBColor(value), parentOpacity * GetAlphaFromRGBA(value))); } } return(null); }
/// <summary> /// Creates a /// <see cref="CssQuotes"/> /// instance. /// </summary> /// <param name="quotesString">the quotes string</param> /// <param name="fallbackToDefault">indicates whether it's OK to fall back to the default</param> /// <returns> /// the resulting /// <see cref="CssQuotes"/> /// instance /// </returns> public static iText.StyledXmlParser.Css.Resolve.CssQuotes CreateQuotes(String quotesString, bool fallbackToDefault ) { bool error = false; List <List <String> > quotes = new List <List <String> >(2); quotes.Add(new List <String>()); quotes.Add(new List <String>()); if (quotesString != null) { if (quotesString.Equals(CommonCssConstants.NONE)) { quotes[0].Add(EMPTY_QUOTE); quotes[1].Add(EMPTY_QUOTE); return(new iText.StyledXmlParser.Css.Resolve.CssQuotes(quotes[0], quotes[1])); } CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(quotesString); CssDeclarationValueTokenizer.Token token; for (int i = 0; ((token = tokenizer.GetNextValidToken()) != null); ++i) { if (token.IsString()) { quotes[i % 2].Add(token.GetValue()); } else { error = true; break; } } if (quotes[0].Count == quotes[1].Count && !quotes[0].IsEmpty() && !error) { return(new iText.StyledXmlParser.Css.Resolve.CssQuotes(quotes[0], quotes[1])); } else { LogManager.GetLogger(typeof(iText.StyledXmlParser.Css.Resolve.CssQuotes)).Error(MessageFormatUtil.Format(iText.StyledXmlParser.LogMessageConstant .QUOTES_PROPERTY_INVALID, quotesString)); } } return(fallbackToDefault ? CreateDefaultQuotes() : null); }
/// <summary> /// Extracts shorthand properties as list of string lists from a string, where the top level /// list is shorthand property and the lower level list is properties included in shorthand property. /// </summary> /// <param name="str">the source string with shorthand properties</param> /// <returns>the list of string lists</returns> public static IList <IList <String> > ExtractShorthandProperties(String str) { IList <IList <String> > result = new List <IList <String> >(); IList <String> currentLayer = new List <String>(); CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(str); CssDeclarationValueTokenizer.Token currentToken = tokenizer.GetNextValidToken(); while (currentToken != null) { if (currentToken.GetType() == CssDeclarationValueTokenizer.TokenType.COMMA) { result.Add(currentLayer); currentLayer = new List <String>(); } else { currentLayer.Add(currentToken.GetValue()); } currentToken = tokenizer.GetNextValidToken(); } result.Add(currentLayer); return(result); }
private static bool CheckNonPagesTargetCounterPresence(CssDeclaration declaration) { bool nonPagesTargetCounterPresent = false; if (CssConstants.CONTENT.Equals(declaration.GetProperty())) { CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(declaration.GetExpression()); CssDeclarationValueTokenizer.Token token; while ((token = tokenizer.GetNextValidToken()) != null) { if (token.IsString()) { continue; } if (token.GetValue().StartsWith(CssConstants.TARGET_COUNTER + "(")) { String paramsStr = token.GetValue().JSubstring(CssConstants.TARGET_COUNTER.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); nonPagesTargetCounterPresent = nonPagesTargetCounterPresent || (@params.Length >= TARGET_COUNTER_MIN_PARAMS_SIZE && !CheckTargetCounterParamsForPageOrPagesReferencePresence(@params)); } else { if (token.GetValue().StartsWith(CssConstants.TARGET_COUNTERS + "(")) { String paramsStr = token.GetValue().JSubstring(CssConstants.TARGET_COUNTERS.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); nonPagesTargetCounterPresent = nonPagesTargetCounterPresent || (@params.Length >= TARGET_COUNTERS_MIN_PARAMS_SIZE && !CheckTargetCounterParamsForPageOrPagesReferencePresence(@params)); } } } } return(nonPagesTargetCounterPresent); }
/// <summary>Resolves content.</summary> /// <param name="styles">the styles map</param> /// <param name="contentContainer">the content container</param> /// <param name="context">the CSS context</param> /// <returns> /// a list of /// <see cref="iText.StyledXmlParser.Node.INode"/> /// instances /// </returns> internal static IList <INode> ResolveContent(IDictionary <String, String> styles, INode contentContainer, CssContext context) { String contentStr = styles.Get(CssConstants.CONTENT); IList <INode> result = new List <INode>(); if (contentStr == null || CssConstants.NONE.Equals(contentStr) || CssConstants.NORMAL.Equals(contentStr)) { return(null); } CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(contentStr); CssDeclarationValueTokenizer.Token token; CssQuotes quotes = null; while ((token = tokenizer.GetNextValidToken()) != null) { if (token.IsString()) { result.Add(new CssContentPropertyResolver.ContentTextNode(contentContainer, token.GetValue())); } else { if (token.GetValue().StartsWith(CssConstants.COUNTERS + "(")) { String paramsStr = token.GetValue().JSubstring(CssConstants.COUNTERS.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); if (@params.Length == 0) { return(ErrorFallback(contentStr)); } // Counters are denoted by case-sensitive identifiers String counterName = @params[0].Trim(); String counterSeparationStr = @params[1].Trim(); counterSeparationStr = counterSeparationStr.JSubstring(1, counterSeparationStr.Length - 1); String listStyleType = @params.Length > 2 ? @params[2].Trim() : null; CssCounterManager counterManager = context.GetCounterManager(); INode scope = contentContainer; if (CssConstants.PAGE.Equals(counterName)) { result.Add(new PageCountElementNode(false, contentContainer)); } else { if (CssConstants.PAGES.Equals(counterName)) { result.Add(new PageCountElementNode(true, contentContainer)); } else { String resolvedCounter = counterManager.ResolveCounters(counterName, counterSeparationStr, listStyleType, scope); if (resolvedCounter == null) { logger.Error(MessageFormatUtil.Format(iText.Html2pdf.LogMessageConstant.UNABLE_TO_RESOLVE_COUNTER, counterName )); } else { result.Add(new CssContentPropertyResolver.ContentTextNode(scope, resolvedCounter)); } } } } else { if (token.GetValue().StartsWith(CssConstants.COUNTER + "(")) { String paramsStr = token.GetValue().JSubstring(CssConstants.COUNTER.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); if (@params.Length == 0) { return(ErrorFallback(contentStr)); } // Counters are denoted by case-sensitive identifiers String counterName = @params[0].Trim(); String listStyleType = @params.Length > 1 ? @params[1].Trim() : null; CssCounterManager counterManager = context.GetCounterManager(); INode scope = contentContainer; if (CssConstants.PAGE.Equals(counterName)) { result.Add(new PageCountElementNode(false, contentContainer)); } else { if (CssConstants.PAGES.Equals(counterName)) { result.Add(new PageCountElementNode(true, contentContainer)); } else { String resolvedCounter = counterManager.ResolveCounter(counterName, listStyleType, scope); if (resolvedCounter == null) { logger.Error(MessageFormatUtil.Format(iText.Html2pdf.LogMessageConstant.UNABLE_TO_RESOLVE_COUNTER, counterName )); } else { result.Add(new CssContentPropertyResolver.ContentTextNode(scope, resolvedCounter)); } } } } else { if (token.GetValue().StartsWith("url(")) { IDictionary <String, String> attributes = new Dictionary <String, String>(); attributes.Put(AttributeConstants.SRC, CssUtils.ExtractUrl(token.GetValue())); //TODO: probably should add user agent styles on CssContentElementNode creation, not here. attributes.Put(AttributeConstants.STYLE, CssConstants.DISPLAY + ":" + CssConstants.INLINE_BLOCK); result.Add(new CssContentElementNode(contentContainer, TagConstants.IMG, attributes)); } else { if (CssGradientUtil.IsCssLinearGradientValue(token.GetValue())) { IDictionary <String, String> attributes = new Dictionary <String, String>(); attributes.Put(AttributeConstants.STYLE, CssConstants.BACKGROUND_IMAGE + ":" + token.GetValue() + ";" + CssConstants .HEIGHT + ":" + CssConstants.INHERIT + ";" + CssConstants.WIDTH + ":" + CssConstants.INHERIT + ";"); result.Add(new CssContentElementNode(contentContainer, TagConstants.DIV, attributes)); } else { if (token.GetValue().StartsWith("attr(") && contentContainer is CssPseudoElementNode) { int endBracket = token.GetValue().IndexOf(')'); if (endBracket > 5) { String attrName = token.GetValue().JSubstring(5, endBracket); if (attrName.Contains("(") || attrName.Contains(" ") || attrName.Contains("'") || attrName.Contains("\"")) { return(ErrorFallback(contentStr)); } IElementNode element = (IElementNode)contentContainer.ParentNode(); String value = element.GetAttribute(attrName); result.Add(new CssContentPropertyResolver.ContentTextNode(contentContainer, value == null ? "" : value)); } } else { if (token.GetValue().EndsWith("quote") && contentContainer is IStylesContainer) { if (quotes == null) { quotes = CssQuotes.CreateQuotes(styles.Get(CssConstants.QUOTES), true); } String value = quotes.ResolveQuote(token.GetValue(), context); if (value == null) { return(ErrorFallback(contentStr)); } result.Add(new CssContentPropertyResolver.ContentTextNode(contentContainer, value)); } else { if (token.GetValue().StartsWith(CssConstants.ELEMENT + "(") && contentContainer is PageMarginBoxContextNode ) { String paramsStr = token.GetValue().JSubstring(CssConstants.ELEMENT.Length + 1, token.GetValue().Length - 1); String[] @params = iText.IO.Util.StringUtil.Split(paramsStr, ","); if (@params.Length == 0) { return(ErrorFallback(contentStr)); } String name = @params[0].Trim(); String runningElementOccurrence = null; if (@params.Length > 1) { runningElementOccurrence = @params[1].Trim(); } result.Add(new PageMarginRunningElementNode(name, runningElementOccurrence)); } else { return(ErrorFallback(contentStr)); } } } } } } } } } return(result); }
private static void AddStopColors(AbstractLinearGradientBuilder builder, IList <String> argumentsList, int stopsStartIndex, float emValue, float remValue) { GradientColorStop lastCreatedStopColor = null; int lastStopIndex = argumentsList.Count - 1; for (int i = stopsStartIndex; i <= lastStopIndex; ++i) { String argument = argumentsList[i]; IList <String> elementsList = new List <String>(); CssDeclarationValueTokenizer tokenizer = new CssDeclarationValueTokenizer(argument); CssDeclarationValueTokenizer.Token nextToken; while ((nextToken = tokenizer.GetNextValidToken()) != null) { elementsList.Add(nextToken.GetValue()); } // cases: color, color + offset, color + offset + offset, offset (hint) if (elementsList.IsEmpty() || elementsList.Count > 3) { throw new StyledXMLParserException(MessageFormatUtil.Format(StyledXMLParserException.INVALID_GRADIENT_COLOR_STOP_VALUE , argument)); } if (CssUtils.IsColorProperty(elementsList[0])) { float[] rgba = CssUtils.ParseRgbaColor(elementsList[0]); if (elementsList.Count == 1) { UnitValue offset = i == stopsStartIndex ? new UnitValue(UnitValue.PERCENT, 0f) : i == lastStopIndex ? new UnitValue(UnitValue.PERCENT, 100f) : null; lastCreatedStopColor = CreateStopColor(rgba, offset); builder.AddColorStop(lastCreatedStopColor); } else { for (int j = 1; j < elementsList.Count; ++j) { if (CssUtils.IsNumericValue(elementsList[j])) { // the numeric value is invalid in linear gradient function. // So check it here as parsing method will use the default pt metric throw new StyledXMLParserException(MessageFormatUtil.Format(StyledXMLParserException.INVALID_GRADIENT_COLOR_STOP_VALUE , argument)); } UnitValue offset = CssUtils.ParseLengthValueToPt(elementsList[j], emValue, remValue); if (offset == null) { throw new StyledXMLParserException(MessageFormatUtil.Format(StyledXMLParserException.INVALID_GRADIENT_COLOR_STOP_VALUE , argument)); } lastCreatedStopColor = CreateStopColor(rgba, offset); builder.AddColorStop(lastCreatedStopColor); } } } else { // it should be a color hint case if (elementsList.Count != 1 || lastCreatedStopColor == null || lastCreatedStopColor.GetHintOffsetType() != GradientColorStop.HintOffsetType.NONE || i == lastStopIndex) { // hint is not a single value, or no color at the beginning, // or two hints in a row, or hint as a last value throw new StyledXMLParserException(MessageFormatUtil.Format(StyledXMLParserException.INVALID_GRADIENT_COLOR_STOP_VALUE , argument)); } UnitValue hint = CssUtils.ParseLengthValueToPt(elementsList[0], emValue, remValue); if (hint == null) { throw new StyledXMLParserException(MessageFormatUtil.Format(StyledXMLParserException.INVALID_GRADIENT_COLOR_STOP_VALUE , argument)); } if (hint.GetUnitType() == UnitValue.PERCENT) { lastCreatedStopColor.SetHint(hint.GetValue() / 100, GradientColorStop.HintOffsetType.RELATIVE_ON_GRADIENT); } else { lastCreatedStopColor.SetHint(hint.GetValue(), GradientColorStop.HintOffsetType.ABSOLUTE_ON_GRADIENT); } } } }