/// <summary>Resolves content and counter(s) styles of a node given the passed context.</summary>
        /// <param name="node">the node</param>
        /// <param name="context">the CSS context (RootFontSize, etc.)</param>
        public virtual void ResolveContentAndCountersStyles(INode node, CssContext context)
        {
            IDictionary <String, String> elementStyles = ResolveElementsStyles(node);

            CounterProcessorUtil.ProcessCounters(elementStyles, context);
            ResolveContentProperty(elementStyles, node, context);
        }
Exemple #2
0
 /// <summary>Check if a pages counter is mentioned.</summary>
 /// <param name="styleSheet">the stylesheet to analyze</param>
 /// <param name="cssContext">the CSS context</param>
 private void CheckIfPagesCounterMentioned(CssStyleSheet styleSheet, CssContext cssContext)
 {
     // The presence of counter(pages) means that theoretically relayout may be needed.
     // We don't know it yet because that selector might not even be used, but
     // when we know it for sure, it's too late because the Document is created right in the start.
     if (CssStyleSheetAnalyzer.CheckPagesCounterPresence(styleSheet))
     {
         cssContext.SetPagesCounterPresent(true);
     }
 }
 /// <summary>Check if a pages counter is mentioned.</summary>
 /// <param name="cssContents">the CSS contents</param>
 /// <param name="cssContext">the CSS context</param>
 private void CheckIfPagesCounterMentioned(String cssContents, CssContext cssContext)
 {
     // TODO more efficient (avoid searching in text string) and precise (e.g. skip spaces) check during the parsing.
     if (cssContents.Contains("counter(pages)") || cssContents.Contains("counters(pages"))
     {
         // The presence of counter(pages) means that theoretically relayout may be needed.
         // We don't know it yet because that selector might not even be used, but
         // when we know it for sure, it's too late because the Document is created right in the start.
         cssContext.SetPagesCounterPresent(true);
     }
 }
        public virtual void ResolveContentTargetCounterNotPageTest()
        {
            IDictionary <String, String> styles = new Dictionary <String, String>();

            styles.Put(CssConstants.CONTENT, "target-counter(url('#some_target'), some_counter)");
            CssContext    context = new CssContext();
            IList <INode> result  = CssContentPropertyResolver.ResolveContent(styles, null, context);

            NUnit.Framework.Assert.IsNotNull(result);
            NUnit.Framework.Assert.AreEqual(1, result.Count);
            NUnit.Framework.Assert.IsTrue(result[0] is ITextNode);
        }
        public virtual void ResolveContentInvalidParamsTest()
        {
            IDictionary <String, String> styles = new Dictionary <String, String>();

            styles.Put(CssConstants.CONTENT, "target-counter(url('#some_target'))");
            CssContext    context = new CssContext();
            IList <INode> result  = CssContentPropertyResolver.ResolveContent(styles, null, context);

            NUnit.Framework.Assert.IsNull(result);
            styles.Put(CssConstants.CONTENT, "target-counters(url('#some_target'), some_counter)");
            result = CssContentPropertyResolver.ResolveContent(styles, null, context);
            NUnit.Framework.Assert.IsNull(result);
            styles.Put(CssConstants.CONTENT, "counter()");
            result = CssContentPropertyResolver.ResolveContent(styles, null, context);
            NUnit.Framework.Assert.IsNull(result);
            styles.Put(CssConstants.CONTENT, "counters(some_counter)");
            result = CssContentPropertyResolver.ResolveContent(styles, null, context);
            NUnit.Framework.Assert.IsNull(result);
        }
Exemple #6
0
        /// <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);
        }
Exemple #7
0
        /// <summary>Collects CSS declarationss.</summary>
        /// <param name="rootNode">the root node</param>
        /// <param name="resourceResolver">the resource resolver</param>
        /// <param name="cssContext">the CSS context</param>
        private void CollectCssDeclarations(INode rootNode, ResourceResolver resourceResolver, CssContext cssContext
                                            )
        {
            cssStyleSheet = new CssStyleSheet();
            LinkedList <INode> q = new LinkedList <INode>();

            q.Add(rootNode);
            while (!q.IsEmpty())
            {
                INode currentNode = q.JGetFirst();
                q.RemoveFirst();
                if (currentNode is IElementNode)
                {
                    IElementNode headChildElement = (IElementNode)currentNode;
                    if (TagConstants.STYLE.Equals(headChildElement.Name()))
                    {
                        if (currentNode.ChildNodes().Count > 0 && currentNode.ChildNodes()[0] is IDataNode)
                        {
                            String        styleData  = ((IDataNode)currentNode.ChildNodes()[0]).GetWholeData();
                            CssStyleSheet styleSheet = CssStyleSheetParser.Parse(styleData);
                            styleSheet = WrapStyleSheetInMediaQueryIfNecessary(headChildElement, styleSheet);
                            cssStyleSheet.AppendCssStyleSheet(styleSheet);
                        }
                    }
                    else
                    {
                        if (CssUtils.IsStyleSheetLink(headChildElement))
                        {
                            String styleSheetUri = headChildElement.GetAttribute(AttributeConstants.HREF);
                            try {
                                using (Stream stream = resourceResolver.RetrieveResourceAsInputStream(styleSheetUri)) {
                                    if (stream != null)
                                    {
                                        CssStyleSheet styleSheet = CssStyleSheetParser.Parse(stream, resourceResolver.ResolveAgainstBaseUri(styleSheetUri
                                                                                                                                            ).ToExternalForm());
                                        styleSheet = WrapStyleSheetInMediaQueryIfNecessary(headChildElement, styleSheet);
                                        cssStyleSheet.AppendCssStyleSheet(styleSheet);
                                    }
                                }
                            }
                            catch (Exception exc) {
                                ILog logger = LogManager.GetLogger(typeof(iText.Html2pdf.Css.Resolve.DefaultCssResolver));
                                logger.Error(iText.Html2pdf.LogMessageConstant.UNABLE_TO_PROCESS_EXTERNAL_CSS_FILE, exc);
                            }
                        }
                    }
                }
                foreach (INode child in currentNode.ChildNodes())
                {
                    if (child is IElementNode)
                    {
                        q.Add(child);
                    }
                }
            }
            CheckIfPagesCounterMentioned(cssStyleSheet, cssContext);
        }
Exemple #8
0
 /// <summary>Resolves a content property.</summary>
 /// <param name="styles">the styles map</param>
 /// <param name="contentContainer">the content container</param>
 /// <param name="context">the CSS context</param>
 private void ResolveContentProperty(IDictionary <String, String> styles, INode contentContainer, CssContext
                                     context)
 {
     if (contentContainer is CssPseudoElementNode || contentContainer is PageMarginBoxContextNode)
     {
         IList <INode> resolvedContent = CssContentPropertyResolver.ResolveContent(styles, contentContainer, context
                                                                                   );
         if (resolvedContent != null)
         {
             foreach (INode child in resolvedContent)
             {
                 contentContainer.AddChild(child);
             }
         }
     }
 }
Exemple #9
0
        /* (non-Javadoc)
         * @see com.itextpdf.html2pdf.css.resolve.ICssResolver#resolveStyles(com.itextpdf.html2pdf.html.node.INode, com.itextpdf.html2pdf.css.resolve.CssContext)
         */
        private IDictionary <String, String> ResolveStyles(INode element, CssContext context)
        {
            IList <CssRuleSet> ruleSets = new List <CssRuleSet>();

            ruleSets.Add(new CssRuleSet(null, UserAgentCss.GetStyles(element)));
            if (element is IElementNode)
            {
                ruleSets.Add(new CssRuleSet(null, HtmlStylesToCssConverter.Convert((IElementNode)element)));
            }
            ruleSets.AddAll(cssStyleSheet.GetCssRuleSets(element, deviceDescription));
            if (element is IElementNode)
            {
                String styleAttribute = ((IElementNode)element).GetAttribute(AttributeConstants.STYLE);
                if (styleAttribute != null)
                {
                    ruleSets.Add(new CssRuleSet(null, CssRuleSetParser.ParsePropertyDeclarations(styleAttribute)));
                }
            }
            IDictionary <String, String> elementStyles = CssStyleSheet.ExtractStylesFromRuleSets(ruleSets);

            if (CssConstants.CURRENTCOLOR.Equals(elementStyles.Get(CssConstants.COLOR)))
            {
                // css-color-3/#currentcolor:
                // If the ‘currentColor’ keyword is set on the ‘color’ property itself, it is treated as ‘color: inherit’.
                elementStyles.Put(CssConstants.COLOR, CssConstants.INHERIT);
            }
            String parentFontSizeStr = null;

            if (element.ParentNode() is IStylesContainer)
            {
                IStylesContainer             parentNode   = (IStylesContainer)element.ParentNode();
                IDictionary <String, String> parentStyles = parentNode.GetStyles();
                if (parentStyles == null && !(element.ParentNode() is IDocumentNode))
                {
                    ILog logger = LogManager.GetLogger(typeof(iText.Html2pdf.Css.Resolve.DefaultCssResolver));
                    logger.Error(iText.Html2pdf.LogMessageConstant.ERROR_RESOLVING_PARENT_STYLES);
                }
                if (parentStyles != null)
                {
                    ICollection <IStyleInheritance> inheritanceRules = new HashSet <IStyleInheritance>();
                    inheritanceRules.Add(cssInheritance);
                    foreach (KeyValuePair <String, String> entry in parentStyles)
                    {
                        elementStyles = StyleUtil.MergeParentStyleDeclaration(elementStyles, entry.Key, entry.Value, parentStyles.
                                                                              Get(CommonCssConstants.FONT_SIZE), inheritanceRules);
                    }
                    parentFontSizeStr = parentStyles.Get(CssConstants.FONT_SIZE);
                }
            }
            String elementFontSize = elementStyles.Get(CssConstants.FONT_SIZE);

            if (CssUtils.IsRelativeValue(elementFontSize) || CssConstants.LARGER.Equals(elementFontSize) || CssConstants
                .SMALLER.Equals(elementFontSize))
            {
                float baseFontSize;
                if (CssUtils.IsRemValue(elementFontSize))
                {
                    baseFontSize = context.GetRootFontSize();
                }
                else
                {
                    if (parentFontSizeStr == null)
                    {
                        baseFontSize = CssUtils.ParseAbsoluteFontSize(CssDefaults.GetDefaultValue(CssConstants.FONT_SIZE));
                    }
                    else
                    {
                        baseFontSize = CssUtils.ParseAbsoluteLength(parentFontSizeStr);
                    }
                }
                float absoluteFontSize = CssUtils.ParseRelativeFontSize(elementFontSize, baseFontSize);
                // Format to 4 decimal places to prevent differences between Java and C#
                elementStyles.Put(CssConstants.FONT_SIZE, DecimalFormatUtil.FormatNumber(absoluteFontSize, "0.####") + CssConstants
                                  .PT);
            }
            else
            {
                elementStyles.Put(CssConstants.FONT_SIZE, Convert.ToString(CssUtils.ParseAbsoluteFontSize(elementFontSize)
                                                                           , System.Globalization.CultureInfo.InvariantCulture) + CssConstants.PT);
            }
            // Update root font size
            if (element is IElementNode && TagConstants.HTML.Equals(((IElementNode)element).Name()))
            {
                context.SetRootFontSize(elementStyles.Get(CssConstants.FONT_SIZE));
            }
            ICollection <String> keys = new HashSet <String>();

            foreach (KeyValuePair <String, String> entry in elementStyles)
            {
                if (CssConstants.INITIAL.Equals(entry.Value) || CssConstants.INHERIT.Equals(entry.Value))
                {
                    // if "inherit" is not resolved till now, parents don't have it
                    keys.Add(entry.Key);
                }
            }
            foreach (String key in keys)
            {
                elementStyles.Put(key, CssDefaults.GetDefaultValue(key));
            }
            // This is needed for correct resolving of content property, so doing it right here
            CounterProcessorUtil.ProcessCounters(elementStyles, context, element);
            ResolveContentProperty(elementStyles, element, context);
            return(elementStyles);
        }
 /// <summary>Check if a non-page(s) target-counter(s) is mentioned and enables it.</summary>
 /// <param name="styleSheet">the stylesheet to analyze</param>
 /// <param name="cssContext">the CSS context</param>
 private static void EnableNonPageTargetCounterIfMentioned(CssStyleSheet styleSheet, CssContext cssContext)
 {
     if (CssStyleSheetAnalyzer.CheckNonPagesTargetCounterPresence(styleSheet))
     {
         cssContext.SetNonPagesTargetCounterPresent(true);
     }
 }