1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.css;
16
17 import static org.htmlunit.BrowserVersionFeatures.CSS_BACKGROUND_INITIAL;
18 import static org.htmlunit.BrowserVersionFeatures.CSS_BACKGROUND_RGBA;
19 import static org.htmlunit.css.CssStyleSheet.FIXED;
20 import static org.htmlunit.css.CssStyleSheet.INITIAL;
21 import static org.htmlunit.css.CssStyleSheet.NONE;
22 import static org.htmlunit.css.CssStyleSheet.REPEAT;
23 import static org.htmlunit.css.CssStyleSheet.SCROLL;
24
25 import java.io.Serializable;
26 import java.util.LinkedHashMap;
27 import java.util.Map;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30
31 import org.htmlunit.BrowserVersion;
32 import org.htmlunit.BrowserVersionFeatures;
33 import org.htmlunit.css.StyleAttributes.Definition;
34 import org.htmlunit.cssparser.dom.AbstractCSSRuleImpl;
35 import org.htmlunit.html.DomElement;
36 import org.htmlunit.html.impl.Color;
37 import org.htmlunit.util.StringUtils;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public abstract class AbstractCssStyleDeclaration implements Serializable {
55
56 private static final Pattern URL_PATTERN =
57 Pattern.compile("url\\(\\s*[\"']?(.*?)[\"']?\\s*\\)");
58
59 private static final Pattern POSITION_PATTERN =
60 Pattern.compile("(\\d+\\s*(%|px|cm|mm|in|pt|pc|em|ex))\\s*"
61 + "(\\d+\\s*(%|px|cm|mm|in|pt|pc|em|ex)|top|bottom|center)");
62 private static final Pattern POSITION_PATTERN2 =
63 Pattern.compile("(left|right|center)\\s*(\\d+\\s*(%|px|cm|mm|in|pt|pc|em|ex)|top|bottom|center)");
64 private static final Pattern POSITION_PATTERN3 =
65 Pattern.compile("(top|bottom|center)\\s*(\\d+\\s*(%|px|cm|mm|in|pt|pc|em|ex)|left|right|center)");
66
67
68
69
70
71
72
73 public abstract String getStylePriority(String name);
74
75
76
77
78
79 public abstract String getCssText();
80
81
82
83
84
85
86 public abstract String getStyleAttribute(String name);
87
88
89
90
91
92
93
94
95
96 public abstract String getStyleAttribute(Definition definition, boolean getDefaultValueIfEmpty);
97
98
99
100
101
102
103 public abstract boolean hasFeature(BrowserVersionFeatures property);
104
105
106
107
108 public abstract BrowserVersion getBrowserVersion();
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public String getStyleAttribute(final Definition definition1, final Definition definition2) {
130 final StyleElement element1 = getStyleElement(definition1.getAttributeName());
131 final StyleElement element2 = getStyleElement(definition2.getAttributeName());
132
133 if (element2 == null) {
134 if (element1 == null) {
135 return "";
136 }
137 return element1.getValue();
138 }
139 if (element1 != null) {
140 if (StyleElement.compareToByImportanceAndSpecificity(element1, element2) > 0) {
141 return element1.getValue();
142 }
143 }
144
145 final String[] values = StringUtils.splitAtJavaWhitespace(element2.getValue());
146 if (definition1.name().contains("TOP")) {
147 if (values.length > 0) {
148 return values[0];
149 }
150 return "";
151 }
152 else if (definition1.name().contains("RIGHT")) {
153 if (values.length > 1) {
154 return values[1];
155 }
156 else if (values.length > 0) {
157 return values[0];
158 }
159 return "";
160 }
161 else if (definition1.name().contains("BOTTOM")) {
162 if (values.length > 2) {
163 return values[2];
164 }
165 else if (values.length > 0) {
166 return values[0];
167 }
168 return "";
169 }
170 else if (definition1.name().contains("LEFT")) {
171 if (values.length > 3) {
172 return values[3];
173 }
174 else if (values.length > 1) {
175 return values[1];
176 }
177 else if (values.length > 0) {
178 return values[0];
179 }
180 else {
181 return "";
182 }
183 }
184 else {
185 throw new IllegalStateException("Unsupported definition: " + definition1);
186 }
187 }
188
189
190
191
192
193 public abstract void setCssText(String value);
194
195
196
197
198
199
200
201 public abstract void setStyleAttribute(String name, String newValue, String important);
202
203
204
205
206
207
208 public abstract String removeStyleAttribute(String name);
209
210
211
212
213
214 public abstract int getLength();
215
216
217
218
219
220 public abstract String item(int index);
221
222
223
224
225
226
227
228 public abstract AbstractCSSRuleImpl getParentRule();
229
230
231
232
233
234
235
236 public abstract StyleElement getStyleElement(String name);
237
238
239
240
241
242
243
244
245 public abstract StyleElement getStyleElementCaseInSensitive(String name);
246
247
248
249
250
251
252
253 public abstract Map<String, StyleElement> getStyleMap();
254
255
256
257
258 public boolean isComputed() {
259 return false;
260 }
261
262
263
264
265
266 public String getBackgroundAttachment() {
267 String value = getStyleAttribute(Definition.BACKGROUND_ATTACHMENT, false);
268 if (org.apache.commons.lang3.StringUtils.isBlank(value)) {
269 final String bg = getStyleAttribute(Definition.BACKGROUND, true);
270 if (org.apache.commons.lang3.StringUtils.isNotBlank(bg)) {
271 value = findAttachment(bg);
272 if (value == null) {
273 if (hasFeature(CSS_BACKGROUND_INITIAL) && !isComputed()) {
274 return INITIAL;
275 }
276 return SCROLL;
277 }
278 return value;
279 }
280 return "";
281 }
282
283 return value;
284 }
285
286
287
288
289
290 public String getBackgroundColor() {
291 String value = getStyleAttribute(Definition.BACKGROUND_COLOR, false);
292 if (org.apache.commons.lang3.StringUtils.isBlank(value)) {
293 final String bg = getStyleAttribute(Definition.BACKGROUND, false);
294 if (org.apache.commons.lang3.StringUtils.isBlank(bg)) {
295 return "";
296 }
297 value = findColor(bg);
298 if (value == null) {
299 if (hasFeature(CSS_BACKGROUND_INITIAL)) {
300 if (!isComputed()) {
301 return INITIAL;
302 }
303 return "rgba(0, 0, 0, 0)";
304 }
305 if (hasFeature(CSS_BACKGROUND_RGBA)) {
306 return "rgba(0, 0, 0, 0)";
307 }
308 return "transparent";
309 }
310 return value;
311 }
312 if (org.apache.commons.lang3.StringUtils.isBlank(value)) {
313 return "";
314 }
315 return value;
316 }
317
318
319
320
321
322 public String getBackgroundImage() {
323 String value = getStyleAttribute(Definition.BACKGROUND_IMAGE, false);
324 if (org.apache.commons.lang3.StringUtils.isBlank(value)) {
325 final String bg = getStyleAttribute(Definition.BACKGROUND, false);
326 if (org.apache.commons.lang3.StringUtils.isNotBlank(bg)) {
327 value = findImageUrl(bg);
328 final boolean backgroundInitial = hasFeature(CSS_BACKGROUND_INITIAL);
329 if (value == null) {
330 return backgroundInitial && !isComputed() ? INITIAL : NONE;
331 }
332 if (isComputed()) {
333 try {
334 value = value.substring(5, value.length() - 2);
335 final DomElement domElement = ((ComputedCssStyleDeclaration) this).getDomElement();
336 return "url(\"" + domElement.getHtmlPageOrNull()
337 .getFullyQualifiedUrl(value) + "\")";
338 }
339 catch (final Exception ignored) {
340
341 }
342 }
343 return value;
344 }
345 return "";
346 }
347
348 return value;
349 }
350
351
352
353
354
355 public String getBackgroundPosition() {
356 String value = getStyleAttribute(Definition.BACKGROUND_POSITION, false);
357 if (value == null) {
358 return null;
359 }
360 if (org.apache.commons.lang3.StringUtils.isBlank(value)) {
361 final String bg = getStyleAttribute(Definition.BACKGROUND, false);
362 if (bg == null) {
363 return null;
364 }
365 if (org.apache.commons.lang3.StringUtils.isNotBlank(bg)) {
366 value = findPosition(bg);
367 final boolean isInitial = hasFeature(CSS_BACKGROUND_INITIAL);
368 if (value == null) {
369 if (isInitial) {
370 return isComputed() ? "" : INITIAL;
371 }
372 return "0% 0%";
373 }
374 if (isComputed()) {
375 final String[] values = StringUtils.splitAtBlank(value);
376 switch (values[0]) {
377 case "left":
378 values[0] = "0%";
379 break;
380
381 case "center":
382 values[0] = "50%";
383 break;
384
385 case "right":
386 values[0] = "100%";
387 break;
388
389 default:
390 }
391 switch (values[1]) {
392 case "top":
393 values[1] = "0%";
394 break;
395
396 case "center":
397 values[1] = "50%";
398 break;
399
400 case "bottom":
401 values[1] = "100%";
402 break;
403
404 default:
405 }
406 value = values[0] + ' ' + values[1];
407 }
408 return value;
409 }
410 return "";
411 }
412
413 return value;
414 }
415
416
417
418
419
420 public String getBackgroundRepeat() {
421 String value = getStyleAttribute(Definition.BACKGROUND_REPEAT, false);
422 if (org.apache.commons.lang3.StringUtils.isBlank(value)) {
423 final String bg = getStyleAttribute(Definition.BACKGROUND, false);
424 if (org.apache.commons.lang3.StringUtils.isNotBlank(bg)) {
425 value = findRepeat(bg);
426 if (value == null) {
427 if (hasFeature(CSS_BACKGROUND_INITIAL) && !isComputed()) {
428 return INITIAL;
429 }
430 return REPEAT;
431 }
432 return value;
433 }
434 return "";
435 }
436
437 return value;
438 }
439
440
441
442
443
444 public String getBorderBottomColor() {
445 String value = getStyleAttribute(Definition.BORDER_BOTTOM_COLOR, false);
446 if (value.isEmpty()) {
447 value = findColor(getStyleAttribute(Definition.BORDER_BOTTOM, false));
448 if (value == null) {
449 value = findColor(getStyleAttribute(Definition.BORDER, false));
450 }
451 if (value == null) {
452 value = "";
453 }
454 }
455 return value;
456 }
457
458
459
460
461
462 public String getBorderBottomStyle() {
463 String value = getStyleAttribute(Definition.BORDER_BOTTOM_STYLE, false);
464 if (value.isEmpty()) {
465 value = findBorderStyle(getStyleAttribute(Definition.BORDER_BOTTOM, false));
466 if (value == null) {
467 value = findBorderStyle(getStyleAttribute(Definition.BORDER, false));
468 }
469 if (value == null) {
470 value = "";
471 }
472 }
473 return value;
474 }
475
476
477
478
479
480 public String getBorderBottomWidth() {
481 return getBorderWidth(Definition.BORDER_BOTTOM_WIDTH, Definition.BORDER_BOTTOM);
482 }
483
484
485
486
487
488 public String getBorderLeftColor() {
489 String value = getStyleAttribute(Definition.BORDER_LEFT_COLOR, false);
490 if (value.isEmpty()) {
491 value = findColor(getStyleAttribute(Definition.BORDER_LEFT, false));
492 if (value == null) {
493 value = findColor(getStyleAttribute(Definition.BORDER, false));
494 }
495 if (value == null) {
496 value = "";
497 }
498 }
499 return value;
500 }
501
502
503
504
505
506 public String getBorderLeftStyle() {
507 String value = getStyleAttribute(Definition.BORDER_LEFT_STYLE, false);
508 if (value.isEmpty()) {
509 value = findBorderStyle(getStyleAttribute(Definition.BORDER_LEFT, false));
510 if (value == null) {
511 value = findBorderStyle(getStyleAttribute(Definition.BORDER, false));
512 }
513 if (value == null) {
514 value = "";
515 }
516 }
517 return value;
518 }
519
520
521
522
523
524 public String getBorderLeftWidth() {
525 return getBorderWidth(Definition.BORDER_LEFT_WIDTH, Definition.BORDER_LEFT);
526 }
527
528
529
530
531
532
533
534 private String getBorderWidth(final Definition borderSideWidth, final Definition borderSide) {
535 String value = getStyleAttribute(borderSideWidth, false);
536 if (value.isEmpty()) {
537 value = findBorderWidth(getStyleAttribute(borderSide, false));
538 if (value == null) {
539 final String borderWidth = getStyleAttribute(Definition.BORDER_WIDTH, false);
540 if (!org.apache.commons.lang3.StringUtils.isEmpty(borderWidth)) {
541 final String[] values = StringUtils.splitAtJavaWhitespace(borderWidth);
542 int index = values.length;
543 if (borderSideWidth.name().contains("TOP")) {
544 index = 0;
545 }
546 else if (borderSideWidth.name().contains("RIGHT")) {
547 index = 1;
548 }
549 else if (borderSideWidth.name().contains("BOTTOM")) {
550 index = 2;
551 }
552 else if (borderSideWidth.name().contains("LEFT")) {
553 index = 3;
554 }
555 if (index < values.length) {
556 value = values[index];
557 }
558 }
559 }
560 if (value == null) {
561 value = findBorderWidth(getStyleAttribute(Definition.BORDER, false));
562 }
563 if (value == null) {
564 value = "";
565 }
566 }
567 return value;
568 }
569
570
571
572
573
574 public String getBorderRightColor() {
575 String value = getStyleAttribute(Definition.BORDER_RIGHT_COLOR, false);
576 if (value.isEmpty()) {
577 value = findColor(getStyleAttribute(Definition.BORDER_RIGHT, false));
578 if (value == null) {
579 value = findColor(getStyleAttribute(Definition.BORDER, false));
580 }
581 if (value == null) {
582 value = "";
583 }
584 }
585 return value;
586 }
587
588
589
590
591
592 public String getBorderRightStyle() {
593 String value = getStyleAttribute(Definition.BORDER_RIGHT_STYLE, false);
594 if (value.isEmpty()) {
595 value = findBorderStyle(getStyleAttribute(Definition.BORDER_RIGHT, false));
596 if (value == null) {
597 value = findBorderStyle(getStyleAttribute(Definition.BORDER, false));
598 }
599 if (value == null) {
600 value = "";
601 }
602 }
603 return value;
604 }
605
606
607
608
609
610 public String getBorderRightWidth() {
611 return getBorderWidth(Definition.BORDER_RIGHT_WIDTH, Definition.BORDER_RIGHT);
612 }
613
614
615
616
617
618 public String getBorderTop() {
619 return getStyleAttribute(Definition.BORDER_TOP, true);
620 }
621
622
623
624
625
626 public String getBorderTopColor() {
627 String value = getStyleAttribute(Definition.BORDER_TOP_COLOR, false);
628 if (value.isEmpty()) {
629 value = findColor(getStyleAttribute(Definition.BORDER_TOP, false));
630 if (value == null) {
631 value = findColor(getStyleAttribute(Definition.BORDER, false));
632 }
633 if (value == null) {
634 value = "";
635 }
636 }
637 return value;
638 }
639
640
641
642
643
644 public String getBorderTopStyle() {
645 String value = getStyleAttribute(Definition.BORDER_TOP_STYLE, false);
646 if (value.isEmpty()) {
647 value = findBorderStyle(getStyleAttribute(Definition.BORDER_TOP, false));
648 if (value == null) {
649 value = findBorderStyle(getStyleAttribute(Definition.BORDER, false));
650 }
651 if (value == null) {
652 value = "";
653 }
654 }
655 return value;
656 }
657
658
659
660
661
662 public String getBorderTopWidth() {
663 return getBorderWidth(Definition.BORDER_TOP_WIDTH, Definition.BORDER_TOP);
664 }
665
666
667
668
669
670 public String getBottom() {
671 return getStyleAttribute(Definition.BOTTOM, true);
672 }
673
674
675
676
677
678 public String getColor() {
679 return getStyleAttribute(Definition.COLOR, true);
680 }
681
682
683
684
685
686 public String getCssFloat() {
687 return getStyleAttribute(Definition.FLOAT, true);
688 }
689
690
691
692
693
694 public String getDisplay() {
695 return getStyleAttribute(Definition.DISPLAY, true);
696 }
697
698
699
700
701
702 public String getFont() {
703 return getStyleAttribute(Definition.FONT, true);
704 }
705
706
707
708
709
710 public String getFontFamily() {
711 return getStyleAttribute(Definition.FONT_FAMILY, true);
712 }
713
714
715
716
717
718 public String getFontSize() {
719 return getStyleAttribute(Definition.FONT_SIZE, true);
720 }
721
722
723
724
725
726 public String getHeight() {
727 return getStyleAttribute(Definition.HEIGHT, true);
728 }
729
730
731
732
733 public String getLeft() {
734 return getStyleAttribute(Definition.LEFT, true);
735 }
736
737
738
739
740 public String getLetterSpacing() {
741 return getStyleAttribute(Definition.LETTER_SPACING, true);
742 }
743
744
745
746
747 public String getLineHeight() {
748 return getStyleAttribute(Definition.LINE_HEIGHT, true);
749 }
750
751
752
753
754 public String getMargin() {
755 return getStyleAttribute(Definition.MARGIN, true);
756 }
757
758
759
760
761
762 public String getMarginBottom() {
763 return getStyleAttribute(Definition.MARGIN_BOTTOM, Definition.MARGIN);
764 }
765
766
767
768
769
770 public String getMarginLeft() {
771 return getStyleAttribute(Definition.MARGIN_LEFT, Definition.MARGIN);
772 }
773
774
775
776
777
778 public String getMarginRight() {
779 return getStyleAttribute(Definition.MARGIN_RIGHT, Definition.MARGIN);
780 }
781
782
783
784
785
786 public String getMarginTop() {
787 return getStyleAttribute(Definition.MARGIN_TOP, Definition.MARGIN);
788 }
789
790
791
792
793 public String getMaxHeight() {
794 return getStyleAttribute(Definition.MAX_HEIGHT, true);
795 }
796
797
798
799
800 public String getMaxWidth() {
801 return getStyleAttribute(Definition.MAX_WIDTH, true);
802 }
803
804
805
806
807 public String getMinHeight() {
808 return getStyleAttribute(Definition.MIN_HEIGHT, true);
809 }
810
811
812
813
814 public String getMinWidth() {
815 return getStyleAttribute(Definition.MIN_WIDTH, true);
816 }
817
818
819
820
821
822 public String getOpacity() {
823 final String opacity = getStyleAttribute(Definition.OPACITY, false);
824 if (opacity == null || opacity.isEmpty()) {
825 return "";
826 }
827
828 final String trimedOpacity = opacity.trim();
829 try {
830 final double value = Double.parseDouble(trimedOpacity);
831 if (value % 1 == 0) {
832 return Integer.toString((int) value);
833 }
834 return Double.toString(value);
835 }
836 catch (final NumberFormatException ignored) {
837
838 }
839 return "";
840 }
841
842
843
844
845 public String getOrphans() {
846 return getStyleAttribute(Definition.ORPHANS, true);
847 }
848
849
850
851
852 public String getOutline() {
853 return getStyleAttribute(Definition.OUTLINE, true);
854 }
855
856
857
858
859 public String getOutlineWidth() {
860 return getStyleAttribute(Definition.OUTLINE_WIDTH, true);
861 }
862
863
864
865
866 public String getPadding() {
867 return getStyleAttribute(Definition.PADDING, true);
868 }
869
870
871
872
873 public String getPaddingBottom() {
874 return getStyleAttribute(Definition.PADDING_BOTTOM, Definition.PADDING);
875 }
876
877
878
879
880 public String getPaddingLeft() {
881 return getStyleAttribute(Definition.PADDING_LEFT, Definition.PADDING);
882 }
883
884
885
886
887 public String getPaddingRight() {
888 return getStyleAttribute(Definition.PADDING_RIGHT, Definition.PADDING);
889 }
890
891
892
893
894 public String getPaddingTop() {
895 return getStyleAttribute(Definition.PADDING_TOP, Definition.PADDING);
896 }
897
898
899
900
901 public String getPosition() {
902 return getStyleAttribute(Definition.POSITION, true);
903 }
904
905
906
907
908 public String getRight() {
909 return getStyleAttribute(Definition.RIGHT, true);
910 }
911
912
913
914
915 public String getRubyAlign() {
916 return getStyleAttribute(Definition.RUBY_ALIGN, true);
917 }
918
919
920
921
922 public String getSize() {
923 return getStyleAttribute(Definition.SIZE, true);
924 }
925
926
927
928
929 public String getTextIndent() {
930 return getStyleAttribute(Definition.TEXT_INDENT, true);
931 }
932
933
934
935
936 public String getTop() {
937 return getStyleAttribute(Definition.TOP, true);
938 }
939
940
941
942
943 public String getVerticalAlign() {
944 return getStyleAttribute(Definition.VERTICAL_ALIGN, true);
945 }
946
947
948
949
950 public String getWidows() {
951 return getStyleAttribute(Definition.WIDOWS, true);
952 }
953
954
955
956
957 public String getWidth() {
958 return getStyleAttribute(Definition.WIDTH, true);
959 }
960
961
962
963
964 public String getWordSpacing() {
965 return getStyleAttribute(Definition.WORD_SPACING, true);
966 }
967
968
969
970
971
972 public String getZIndex() {
973 final String value = getStyleAttribute(Definition.Z_INDEX_, true);
974 try {
975 Integer.parseInt(value);
976 return value;
977 }
978 catch (final NumberFormatException e) {
979 return "";
980 }
981 }
982
983
984
985
986
987
988 private static String findAttachment(final String text) {
989 if (text.contains(SCROLL)) {
990 return SCROLL;
991 }
992 if (text.contains(FIXED)) {
993 return FIXED;
994 }
995 return null;
996 }
997
998
999
1000
1001
1002
1003 private static String findColor(final String text) {
1004 Color tmpColor = StringUtils.findColorRGB(text);
1005 if (tmpColor != null) {
1006 return StringUtils.formatColor(tmpColor);
1007 }
1008
1009 final String[] tokens = StringUtils.splitAtBlank(text);
1010 for (final String token : tokens) {
1011 if (CssColors.isColorKeyword(token)) {
1012 return token;
1013 }
1014
1015 tmpColor = StringUtils.asColorHexadecimal(token);
1016 if (tmpColor != null) {
1017 return StringUtils.formatColor(tmpColor);
1018 }
1019 }
1020 return null;
1021 }
1022
1023
1024
1025
1026
1027
1028 private static String findImageUrl(final String text) {
1029 final Matcher m = URL_PATTERN.matcher(text);
1030 if (m.find()) {
1031 return "url(\"" + m.group(1) + "\")";
1032 }
1033 return null;
1034 }
1035
1036
1037
1038
1039
1040
1041 private static String findPosition(final String text) {
1042 Matcher m = POSITION_PATTERN.matcher(text);
1043 if (m.find()) {
1044 return m.group(1) + " " + m.group(3);
1045 }
1046 m = POSITION_PATTERN2.matcher(text);
1047 if (m.find()) {
1048 return m.group(1) + " " + m.group(2);
1049 }
1050 m = POSITION_PATTERN3.matcher(text);
1051 if (m.find()) {
1052 return m.group(2) + " " + m.group(1);
1053 }
1054 return null;
1055 }
1056
1057
1058
1059
1060
1061
1062 private static String findRepeat(final String text) {
1063 if (text.contains("repeat-x")) {
1064 return "repeat-x";
1065 }
1066 if (text.contains("repeat-y")) {
1067 return "repeat-y";
1068 }
1069 if (text.contains("no-repeat")) {
1070 return "no-repeat";
1071 }
1072 if (text.contains(REPEAT)) {
1073 return REPEAT;
1074 }
1075 return null;
1076 }
1077
1078
1079
1080
1081
1082
1083 private static String findBorderStyle(final String text) {
1084 for (final String token : StringUtils.splitAtBlank(text)) {
1085 if (isBorderStyle(token)) {
1086 return token;
1087 }
1088 }
1089 return null;
1090 }
1091
1092
1093
1094
1095
1096
1097 private static boolean isBorderStyle(final String token) {
1098 return NONE.equalsIgnoreCase(token) || "hidden".equalsIgnoreCase(token)
1099 || "dotted".equalsIgnoreCase(token) || "dashed".equalsIgnoreCase(token)
1100 || "solid".equalsIgnoreCase(token) || "double".equalsIgnoreCase(token)
1101 || "groove".equalsIgnoreCase(token) || "ridge".equalsIgnoreCase(token)
1102 || "inset".equalsIgnoreCase(token) || "outset".equalsIgnoreCase(token);
1103 }
1104
1105
1106
1107
1108
1109
1110 private static String findBorderWidth(final String text) {
1111 for (final String token : StringUtils.splitAtBlank(text)) {
1112 if (isBorderWidth(token)) {
1113 return token;
1114 }
1115 }
1116 return null;
1117 }
1118
1119
1120
1121
1122
1123
1124 private static boolean isBorderWidth(final String token) {
1125 return "thin".equalsIgnoreCase(token) || "medium".equalsIgnoreCase(token)
1126 || "thick".equalsIgnoreCase(token) || isLength(token);
1127 }
1128
1129
1130
1131
1132
1133
1134 static boolean isLength(final String token) {
1135 if (token.endsWith("%")) {
1136 try {
1137 Double.parseDouble(token.substring(0, token.length() - 1));
1138 return true;
1139 }
1140 catch (final NumberFormatException ignored) {
1141
1142 }
1143 return false;
1144 }
1145
1146 if (token.endsWith("em") || token.endsWith("ex") || token.endsWith("px") || token.endsWith("in")
1147 || token.endsWith("cm") || token.endsWith("mm") || token.endsWith("pt") || token.endsWith("pc")) {
1148
1149 try {
1150 Double.parseDouble(token.substring(0, token.length() - 2));
1151 return true;
1152 }
1153 catch (final NumberFormatException ignored) {
1154
1155 }
1156 return false;
1157 }
1158
1159 return false;
1160 }
1161 }