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 getBlockSize() {
445 return getStyleAttribute(Definition.BLOCK_SIZE, true);
446 }
447
448
449
450
451
452 public String getBorderBottomColor() {
453 String value = getStyleAttribute(Definition.BORDER_BOTTOM_COLOR, false);
454 if (value.isEmpty()) {
455 value = findColor(getStyleAttribute(Definition.BORDER_BOTTOM, false));
456 if (value == null) {
457 value = findColor(getStyleAttribute(Definition.BORDER, false));
458 }
459 if (value == null) {
460 value = "";
461 }
462 }
463 return value;
464 }
465
466
467
468
469
470 public String getBorderBottomStyle() {
471 String value = getStyleAttribute(Definition.BORDER_BOTTOM_STYLE, false);
472 if (value.isEmpty()) {
473 value = findBorderStyle(getStyleAttribute(Definition.BORDER_BOTTOM, false));
474 if (value == null) {
475 value = findBorderStyle(getStyleAttribute(Definition.BORDER, false));
476 }
477 if (value == null) {
478 value = "";
479 }
480 }
481 return value;
482 }
483
484
485
486
487
488 public String getBorderBottomWidth() {
489 return getBorderWidth(Definition.BORDER_BOTTOM_WIDTH, Definition.BORDER_BOTTOM);
490 }
491
492
493
494
495
496 public String getBorderLeftColor() {
497 String value = getStyleAttribute(Definition.BORDER_LEFT_COLOR, false);
498 if (value.isEmpty()) {
499 value = findColor(getStyleAttribute(Definition.BORDER_LEFT, false));
500 if (value == null) {
501 value = findColor(getStyleAttribute(Definition.BORDER, false));
502 }
503 if (value == null) {
504 value = "";
505 }
506 }
507 return value;
508 }
509
510
511
512
513
514 public String getBorderLeftStyle() {
515 String value = getStyleAttribute(Definition.BORDER_LEFT_STYLE, false);
516 if (value.isEmpty()) {
517 value = findBorderStyle(getStyleAttribute(Definition.BORDER_LEFT, false));
518 if (value == null) {
519 value = findBorderStyle(getStyleAttribute(Definition.BORDER, false));
520 }
521 if (value == null) {
522 value = "";
523 }
524 }
525 return value;
526 }
527
528
529
530
531
532 public String getBorderLeftWidth() {
533 return getBorderWidth(Definition.BORDER_LEFT_WIDTH, Definition.BORDER_LEFT);
534 }
535
536
537
538
539
540
541
542 private String getBorderWidth(final Definition borderSideWidth, final Definition borderSide) {
543 String value = getStyleAttribute(borderSideWidth, false);
544 if (value.isEmpty()) {
545 value = findBorderWidth(getStyleAttribute(borderSide, false));
546 if (value == null) {
547 final String borderWidth = getStyleAttribute(Definition.BORDER_WIDTH, false);
548 if (!org.apache.commons.lang3.StringUtils.isEmpty(borderWidth)) {
549 final String[] values = StringUtils.splitAtJavaWhitespace(borderWidth);
550 int index = values.length;
551 if (borderSideWidth.name().contains("TOP")) {
552 index = 0;
553 }
554 else if (borderSideWidth.name().contains("RIGHT")) {
555 index = 1;
556 }
557 else if (borderSideWidth.name().contains("BOTTOM")) {
558 index = 2;
559 }
560 else if (borderSideWidth.name().contains("LEFT")) {
561 index = 3;
562 }
563 if (index < values.length) {
564 value = values[index];
565 }
566 }
567 }
568 if (value == null) {
569 value = findBorderWidth(getStyleAttribute(Definition.BORDER, false));
570 }
571 if (value == null) {
572 value = "";
573 }
574 }
575 return value;
576 }
577
578
579
580
581
582 public String getBorderRightColor() {
583 String value = getStyleAttribute(Definition.BORDER_RIGHT_COLOR, false);
584 if (value.isEmpty()) {
585 value = findColor(getStyleAttribute(Definition.BORDER_RIGHT, false));
586 if (value == null) {
587 value = findColor(getStyleAttribute(Definition.BORDER, false));
588 }
589 if (value == null) {
590 value = "";
591 }
592 }
593 return value;
594 }
595
596
597
598
599
600 public String getBorderRightStyle() {
601 String value = getStyleAttribute(Definition.BORDER_RIGHT_STYLE, false);
602 if (value.isEmpty()) {
603 value = findBorderStyle(getStyleAttribute(Definition.BORDER_RIGHT, false));
604 if (value == null) {
605 value = findBorderStyle(getStyleAttribute(Definition.BORDER, false));
606 }
607 if (value == null) {
608 value = "";
609 }
610 }
611 return value;
612 }
613
614
615
616
617
618 public String getBorderRightWidth() {
619 return getBorderWidth(Definition.BORDER_RIGHT_WIDTH, Definition.BORDER_RIGHT);
620 }
621
622
623
624
625
626 public String getBorderTop() {
627 return getStyleAttribute(Definition.BORDER_TOP, true);
628 }
629
630
631
632
633
634 public String getBorderTopColor() {
635 String value = getStyleAttribute(Definition.BORDER_TOP_COLOR, false);
636 if (value.isEmpty()) {
637 value = findColor(getStyleAttribute(Definition.BORDER_TOP, false));
638 if (value == null) {
639 value = findColor(getStyleAttribute(Definition.BORDER, false));
640 }
641 if (value == null) {
642 value = "";
643 }
644 }
645 return value;
646 }
647
648
649
650
651
652 public String getBorderTopStyle() {
653 String value = getStyleAttribute(Definition.BORDER_TOP_STYLE, false);
654 if (value.isEmpty()) {
655 value = findBorderStyle(getStyleAttribute(Definition.BORDER_TOP, false));
656 if (value == null) {
657 value = findBorderStyle(getStyleAttribute(Definition.BORDER, false));
658 }
659 if (value == null) {
660 value = "";
661 }
662 }
663 return value;
664 }
665
666
667
668
669
670 public String getBorderTopWidth() {
671 return getBorderWidth(Definition.BORDER_TOP_WIDTH, Definition.BORDER_TOP);
672 }
673
674
675
676
677
678 public String getBottom() {
679 return getStyleAttribute(Definition.BOTTOM, true);
680 }
681
682
683
684
685
686 public String getColor() {
687 return getStyleAttribute(Definition.COLOR, true);
688 }
689
690
691
692
693
694 public String getCssFloat() {
695 return getStyleAttribute(Definition.FLOAT, true);
696 }
697
698
699
700
701
702 public String getDisplay() {
703 return getStyleAttribute(Definition.DISPLAY, true);
704 }
705
706
707
708
709
710 public String getFont() {
711 return getStyleAttribute(Definition.FONT, true);
712 }
713
714
715
716
717
718 public String getFontFamily() {
719 return getStyleAttribute(Definition.FONT_FAMILY, true);
720 }
721
722
723
724
725
726 public String getFontSize() {
727 return getStyleAttribute(Definition.FONT_SIZE, true);
728 }
729
730
731
732
733
734 public String getHeight() {
735 return getStyleAttribute(Definition.HEIGHT, true);
736 }
737
738
739
740
741 public String getLeft() {
742 return getStyleAttribute(Definition.LEFT, true);
743 }
744
745
746
747
748 public String getLetterSpacing() {
749 return getStyleAttribute(Definition.LETTER_SPACING, true);
750 }
751
752
753
754
755 public String getLineHeight() {
756 return getStyleAttribute(Definition.LINE_HEIGHT, true);
757 }
758
759
760
761
762 public String getMargin() {
763 return getStyleAttribute(Definition.MARGIN, true);
764 }
765
766
767
768
769
770 public String getMarginBottom() {
771 return getStyleAttribute(Definition.MARGIN_BOTTOM, Definition.MARGIN);
772 }
773
774
775
776
777
778 public String getMarginLeft() {
779 return getStyleAttribute(Definition.MARGIN_LEFT, Definition.MARGIN);
780 }
781
782
783
784
785
786 public String getMarginRight() {
787 return getStyleAttribute(Definition.MARGIN_RIGHT, Definition.MARGIN);
788 }
789
790
791
792
793
794 public String getMarginTop() {
795 return getStyleAttribute(Definition.MARGIN_TOP, Definition.MARGIN);
796 }
797
798
799
800
801 public String getMaxHeight() {
802 return getStyleAttribute(Definition.MAX_HEIGHT, true);
803 }
804
805
806
807
808 public String getMaxWidth() {
809 return getStyleAttribute(Definition.MAX_WIDTH, true);
810 }
811
812
813
814
815 public String getMinHeight() {
816 return getStyleAttribute(Definition.MIN_HEIGHT, true);
817 }
818
819
820
821
822 public String getMinWidth() {
823 return getStyleAttribute(Definition.MIN_WIDTH, true);
824 }
825
826
827
828
829
830 public String getOpacity() {
831 final String opacity = getStyleAttribute(Definition.OPACITY, false);
832 if (opacity == null || opacity.isEmpty()) {
833 return "";
834 }
835
836 final String trimedOpacity = opacity.trim();
837 try {
838 final double value = Double.parseDouble(trimedOpacity);
839 if (value % 1 == 0) {
840 return Integer.toString((int) value);
841 }
842 return Double.toString(value);
843 }
844 catch (final NumberFormatException ignored) {
845
846 }
847 return "";
848 }
849
850
851
852
853 public String getOrphans() {
854 return getStyleAttribute(Definition.ORPHANS, true);
855 }
856
857
858
859
860 public String getOutline() {
861 return getStyleAttribute(Definition.OUTLINE, true);
862 }
863
864
865
866
867 public String getOutlineWidth() {
868 return getStyleAttribute(Definition.OUTLINE_WIDTH, true);
869 }
870
871
872
873
874 public String getPadding() {
875 return getStyleAttribute(Definition.PADDING, true);
876 }
877
878
879
880
881 public String getPaddingBottom() {
882 return getStyleAttribute(Definition.PADDING_BOTTOM, Definition.PADDING);
883 }
884
885
886
887
888 public String getPaddingLeft() {
889 return getStyleAttribute(Definition.PADDING_LEFT, Definition.PADDING);
890 }
891
892
893
894
895 public String getPaddingRight() {
896 return getStyleAttribute(Definition.PADDING_RIGHT, Definition.PADDING);
897 }
898
899
900
901
902 public String getPaddingTop() {
903 return getStyleAttribute(Definition.PADDING_TOP, Definition.PADDING);
904 }
905
906
907
908
909 public String getPosition() {
910 return getStyleAttribute(Definition.POSITION, true);
911 }
912
913
914
915
916 public String getRight() {
917 return getStyleAttribute(Definition.RIGHT, true);
918 }
919
920
921
922
923 public String getRubyAlign() {
924 return getStyleAttribute(Definition.RUBY_ALIGN, true);
925 }
926
927
928
929
930 public String getSize() {
931 return getStyleAttribute(Definition.SIZE, true);
932 }
933
934
935
936
937 public String getTextIndent() {
938 return getStyleAttribute(Definition.TEXT_INDENT, true);
939 }
940
941
942
943
944 public String getTop() {
945 return getStyleAttribute(Definition.TOP, true);
946 }
947
948
949
950
951 public String getVerticalAlign() {
952 return getStyleAttribute(Definition.VERTICAL_ALIGN, true);
953 }
954
955
956
957
958 public String getWidows() {
959 return getStyleAttribute(Definition.WIDOWS, true);
960 }
961
962
963
964
965 public String getWidth() {
966 return getStyleAttribute(Definition.WIDTH, true);
967 }
968
969
970
971
972 public String getWordSpacing() {
973 return getStyleAttribute(Definition.WORD_SPACING, true);
974 }
975
976
977
978
979
980 public String getZIndex() {
981 final String value = getStyleAttribute(Definition.Z_INDEX_, true);
982 try {
983 Integer.parseInt(value);
984 return value;
985 }
986 catch (final NumberFormatException e) {
987 return "";
988 }
989 }
990
991
992
993
994
995
996 private static String findAttachment(final String text) {
997 if (text.contains(SCROLL)) {
998 return SCROLL;
999 }
1000 if (text.contains(FIXED)) {
1001 return FIXED;
1002 }
1003 return null;
1004 }
1005
1006
1007
1008
1009
1010
1011 private static String findColor(final String text) {
1012 Color tmpColor = StringUtils.findColorRGB(text);
1013 if (tmpColor != null) {
1014 return StringUtils.formatColor(tmpColor);
1015 }
1016
1017 final String[] tokens = StringUtils.splitAtBlank(text);
1018 for (final String token : tokens) {
1019 if (CssColors.isColorKeyword(token)) {
1020 return token;
1021 }
1022
1023 tmpColor = StringUtils.asColorHexadecimal(token);
1024 if (tmpColor != null) {
1025 return StringUtils.formatColor(tmpColor);
1026 }
1027 }
1028 return null;
1029 }
1030
1031
1032
1033
1034
1035
1036 private static String findImageUrl(final String text) {
1037 final Matcher m = URL_PATTERN.matcher(text);
1038 if (m.find()) {
1039 return "url(\"" + m.group(1) + "\")";
1040 }
1041 return null;
1042 }
1043
1044
1045
1046
1047
1048
1049 private static String findPosition(final String text) {
1050 Matcher m = POSITION_PATTERN.matcher(text);
1051 if (m.find()) {
1052 return m.group(1) + " " + m.group(3);
1053 }
1054 m = POSITION_PATTERN2.matcher(text);
1055 if (m.find()) {
1056 return m.group(1) + " " + m.group(2);
1057 }
1058 m = POSITION_PATTERN3.matcher(text);
1059 if (m.find()) {
1060 return m.group(2) + " " + m.group(1);
1061 }
1062 return null;
1063 }
1064
1065
1066
1067
1068
1069
1070 private static String findRepeat(final String text) {
1071 if (text.contains("repeat-x")) {
1072 return "repeat-x";
1073 }
1074 if (text.contains("repeat-y")) {
1075 return "repeat-y";
1076 }
1077 if (text.contains("no-repeat")) {
1078 return "no-repeat";
1079 }
1080 if (text.contains(REPEAT)) {
1081 return REPEAT;
1082 }
1083 return null;
1084 }
1085
1086
1087
1088
1089
1090
1091 private static String findBorderStyle(final String text) {
1092 for (final String token : StringUtils.splitAtBlank(text)) {
1093 if (isBorderStyle(token)) {
1094 return token;
1095 }
1096 }
1097 return null;
1098 }
1099
1100
1101
1102
1103
1104
1105 private static boolean isBorderStyle(final String token) {
1106 return NONE.equalsIgnoreCase(token) || "hidden".equalsIgnoreCase(token)
1107 || "dotted".equalsIgnoreCase(token) || "dashed".equalsIgnoreCase(token)
1108 || "solid".equalsIgnoreCase(token) || "double".equalsIgnoreCase(token)
1109 || "groove".equalsIgnoreCase(token) || "ridge".equalsIgnoreCase(token)
1110 || "inset".equalsIgnoreCase(token) || "outset".equalsIgnoreCase(token);
1111 }
1112
1113
1114
1115
1116
1117
1118 private static String findBorderWidth(final String text) {
1119 for (final String token : StringUtils.splitAtBlank(text)) {
1120 if (isBorderWidth(token)) {
1121 return token;
1122 }
1123 }
1124 return null;
1125 }
1126
1127
1128
1129
1130
1131
1132 private static boolean isBorderWidth(final String token) {
1133 return "thin".equalsIgnoreCase(token) || "medium".equalsIgnoreCase(token)
1134 || "thick".equalsIgnoreCase(token) || isLength(token);
1135 }
1136
1137
1138
1139
1140
1141
1142 static boolean isLength(final String token) {
1143 if (token.endsWith("%")) {
1144 try {
1145 Double.parseDouble(token.substring(0, token.length() - 1));
1146 return true;
1147 }
1148 catch (final NumberFormatException ignored) {
1149
1150 }
1151 return false;
1152 }
1153
1154 if (token.endsWith("em") || token.endsWith("ex") || token.endsWith("px") || token.endsWith("in")
1155 || token.endsWith("cm") || token.endsWith("mm") || token.endsWith("pt") || token.endsWith("pc")) {
1156
1157 try {
1158 Double.parseDouble(token.substring(0, token.length() - 2));
1159 return true;
1160 }
1161 catch (final NumberFormatException ignored) {
1162
1163 }
1164 return false;
1165 }
1166
1167 return false;
1168 }
1169 }