1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.gargoylesoftware.htmlunit.javascript.host.css;
16
17 import java.io.ByteArrayInputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.Reader;
21 import java.io.StringReader;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Map;
27 import java.util.Set;
28
29 import net.sourceforge.htmlunit.corejs.javascript.Context;
30
31 import org.apache.commons.io.IOUtils;
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.w3c.css.sac.AttributeCondition;
36 import org.w3c.css.sac.CombinatorCondition;
37 import org.w3c.css.sac.Condition;
38 import org.w3c.css.sac.ConditionalSelector;
39 import org.w3c.css.sac.ContentCondition;
40 import org.w3c.css.sac.DescendantSelector;
41 import org.w3c.css.sac.ElementSelector;
42 import org.w3c.css.sac.ErrorHandler;
43 import org.w3c.css.sac.InputSource;
44 import org.w3c.css.sac.LangCondition;
45 import org.w3c.css.sac.NegativeCondition;
46 import org.w3c.css.sac.NegativeSelector;
47 import org.w3c.css.sac.Selector;
48 import org.w3c.css.sac.SelectorList;
49 import org.w3c.css.sac.SiblingSelector;
50 import org.w3c.dom.css.CSSImportRule;
51 import org.w3c.dom.css.CSSRule;
52 import org.w3c.dom.css.CSSRuleList;
53
54 import com.gargoylesoftware.htmlunit.BrowserVersion;
55 import com.gargoylesoftware.htmlunit.BrowserVersionFeatures;
56 import com.gargoylesoftware.htmlunit.Cache;
57 import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
58 import com.gargoylesoftware.htmlunit.WebClient;
59 import com.gargoylesoftware.htmlunit.WebRequest;
60 import com.gargoylesoftware.htmlunit.WebResponse;
61 import com.gargoylesoftware.htmlunit.html.DomNode;
62 import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
63 import com.gargoylesoftware.htmlunit.html.HtmlElement;
64 import com.gargoylesoftware.htmlunit.html.HtmlHtml;
65 import com.gargoylesoftware.htmlunit.html.HtmlInput;
66 import com.gargoylesoftware.htmlunit.html.HtmlLink;
67 import com.gargoylesoftware.htmlunit.html.HtmlPage;
68 import com.gargoylesoftware.htmlunit.html.HtmlRadioButtonInput;
69 import com.gargoylesoftware.htmlunit.html.HtmlSelect;
70 import com.gargoylesoftware.htmlunit.html.HtmlStyle;
71 import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
72 import com.gargoylesoftware.htmlunit.javascript.host.Window;
73 import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLElement;
74 import com.gargoylesoftware.htmlunit.util.UrlUtils;
75 import com.steadystate.css.dom.CSSImportRuleImpl;
76 import com.steadystate.css.dom.CSSMediaRuleImpl;
77 import com.steadystate.css.dom.CSSStyleRuleImpl;
78 import com.steadystate.css.dom.CSSStyleSheetImpl;
79 import com.steadystate.css.parser.CSSOMParser;
80 import com.steadystate.css.parser.SACParserCSS21;
81 import com.steadystate.css.parser.SelectorListImpl;
82
83
84
85
86
87
88
89
90
91
92 public class CSSStyleSheet extends SimpleScriptable {
93
94 private static final Log LOG = LogFactory.getLog(CSSStyleSheet.class);
95
96
97 private final org.w3c.dom.css.CSSStyleSheet wrapped_;
98
99
100 private final HTMLElement ownerNode_;
101
102
103 private com.gargoylesoftware.htmlunit.javascript.host.css.CSSRuleList cssRules_;
104
105
106 private Map<CSSImportRule, CSSStyleSheet> imports_ = new HashMap<CSSImportRule, CSSStyleSheet>();
107
108
109 private String uri_;
110
111
112
113
114 public CSSStyleSheet() {
115 wrapped_ = new CSSStyleSheetImpl();
116 ownerNode_ = null;
117 }
118
119
120
121
122
123
124
125 public CSSStyleSheet(final HTMLElement element, final InputSource source, final String uri) {
126 setParentScope(element.getWindow());
127 setPrototype(getPrototype(CSSStyleSheet.class));
128 wrapped_ = parseCSS(source);
129 uri_ = uri;
130 ownerNode_ = element;
131 }
132
133
134
135
136
137
138
139 public CSSStyleSheet(final HTMLElement element, final org.w3c.dom.css.CSSStyleSheet wrapped, final String uri) {
140 setParentScope(element.getWindow());
141 setPrototype(getPrototype(CSSStyleSheet.class));
142 wrapped_ = wrapped;
143 uri_ = uri;
144 ownerNode_ = element;
145 }
146
147
148
149
150
151 public org.w3c.dom.css.CSSStyleSheet getWrappedSheet() {
152 return wrapped_;
153 }
154
155
156
157
158
159
160
161
162
163 public void modifyIfNecessary(final ComputedCSSStyleDeclaration style, final HTMLElement element) {
164 final CSSRuleList rules = getWrappedSheet().getCssRules();
165 modifyIfNecessary(style, element, rules, new HashSet<String>());
166 }
167
168 private void modifyIfNecessary(final ComputedCSSStyleDeclaration style, final HTMLElement element,
169 final CSSRuleList rules, final Set<String> alreadyProcessing) {
170 if (rules == null) {
171 return;
172 }
173 final HtmlElement e = element.getDomNodeOrDie();
174 for (int i = 0; i < rules.getLength(); i++) {
175 final CSSRule rule = rules.item(i);
176 if (rule.getType() == CSSRule.STYLE_RULE) {
177 final CSSStyleRuleImpl styleRule = (CSSStyleRuleImpl) rule;
178 final SelectorList selectors = styleRule.getSelectors();
179 for (int j = 0; j < selectors.getLength(); j++) {
180 final Selector selector = selectors.item(j);
181 final boolean selected = selects(selector, e);
182 if (selected) {
183 final org.w3c.dom.css.CSSStyleDeclaration dec = styleRule.getStyle();
184 style.applyStyleFromSelector(dec, selector);
185 }
186 }
187 }
188 else if (rule.getType() == CSSRule.IMPORT_RULE) {
189 final CSSImportRuleImpl importRule = (CSSImportRuleImpl) rule;
190 CSSStyleSheet sheet = imports_.get(importRule);
191 if (sheet == null) {
192
193 final String uri = (uri_ != null) ? uri_
194 : e.getPage().getWebResponse().getWebRequest().getUrl().toExternalForm();
195 final String href = importRule.getHref();
196 final String url = UrlUtils.resolveUrl(uri, href);
197 sheet = loadStylesheet(getWindow(), ownerNode_, null, url);
198 imports_.put(importRule, sheet);
199 }
200
201 if (!alreadyProcessing.contains(sheet.getUri())) {
202 final CSSRuleList sheetRules = sheet.getWrappedSheet().getCssRules();
203 alreadyProcessing.add(getUri());
204 sheet.modifyIfNecessary(style, element, sheetRules, alreadyProcessing);
205 }
206 }
207 else if (rule.getType() == CSSRule.MEDIA_RULE) {
208 final CSSMediaRuleImpl mediaRule = (CSSMediaRuleImpl) rule;
209 final String media = mediaRule.getMedia().getMediaText();
210 if (isActive(media)) {
211 final CSSRuleList internalRules = mediaRule.getCssRules();
212 modifyIfNecessary(style, element, internalRules, alreadyProcessing);
213 }
214 }
215 }
216 }
217
218
219
220
221
222
223
224
225
226 public static CSSStyleSheet loadStylesheet(final Window window, final HTMLElement element,
227 final HtmlLink link, final String url) {
228 CSSStyleSheet sheet;
229 final HtmlPage page = (HtmlPage) element.getDomNodeOrDie().getPage();
230 String uri = page.getWebResponse().getWebRequest().getUrl().toExternalForm();
231 try {
232
233 final WebRequest request;
234 final WebClient client = page.getWebClient();
235 if (link != null) {
236
237 request = link.getWebRequest();
238 }
239 else {
240
241 request = new WebRequest(new URL(url));
242 final String referer = page.getWebResponse().getWebRequest().getUrl().toExternalForm();
243 request.setAdditionalHeader("Referer", referer);
244 }
245
246 uri = request.getUrl().toExternalForm();
247 final Cache cache = client.getCache();
248 final Object fromCache = cache.getCachedObject(request);
249 if (fromCache != null && fromCache instanceof org.w3c.dom.css.CSSStyleSheet) {
250 sheet = new CSSStyleSheet(element, (org.w3c.dom.css.CSSStyleSheet) fromCache, uri);
251 }
252 else {
253 final WebResponse response = client.loadWebResponse(request);
254 uri = response.getWebRequest().getUrl().toExternalForm();
255 client.printContentIfNecessary(response);
256 client.throwFailingHttpStatusCodeExceptionIfNecessary(response);
257
258 final InputSource source = new InputSource();
259 source.setByteStream(response.getContentAsStream());
260 source.setEncoding(response.getContentCharset());
261 sheet = new CSSStyleSheet(element, source, uri);
262 cache.cacheIfPossible(request, response, sheet.getWrappedSheet());
263 }
264 }
265 catch (final FailingHttpStatusCodeException e) {
266
267 LOG.error(e.getMessage());
268 final InputSource source = new InputSource(new StringReader(""));
269 sheet = new CSSStyleSheet(element, source, uri);
270 }
271 catch (final IOException e) {
272
273 LOG.error(e.getMessage());
274 final InputSource source = new InputSource(new StringReader(""));
275 sheet = new CSSStyleSheet(element, source, uri);
276 }
277 catch (final Exception e) {
278
279 throw Context.reportRuntimeError("Exception: " + e);
280 }
281 return sheet;
282 }
283
284
285
286
287
288
289
290
291 boolean selects(final Selector selector, final HtmlElement element) {
292 return selects(getBrowserVersion(), selector, element);
293 }
294
295
296
297
298
299
300
301
302
303 public static boolean selects(final BrowserVersion browserVersion, final Selector selector,
304 final HtmlElement element) {
305 switch (selector.getSelectorType()) {
306 case Selector.SAC_ANY_NODE_SELECTOR:
307 return true;
308 case Selector.SAC_CHILD_SELECTOR:
309 if (element.getParentNode() == element.getPage()) {
310 return false;
311 }
312 final DescendantSelector cs = (DescendantSelector) selector;
313 if (!(element.getParentNode() instanceof HtmlElement)) {
314 return false;
315 }
316 final HtmlElement parent = (HtmlElement) element.getParentNode();
317 return selects(browserVersion, cs.getSimpleSelector(), element) && parent != null
318 && selects(browserVersion, cs.getAncestorSelector(), parent);
319 case Selector.SAC_DESCENDANT_SELECTOR:
320 final DescendantSelector ds = (DescendantSelector) selector;
321 if (selects(browserVersion, ds.getSimpleSelector(), element)) {
322 DomNode ancestor = element.getParentNode();
323 while (ancestor instanceof HtmlElement) {
324 if (selects(browserVersion, ds.getAncestorSelector(), (HtmlElement) ancestor)) {
325 return true;
326 }
327 ancestor = ancestor.getParentNode();
328 }
329 }
330 return false;
331 case Selector.SAC_CONDITIONAL_SELECTOR:
332 final ConditionalSelector conditional = (ConditionalSelector) selector;
333 final Condition condition = conditional.getCondition();
334 return selects(browserVersion, conditional.getSimpleSelector(), element)
335 && selects(browserVersion, condition, element);
336 case Selector.SAC_ELEMENT_NODE_SELECTOR:
337 final ElementSelector es = (ElementSelector) selector;
338 final String name = es.getLocalName();
339 return name == null || name.equalsIgnoreCase(element.getTagName());
340 case Selector.SAC_ROOT_NODE_SELECTOR:
341 return HtmlHtml.TAG_NAME.equalsIgnoreCase(element.getTagName());
342 case Selector.SAC_DIRECT_ADJACENT_SELECTOR:
343 final SiblingSelector ss = (SiblingSelector) selector;
344 final DomNode prev = element.getPreviousSibling();
345 return prev instanceof HtmlElement
346 && selects(browserVersion, ss.getSelector(), (HtmlElement) prev)
347 && selects(browserVersion, ss.getSiblingSelector(), element);
348 case Selector.SAC_NEGATIVE_SELECTOR:
349 final NegativeSelector ns = (NegativeSelector) selector;
350 return !selects(browserVersion, ns.getSimpleSelector(), element);
351 case Selector.SAC_PSEUDO_ELEMENT_SELECTOR:
352 case Selector.SAC_COMMENT_NODE_SELECTOR:
353 case Selector.SAC_CDATA_SECTION_NODE_SELECTOR:
354 case Selector.SAC_PROCESSING_INSTRUCTION_NODE_SELECTOR:
355 case Selector.SAC_TEXT_NODE_SELECTOR:
356 return false;
357 default:
358 LOG.error("Unknown CSS selector type '" + selector.getSelectorType() + "'.");
359 return false;
360 }
361 }
362
363
364
365
366
367
368
369
370
371 static boolean selects(final BrowserVersion browserVersion, final Condition condition, final HtmlElement element) {
372 switch (condition.getConditionType()) {
373 case Condition.SAC_ID_CONDITION:
374 final AttributeCondition ac4 = (AttributeCondition) condition;
375 return ac4.getValue().equals(element.getId());
376 case Condition.SAC_CLASS_CONDITION:
377 final AttributeCondition ac3 = (AttributeCondition) condition;
378 final String v3 = ac3.getValue();
379 final String a3 = element.getAttribute("class");
380 return a3.equals(v3) || a3.startsWith(v3 + " ") || a3.endsWith(" " + v3) || a3.contains(" " + v3 + " ");
381 case Condition.SAC_AND_CONDITION:
382 final CombinatorCondition cc1 = (CombinatorCondition) condition;
383 return selects(browserVersion, cc1.getFirstCondition(), element)
384 && selects(browserVersion, cc1.getSecondCondition(), element);
385 case Condition.SAC_ATTRIBUTE_CONDITION:
386 final AttributeCondition ac1 = (AttributeCondition) condition;
387 if (ac1.getSpecified()) {
388 return element.getAttribute(ac1.getLocalName()).equals(ac1.getValue());
389 }
390 return element.hasAttribute(ac1.getLocalName());
391 case Condition.SAC_BEGIN_HYPHEN_ATTRIBUTE_CONDITION:
392 final AttributeCondition ac2 = (AttributeCondition) condition;
393 final String v = ac2.getValue();
394 final String a = element.getAttribute(ac2.getLocalName());
395 return a.equals(v) || a.startsWith(v + "-") || a.endsWith("-" + v) || a.contains("-" + v + "-");
396 case Condition.SAC_ONE_OF_ATTRIBUTE_CONDITION:
397 final AttributeCondition ac5 = (AttributeCondition) condition;
398 final String v2 = ac5.getValue();
399 final String a2 = element.getAttribute(ac5.getLocalName());
400 return a2.equals(v2) || a2.startsWith(v2 + " ") || a2.endsWith(" " + v2) || a2.contains(" " + v2 + " ");
401 case Condition.SAC_OR_CONDITION:
402 final CombinatorCondition cc2 = (CombinatorCondition) condition;
403 return selects(browserVersion, cc2.getFirstCondition(), element)
404 || selects(browserVersion, cc2.getSecondCondition(), element);
405 case Condition.SAC_NEGATIVE_CONDITION:
406 final NegativeCondition nc = (NegativeCondition) condition;
407 return !selects(browserVersion, nc.getCondition(), element);
408 case Condition.SAC_ONLY_CHILD_CONDITION:
409 return element.getParentNode().getChildNodes().getLength() == 1;
410 case Condition.SAC_CONTENT_CONDITION:
411 final ContentCondition cc = (ContentCondition) condition;
412 return element.asText().contains(cc.getData());
413 case Condition.SAC_LANG_CONDITION:
414 if (!browserVersion.hasFeature(BrowserVersionFeatures.CSS_SELECTOR_LANG)) {
415 return false;
416 }
417 final String lcLang = ((LangCondition) condition).getLang();
418 for (DomNode node = element; node instanceof HtmlElement; node = node.getParentNode()) {
419 final String nodeLang = ((HtmlElement) node).getAttribute("lang");
420
421 if (nodeLang.startsWith(lcLang)
422 && (nodeLang.length() == lcLang.length() || '-' == nodeLang.charAt(lcLang.length()))) {
423 return true;
424 }
425 }
426 return false;
427 case Condition.SAC_ONLY_TYPE_CONDITION:
428 final String tagName = element.getTagName();
429 return ((HtmlPage) element.getPage()).getElementsByTagName(tagName).getLength() == 1;
430 case Condition.SAC_PSEUDO_CLASS_CONDITION:
431 return selectsPseudoClass(browserVersion, (AttributeCondition) condition, element);
432 case Condition.SAC_POSITIONAL_CONDITION:
433 return false;
434 default:
435 LOG.error("Unknown CSS condition type '" + condition.getConditionType() + "'.");
436 return false;
437 }
438 }
439
440 private static boolean selectsPseudoClass(final BrowserVersion browserVersion,
441 final AttributeCondition condition, final HtmlElement element) {
442 if (!browserVersion.hasFeature(BrowserVersionFeatures.CSS_SPECIAL_PSEUDO_CLASSES)) {
443 return false;
444 }
445
446 final String value = condition.getValue();
447 if ("root".equals(value)) {
448 return element == element.getPage().getDocumentElement();
449 }
450 else if ("enabled".equals(value)) {
451 return (element instanceof HtmlInput && !((HtmlInput) element).isDisabled())
452 || (element instanceof HtmlSelect && !((HtmlSelect) element).isDisabled());
453 }
454 else if ("disabled".equals(value)) {
455 return (element instanceof HtmlInput && ((HtmlInput) element).isDisabled())
456 || (element instanceof HtmlSelect && ((HtmlSelect) element).isDisabled());
457 }
458 else if ("checked".equals(value)) {
459 return (element instanceof HtmlCheckBoxInput && ((HtmlCheckBoxInput) element).isChecked())
460 || (element instanceof HtmlRadioButtonInput && ((HtmlRadioButtonInput) element).isChecked());
461 }
462 return false;
463 }
464
465
466
467
468
469
470
471
472 private org.w3c.dom.css.CSSStyleSheet parseCSS(final InputSource source) {
473 org.w3c.dom.css.CSSStyleSheet ss;
474 try {
475 final ErrorHandler errorHandler = getWindow().getWebWindow().getWebClient().getCssErrorHandler();
476 final CSSOMParser parser = new CSSOMParser(new SACParserCSS21());
477 parser.setErrorHandler(errorHandler);
478 ss = parser.parseStyleSheet(source, null, null);
479 }
480 catch (final Exception e) {
481 LOG.error("Error parsing CSS from '" + toString(source) + "': " + e.getMessage(), e);
482 ss = new CSSStyleSheetImpl();
483 }
484 catch (final Error e) {
485
486 LOG.error("Error parsing CSS from '" + toString(source) + "': " + e.getMessage(), e);
487 ss = new CSSStyleSheetImpl();
488 }
489 return ss;
490 }
491
492
493
494
495
496
497
498
499 public SelectorList parseSelectors(final InputSource source) {
500 SelectorList selectors;
501 try {
502 final ErrorHandler errorHandler = getWindow().getWebWindow().getWebClient().getCssErrorHandler();
503 final CSSOMParser parser = new CSSOMParser(new SACParserCSS21());
504 parser.setErrorHandler(errorHandler);
505 selectors = parser.parseSelectors(source);
506
507 if (null == selectors) {
508 selectors = new SelectorListImpl();
509 }
510 }
511 catch (final Exception e) {
512 LOG.error("Error parsing CSS selectors from '" + toString(source) + "': " + e.getMessage(), e);
513 selectors = new SelectorListImpl();
514 }
515 catch (final Error e) {
516
517 LOG.error("Error parsing CSS selectors from '" + toString(source) + "': " + e.getMessage(), e);
518 selectors = new SelectorListImpl();
519 }
520 return selectors;
521 }
522
523
524
525
526
527
528 private static String toString(final InputSource source) {
529 try {
530 final Reader reader = source.getCharacterStream();
531 if (null != reader) {
532
533 if (reader instanceof StringReader) {
534 final StringReader sr = (StringReader) reader;
535 sr.reset();
536 }
537 return IOUtils.toString(reader);
538 }
539 final InputStream is = source.getByteStream();
540 if (null != is) {
541
542 if (is instanceof ByteArrayInputStream) {
543 final ByteArrayInputStream bis = (ByteArrayInputStream) is;
544 bis.reset();
545 }
546 return IOUtils.toString(is);
547 }
548 return "";
549 }
550 catch (final IOException e) {
551 return "";
552 }
553 }
554
555
556
557
558
559 public HTMLElement jsxGet_ownerNode() {
560 return ownerNode_;
561 }
562
563
564
565
566
567 public HTMLElement jsxGet_owningElement() {
568 return ownerNode_;
569 }
570
571
572
573
574
575 public com.gargoylesoftware.htmlunit.javascript.host.css.CSSRuleList jsxGet_rules() {
576 return jsxGet_cssRules();
577 }
578
579
580
581
582
583 public com.gargoylesoftware.htmlunit.javascript.host.css.CSSRuleList jsxGet_cssRules() {
584 if (cssRules_ == null) {
585 cssRules_ = new com.gargoylesoftware.htmlunit.javascript.host.css.CSSRuleList(this);
586 }
587 return cssRules_;
588 }
589
590
591
592
593
594 public String jsxGet_href() {
595 final BrowserVersion version = getBrowserVersion();
596
597 if (ownerNode_ != null) {
598 final DomNode node = ownerNode_.getDomNodeOrDie();
599 if (node instanceof HtmlLink) {
600
601 final HtmlLink link = (HtmlLink) node;
602 final HtmlPage page = (HtmlPage) link.getPage();
603 final String href = link.getHrefAttribute();
604 if (!version.hasFeature(BrowserVersionFeatures.STYLESHEET_HREF_EXPANDURL)) {
605
606 return href;
607 }
608
609 try {
610 final URL url = page.getFullyQualifiedUrl(href);
611 return url.toExternalForm();
612 }
613 catch (final MalformedURLException e) {
614
615 LOG.warn(e.getMessage(), e);
616 }
617 }
618 }
619
620
621 if (version.hasFeature(BrowserVersionFeatures.STYLESHEET_HREF_STYLE_EMPTY)) {
622 return "";
623 }
624 else if (version.hasFeature(BrowserVersionFeatures.STYLESHEET_HREF_STYLE_NULL)) {
625 return null;
626 }
627 else {
628 final DomNode node = ownerNode_.getDomNodeOrDie();
629 final HtmlPage page = (HtmlPage) node.getPage();
630 final URL url = page.getWebResponse().getWebRequest().getUrl();
631 return url.toExternalForm();
632 }
633 }
634
635
636
637
638
639
640
641
642 public int jsxFunction_insertRule(final String rule, final int position) {
643 return wrapped_.insertRule(rule.trim(), position);
644 }
645
646
647
648
649
650
651 public void jsxFunction_deleteRule(final int position) {
652 wrapped_.deleteRule(position);
653 }
654
655
656
657
658
659
660
661
662 public int jsxFunction_addRule(final String selector, final String rule) {
663 final String completeRule = selector.trim() + " {" + rule + "}";
664 wrapped_.insertRule(completeRule, wrapped_.getCssRules().getLength());
665 return -1;
666 }
667
668
669
670
671
672
673 public void jsxFunction_removeRule(final int position) {
674 wrapped_.deleteRule(position);
675 }
676
677
678
679
680
681 public String getUri() {
682 return uri_;
683 }
684
685
686
687
688
689 public boolean isActive() {
690 final String media;
691 final HtmlElement e = ownerNode_.getDomNodeOrNull();
692 if (e instanceof HtmlStyle) {
693 final HtmlStyle style = (HtmlStyle) e;
694 media = style.getMediaAttribute();
695 }
696 else if (e instanceof HtmlLink) {
697 final HtmlLink link = (HtmlLink) e;
698 media = link.getMediaAttribute();
699 }
700 else {
701 media = "";
702 }
703 return isActive(media);
704 }
705
706 private static boolean isActive(final String media) {
707 if (StringUtils.isBlank(media)) {
708 return true;
709 }
710 for (String s : StringUtils.split(media, ',')) {
711 final String mediaType = s.trim();
712 if ("screen".equals(mediaType) || "all".equals(mediaType)) {
713 return true;
714 }
715 }
716 return false;
717 }
718
719 }