// NOTE: If src property is written in incorrect format (for example, contains token url(<url_content>)<some_nonsense>), // then browser ignores it altogether and doesn't load font at all, even if there are valid tokens. // iText will still process all split tokens and can possibly load this font in case it contains some correct urls. /// <summary>Processes and splits a string sequence containing a url/uri</summary> /// <param name="src">a string representing css src attribute</param> public static String[] SplitSourcesSequence(String src) { IList <String> list = new List <String>(); int indexToStart = 0; while (indexToStart < src.Length) { int indexToCut; int indexUnescapedOpeningQuoteMark = Math.Min(CssUtils.FindNextUnescapedChar(src, '\'', indexToStart) >= 0 ? CssUtils.FindNextUnescapedChar(src, '\'', indexToStart) : int.MaxValue, CssUtils.FindNextUnescapedChar (src, '"', indexToStart) >= 0 ? CssUtils.FindNextUnescapedChar(src, '"', indexToStart) : int.MaxValue); int indexUnescapedBracket = CssUtils.FindNextUnescapedChar(src, ')', indexToStart); if (indexUnescapedOpeningQuoteMark < indexUnescapedBracket) { indexToCut = CssUtils.FindNextUnescapedChar(src, src[indexUnescapedOpeningQuoteMark], indexUnescapedOpeningQuoteMark + 1); if (indexToCut == -1) { indexToCut = src.Length; } } else { indexToCut = indexUnescapedBracket; } while (indexToCut < src.Length && src[indexToCut] != ',') { indexToCut++; } list.Add(src.JSubstring(indexToStart, indexToCut).Trim()); indexToStart = ++indexToCut; } String[] result = new String[list.Count]; list.ToArray(result); return(result); }
/// <summary> /// Resolves a pseudo selector, appends it to list and updates /// <see cref="CssSelectorParserMatch"/> /// in process. /// </summary> /// <param name="selectorItems">list of items to which new selector will be added to</param> /// <param name="pseudoSelector">the pseudo selector</param> /// <param name="match"> /// the corresponding /// <see cref="CssSelectorParserMatch"/> /// that will be updated. /// </param> private static void AppendPseudoSelector(IList <ICssSelectorItem> selectorItems, String pseudoSelector, CssSelectorParserMatch match) { pseudoSelector = pseudoSelector.ToLowerInvariant(); int start = match.GetIndex() + pseudoSelector.Length; String source = match.GetSource(); if (start < source.Length && source[start] == '(') { int bracketDepth = 1; int curr = start + 1; while (bracketDepth > 0 && curr < source.Length) { if (source[curr] == '(') { ++bracketDepth; } else { if (source[curr] == ')') { --bracketDepth; } else { if (source[curr] == '"' || source[curr] == '\'') { curr = CssUtils.FindNextUnescapedChar(source, source[curr], curr + 1); } } } ++curr; } if (bracketDepth == 0) { match.Next(curr); pseudoSelector += source.JSubstring(start, curr); } else { match.Next(); } } else { match.Next(); } /* * This :: notation is introduced by the current document in order to establish a discrimination between * pseudo-classes and pseudo-elements. * For compatibility with existing style sheets, user agents must also accept the previous one-colon * notation for pseudo-elements introduced in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and :after). * This compatibility is not allowed for the new pseudo-elements introduced in this specification. */ if (pseudoSelector.StartsWith("::")) { selectorItems.Add(new CssPseudoElementSelectorItem(pseudoSelector.Substring(2))); } else { if (pseudoSelector.StartsWith(":") && legacyPseudoElements.Contains(pseudoSelector.Substring(1))) { selectorItems.Add(new CssPseudoElementSelectorItem(pseudoSelector.Substring(1))); } else { ICssSelectorItem pseudoClassSelectorItem = CssPseudoClassSelectorItem.Create(pseudoSelector.Substring(1)); if (pseudoClassSelectorItem == null) { throw new ArgumentException(MessageFormatUtil.Format(iText.StyledXmlParser.LogMessageConstant.UNSUPPORTED_PSEUDO_CSS_SELECTOR , pseudoSelector)); } selectorItems.Add(pseudoClassSelectorItem); } } }