1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.css;
16
17 import static org.htmlunit.BrowserVersionFeatures.CSS_BACKGROUND_INITIAL;
18 import static org.htmlunit.BrowserVersionFeatures.JS_STYLE_WORD_SPACING_ACCEPTS_PERCENT;
19 import static org.htmlunit.css.CssStyleSheet.ABSOLUTE;
20 import static org.htmlunit.css.CssStyleSheet.AUTO;
21 import static org.htmlunit.css.CssStyleSheet.FIXED;
22 import static org.htmlunit.css.CssStyleSheet.INHERIT;
23 import static org.htmlunit.css.CssStyleSheet.INITIAL;
24 import static org.htmlunit.css.CssStyleSheet.RELATIVE;
25 import static org.htmlunit.css.CssStyleSheet.STATIC;
26 import static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
27 import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
28
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.HashSet;
33 import java.util.LinkedHashMap;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Map;
37 import java.util.Set;
38
39 import org.apache.commons.lang3.ArrayUtils;
40 import org.apache.commons.lang3.StringUtils;
41 import org.htmlunit.BrowserVersion;
42 import org.htmlunit.corejs.javascript.Scriptable;
43 import org.htmlunit.corejs.javascript.ScriptableObject;
44 import org.htmlunit.css.AbstractCssStyleDeclaration;
45 import org.htmlunit.css.StyleAttributes;
46 import org.htmlunit.css.StyleAttributes.Definition;
47 import org.htmlunit.css.StyleElement;
48 import org.htmlunit.css.WrappedCssStyleDeclaration;
49 import org.htmlunit.cssparser.dom.AbstractCSSRuleImpl;
50 import org.htmlunit.javascript.HtmlUnitScriptable;
51 import org.htmlunit.javascript.JavaScriptEngine;
52 import org.htmlunit.javascript.configuration.JsxClass;
53 import org.htmlunit.javascript.configuration.JsxConstructor;
54 import org.htmlunit.javascript.configuration.JsxFunction;
55 import org.htmlunit.javascript.configuration.JsxGetter;
56 import org.htmlunit.javascript.configuration.JsxSetter;
57 import org.htmlunit.javascript.configuration.JsxSymbol;
58 import org.htmlunit.javascript.host.Element;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 @JsxClass
76 public class CSSStyleDeclaration extends HtmlUnitScriptable {
77
78 private static final Set<String> LENGTH_PROPERTIES_FFFF = new HashSet<>(Arrays.asList(
79 Definition.BORDER_TOP_WIDTH.getAttributeName(),
80 Definition.BORDER_LEFT_WIDTH.getAttributeName(),
81 Definition.BORDER_BOTTOM_WIDTH.getAttributeName(),
82 Definition.BORDER_RIGHT_WIDTH.getAttributeName(),
83 Definition.LETTER_SPACING.getAttributeName()));
84
85 private static final Set<String> LENGTH_PROPERTIES_TTFF = new HashSet<>(Arrays.asList(
86 Definition.HEIGHT.getAttributeName(),
87 Definition.WIDTH.getAttributeName(),
88 Definition.TOP.getAttributeName(),
89 Definition.LEFT.getAttributeName(),
90 Definition.BOTTOM.getAttributeName(),
91 Definition.RIGHT.getAttributeName(),
92 Definition.MARGIN_TOP.getAttributeName(),
93 Definition.MARGIN_LEFT.getAttributeName(),
94 Definition.MARGIN_BOTTOM.getAttributeName(),
95 Definition.MARGIN_RIGHT.getAttributeName(),
96 Definition.MIN_HEIGHT.getAttributeName(),
97 Definition.MIN_WIDTH.getAttributeName()
98 ));
99
100 private static final Set<String> LENGTH_PROPERTIES_FTFF = new HashSet<>(Arrays.asList(
101 Definition.FONT_SIZE.getAttributeName(),
102 Definition.TEXT_INDENT.getAttributeName(),
103 Definition.PADDING_TOP.getAttributeName(),
104 Definition.PADDING_LEFT.getAttributeName(),
105 Definition.PADDING_BOTTOM.getAttributeName(),
106 Definition.PADDING_RIGHT.getAttributeName(),
107 Definition.MAX_HEIGHT.getAttributeName(),
108 Definition.MAX_WIDTH.getAttributeName()
109 ));
110
111 private static final String[] THIN_MED_THICK = {"thin", "medium", "thick"};
112 private static final String[] ALIGN_KEYWORDS =
113 {"baseline", "sub", "super", "text-top", "text-bottom", "middle", "top", "bottom",
114 "inherit", "initial", "revert", "unset"};
115 private static final String[] FONT_SIZES =
116 {"xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large",
117 "smaller", "larger"};
118
119
120
121
122 private AbstractCssStyleDeclaration styleDeclaration_;
123
124
125
126
127 public CSSStyleDeclaration() {
128 super();
129 }
130
131
132
133
134
135
136
137 @JsxConstructor
138 public void jsConstructor(final String type, final ScriptableObject details) {
139 throw JavaScriptEngine.typeError("CSSStyleDeclaration ctor is not available");
140 }
141
142
143
144
145
146
147 public CSSStyleDeclaration(final Element element, final AbstractCssStyleDeclaration styleDeclaration) {
148 super();
149 setParentScope(element.getParentScope());
150 setPrototype(getPrototype(getClass()));
151
152 setDomNode(element.getDomNodeOrNull(), false);
153
154 if (styleDeclaration == null) {
155 throw new IllegalStateException("styleDeclaration can't be null");
156 }
157 styleDeclaration_ = styleDeclaration;
158 }
159
160
161
162
163
164
165 CSSStyleDeclaration(final CSSStyleSheet parentStyleSheet, final WrappedCssStyleDeclaration styleDeclaration) {
166 super();
167 setParentScope(parentStyleSheet);
168 setPrototype(getPrototype(getClass()));
169
170 if (styleDeclaration == null) {
171 throw new IllegalStateException("styleDeclaration can't be null");
172 }
173 styleDeclaration_ = styleDeclaration;
174 }
175
176 protected AbstractCssStyleDeclaration getCssStyleDeclaration() {
177 return styleDeclaration_;
178 }
179
180
181
182
183
184
185
186 protected String getStylePriority(final String name) {
187 return styleDeclaration_.getStylePriority(name);
188 }
189
190
191
192
193
194
195 protected void setStyleAttribute(final String name, final String newValue) {
196 setStyleAttribute(name, newValue, "");
197 }
198
199
200
201
202
203
204
205 protected void setStyleAttribute(final String name, String newValue, final String important) {
206 if (null == newValue || "null".equals(newValue)) {
207 newValue = "";
208 }
209
210 styleDeclaration_.setStyleAttribute(name, newValue, important);
211 }
212
213
214
215
216
217 private String removeStyleAttribute(final String name) {
218 if (styleDeclaration_ == null) {
219 return null;
220 }
221 return styleDeclaration_.removeStyleAttribute(name);
222 }
223
224
225
226
227
228
229
230 private Map<String, StyleElement> getStyleMap() {
231 if (styleDeclaration_ == null) {
232 return Collections.emptyMap();
233 }
234 return styleDeclaration_.getStyleMap();
235 }
236
237
238
239
240
241 @JsxGetter
242 public String getBackgroundAttachment() {
243 if (styleDeclaration_ == null) {
244 return null;
245 }
246 return styleDeclaration_.getBackgroundAttachment();
247 }
248
249
250
251
252
253 @JsxSetter
254 public void setBackgroundAttachment(final String backgroundAttachment) {
255 setStyleAttribute(Definition.BACKGROUND_ATTACHMENT.getAttributeName(), backgroundAttachment);
256 }
257
258
259
260
261
262 @JsxGetter
263 public String getBackgroundColor() {
264 if (styleDeclaration_ == null) {
265 return null;
266 }
267 return styleDeclaration_.getBackgroundColor();
268 }
269
270
271
272
273
274 @JsxSetter
275 public void setBackgroundColor(final String backgroundColor) {
276 setStyleAttribute(Definition.BACKGROUND_COLOR.getAttributeName(), backgroundColor);
277 }
278
279
280
281
282
283 @JsxGetter
284 public String getBackgroundImage() {
285 if (styleDeclaration_ == null) {
286 return null;
287 }
288 return styleDeclaration_.getBackgroundImage();
289 }
290
291
292
293
294
295 @JsxSetter
296 public void setBackgroundImage(final String backgroundImage) {
297 setStyleAttribute(Definition.BACKGROUND_IMAGE.getAttributeName(), backgroundImage);
298 }
299
300
301
302
303
304 @JsxGetter
305 public String getBackgroundPosition() {
306 if (styleDeclaration_ == null) {
307 return null;
308 }
309 return styleDeclaration_.getBackgroundPosition();
310 }
311
312
313
314
315
316 @JsxSetter
317 public void setBackgroundPosition(final String backgroundPosition) {
318 setStyleAttribute(Definition.BACKGROUND_POSITION.getAttributeName(), backgroundPosition);
319 }
320
321
322
323
324
325 @JsxGetter
326 public String getBackgroundRepeat() {
327 if (styleDeclaration_ == null) {
328 return null;
329 }
330 return styleDeclaration_.getBackgroundRepeat();
331 }
332
333
334
335
336
337 @JsxSetter
338 public void setBackgroundRepeat(final String backgroundRepeat) {
339 setStyleAttribute(Definition.BACKGROUND_REPEAT.getAttributeName(), backgroundRepeat);
340 }
341
342
343
344
345
346 @JsxGetter
347 public String getBorderBottomColor() {
348 if (styleDeclaration_ == null) {
349 return null;
350 }
351 return styleDeclaration_.getBorderBottomColor();
352 }
353
354
355
356
357
358 @JsxSetter
359 public void setBorderBottomColor(final String borderBottomColor) {
360 setStyleAttribute(Definition.BORDER_BOTTOM_COLOR.getAttributeName(), borderBottomColor);
361 }
362
363
364
365
366
367 @JsxGetter
368 public String getBorderBottomStyle() {
369 if (styleDeclaration_ == null) {
370 return null;
371 }
372 return styleDeclaration_.getBorderBottomStyle();
373 }
374
375
376
377
378
379 @JsxSetter
380 public void setBorderBottomStyle(final String borderBottomStyle) {
381 setStyleAttribute(Definition.BORDER_BOTTOM_STYLE.getAttributeName(), borderBottomStyle);
382 }
383
384
385
386
387
388 @JsxGetter
389 public String getBorderBottomWidth() {
390 if (styleDeclaration_ == null) {
391 return null;
392 }
393 return styleDeclaration_.getBorderBottomWidth();
394 }
395
396
397
398
399
400 @JsxSetter
401 public void setBorderBottomWidth(final Object borderBottomWidth) {
402 setStyleLengthAttribute(Definition.BORDER_BOTTOM_WIDTH.getAttributeName(), borderBottomWidth, "",
403 false, false, false, null);
404 }
405
406
407
408
409
410 @JsxGetter
411 public String getBorderLeftColor() {
412 if (styleDeclaration_ == null) {
413 return null;
414 }
415 return styleDeclaration_.getBorderLeftColor();
416 }
417
418
419
420
421
422 @JsxSetter
423 public void setBorderLeftColor(final String borderLeftColor) {
424 setStyleAttribute(Definition.BORDER_LEFT_COLOR.getAttributeName(), borderLeftColor);
425 }
426
427
428
429
430
431 @JsxGetter
432 public String getBorderLeftStyle() {
433 if (styleDeclaration_ == null) {
434 return null;
435 }
436 return styleDeclaration_.getBorderLeftStyle();
437 }
438
439
440
441
442
443 @JsxSetter
444 public void setBorderLeftStyle(final String borderLeftStyle) {
445 setStyleAttribute(Definition.BORDER_LEFT_STYLE.getAttributeName(), borderLeftStyle);
446 }
447
448
449
450
451
452 @JsxGetter
453 public String getBorderLeftWidth() {
454 if (styleDeclaration_ == null) {
455 return null;
456 }
457 return styleDeclaration_.getBorderLeftWidth();
458 }
459
460
461
462
463
464 @JsxSetter
465 public void setBorderLeftWidth(final Object borderLeftWidth) {
466 setStyleLengthAttribute(Definition.BORDER_LEFT_WIDTH.getAttributeName(), borderLeftWidth, "",
467 false, false, false, null);
468 }
469
470
471
472
473
474 @JsxGetter
475 public String getBorderRightColor() {
476 if (styleDeclaration_ == null) {
477 return null;
478 }
479 return styleDeclaration_.getBorderRightColor();
480 }
481
482
483
484
485
486 @JsxSetter
487 public void setBorderRightColor(final String borderRightColor) {
488 setStyleAttribute(Definition.BORDER_RIGHT_COLOR.getAttributeName(), borderRightColor);
489 }
490
491
492
493
494
495 @JsxGetter
496 public String getBorderRightStyle() {
497 if (styleDeclaration_ == null) {
498 return null;
499 }
500 return styleDeclaration_.getBorderRightStyle();
501 }
502
503
504
505
506
507 @JsxSetter
508 public void setBorderRightStyle(final String borderRightStyle) {
509 setStyleAttribute(Definition.BORDER_RIGHT_STYLE.getAttributeName(), borderRightStyle);
510 }
511
512
513
514
515
516 @JsxGetter
517 public String getBorderRightWidth() {
518 if (styleDeclaration_ == null) {
519 return null;
520 }
521 return styleDeclaration_.getBorderRightWidth();
522 }
523
524
525
526
527
528 @JsxSetter
529 public void setBorderRightWidth(final Object borderRightWidth) {
530 setStyleLengthAttribute(Definition.BORDER_RIGHT_WIDTH.getAttributeName(), borderRightWidth, "",
531 false, false, false, null);
532 }
533
534
535
536
537
538 @JsxGetter
539 public String getBorderTop() {
540 if (styleDeclaration_ == null) {
541 return null;
542 }
543 return styleDeclaration_.getBorderTop();
544 }
545
546
547
548
549
550 @JsxSetter
551 public void setBorderTop(final String borderTop) {
552 setStyleAttribute(Definition.BORDER_TOP.getAttributeName(), borderTop);
553 }
554
555
556
557
558
559 @JsxGetter
560 public String getBorderTopColor() {
561 if (styleDeclaration_ == null) {
562 return null;
563 }
564 return styleDeclaration_.getBorderTopColor();
565 }
566
567
568
569
570
571 @JsxSetter
572 public void setBorderTopColor(final String borderTopColor) {
573 setStyleAttribute(Definition.BORDER_TOP_COLOR.getAttributeName(), borderTopColor);
574 }
575
576
577
578
579
580 @JsxGetter
581 public String getBorderTopStyle() {
582 if (styleDeclaration_ == null) {
583 return null;
584 }
585 return styleDeclaration_.getBorderTopStyle();
586 }
587
588
589
590
591
592 @JsxSetter
593 public void setBorderTopStyle(final String borderTopStyle) {
594 setStyleAttribute(Definition.BORDER_TOP_STYLE.getAttributeName(), borderTopStyle);
595 }
596
597
598
599
600
601 @JsxGetter
602 public String getBorderTopWidth() {
603 if (styleDeclaration_ == null) {
604 return null;
605 }
606 return styleDeclaration_.getBorderTopWidth();
607 }
608
609
610
611
612
613 @JsxSetter
614 public void setBorderTopWidth(final Object borderTopWidth) {
615 setStyleLengthAttribute(Definition.BORDER_TOP_WIDTH.getAttributeName(), borderTopWidth, "",
616 false, false, false, null);
617 }
618
619
620
621
622
623 @JsxGetter
624 public String getBottom() {
625 if (styleDeclaration_ == null) {
626 return null;
627 }
628 return styleDeclaration_.getBottom();
629 }
630
631
632
633
634
635 @JsxSetter
636 public void setBottom(final Object bottom) {
637 setStyleLengthAttribute(Definition.BOTTOM.getAttributeName(), bottom, "", true, true, false, null);
638 }
639
640
641
642
643
644 @JsxGetter
645 public String getColor() {
646 if (styleDeclaration_ == null) {
647 return null;
648 }
649 return styleDeclaration_.getColor();
650 }
651
652
653
654
655
656 @JsxSetter
657 public void setColor(final String color) {
658 setStyleAttribute(Definition.COLOR.getAttributeName(), color);
659 }
660
661
662
663
664
665 @JsxGetter
666 public String getCssFloat() {
667 if (styleDeclaration_ == null) {
668 return null;
669 }
670 return styleDeclaration_.getCssFloat();
671 }
672
673
674
675
676
677 @JsxSetter
678 public void setCssFloat(final String value) {
679 setStyleAttribute(Definition.FLOAT.getAttributeName(), value);
680 }
681
682
683
684
685
686 @JsxGetter
687 public String getCssText() {
688 if (styleDeclaration_ == null) {
689 return null;
690 }
691 return styleDeclaration_.getCssText();
692 }
693
694
695
696
697
698 @JsxSetter
699 public void setCssText(final String value) {
700 String fixedValue = value;
701 if (fixedValue == null || "null".equals(fixedValue)) {
702 fixedValue = "";
703 }
704
705 styleDeclaration_.setCssText(fixedValue);
706 }
707
708
709
710
711
712 @JsxGetter
713 public String getDisplay() {
714 if (styleDeclaration_ == null) {
715 return null;
716 }
717 return styleDeclaration_.getDisplay();
718 }
719
720
721
722
723
724 @JsxSetter
725 public void setDisplay(final String display) {
726 setStyleAttribute(Definition.DISPLAY.getAttributeName(), display);
727 }
728
729
730
731
732
733 @JsxGetter
734 public String getFontSize() {
735 if (styleDeclaration_ == null) {
736 return null;
737 }
738 return styleDeclaration_.getFontSize();
739 }
740
741
742
743
744
745 @JsxSetter
746 public void setFontSize(final Object fontSize) {
747 setStyleLengthAttribute(Definition.FONT_SIZE.getAttributeName(), fontSize, "", false, true, false, FONT_SIZES);
748 updateFont(getFont(), false);
749 }
750
751
752
753
754
755 @JsxGetter
756 public String getLineHeight() {
757 if (styleDeclaration_ == null) {
758 return null;
759 }
760 return styleDeclaration_.getLineHeight();
761 }
762
763
764
765
766
767 @JsxSetter
768 public void setLineHeight(final String lineHeight) {
769 setStyleAttribute(Definition.LINE_HEIGHT.getAttributeName(), lineHeight);
770 updateFont(getFont(), false);
771 }
772
773
774
775
776
777 @JsxGetter
778 public String getFontFamily() {
779 if (styleDeclaration_ == null) {
780 return null;
781 }
782 return styleDeclaration_.getFontFamily();
783 }
784
785
786
787
788
789 @JsxSetter
790 public void setFontFamily(final String fontFamily) {
791 setStyleAttribute(Definition.FONT_FAMILY.getAttributeName(), fontFamily);
792 updateFont(getFont(), false);
793 }
794
795 private void updateFont(final String font, final boolean force) {
796 final BrowserVersion browserVersion = getBrowserVersion();
797 final String[] details = ComputedFont.getDetails(font);
798 if (details != null || force) {
799 final StringBuilder newFont = new StringBuilder();
800 newFont.append(getFontSize());
801 String lineHeight = getLineHeight();
802 final String defaultLineHeight = Definition.LINE_HEIGHT.getDefaultComputedValue(browserVersion);
803 if (lineHeight.isEmpty()) {
804 lineHeight = defaultLineHeight;
805 }
806
807 if (!lineHeight.equals(defaultLineHeight)) {
808 newFont.append('/');
809 if (lineHeight.equals(defaultLineHeight)) {
810 newFont.append(Definition.LINE_HEIGHT.getDefaultComputedValue(browserVersion));
811 }
812 else {
813 newFont.append(lineHeight);
814 }
815 }
816
817 newFont.append(' ').append(getFontFamily());
818 setStyleAttribute(Definition.FONT.getAttributeName(), newFont.toString());
819 }
820 }
821
822
823
824
825
826 @JsxGetter
827 public String getFont() {
828 if (styleDeclaration_ == null) {
829 return null;
830 }
831 return styleDeclaration_.getFont();
832 }
833
834
835
836
837
838 @JsxSetter
839 public void setFont(final String font) {
840 final String[] details = ComputedFont.getDetails(font);
841 if (details != null) {
842 setStyleAttribute(Definition.FONT_FAMILY.getAttributeName(), details[ComputedFont.FONT_FAMILY_INDEX]);
843 final String fontSize = details[ComputedFont.FONT_SIZE_INDEX];
844 if (details[ComputedFont.LINE_HEIGHT_INDEX] != null) {
845 setStyleAttribute(Definition.LINE_HEIGHT.getAttributeName(), details[ComputedFont.LINE_HEIGHT_INDEX]);
846 }
847 setStyleAttribute(Definition.FONT_SIZE.getAttributeName(), fontSize);
848 updateFont(font, true);
849 }
850 }
851
852
853
854
855
856 @JsxGetter
857 public String getHeight() {
858 if (styleDeclaration_ == null) {
859 return null;
860 }
861 return styleDeclaration_.getHeight();
862 }
863
864
865
866
867
868 @JsxSetter
869 public void setHeight(final Object height) {
870 setStyleLengthAttribute(Definition.HEIGHT.getAttributeName(), height, "", true, true, false, null);
871 }
872
873
874
875
876
877 @JsxGetter
878 public String getLeft() {
879 if (styleDeclaration_ == null) {
880 return null;
881 }
882 return styleDeclaration_.getLeft();
883 }
884
885
886
887
888
889 @JsxSetter
890 public void setLeft(final Object left) {
891 setStyleLengthAttribute(Definition.LEFT.getAttributeName(), left, "", true, true, false, null);
892 }
893
894
895
896
897
898 @JsxGetter
899 public int getLength() {
900 if (styleDeclaration_ == null) {
901 return 0;
902 }
903 return styleDeclaration_.getLength();
904 }
905
906
907
908
909
910 @JsxFunction
911 public String item(final int index) {
912 if (styleDeclaration_ == null) {
913 return null;
914 }
915
916 return styleDeclaration_.item(index);
917 }
918
919
920
921
922
923 @JsxSymbol(symbolName = "iterator")
924 public Scriptable values() {
925 return JavaScriptEngine.newArrayIteratorTypeValues(getParentScope(), this);
926 }
927
928
929
930
931
932 @JsxGetter
933 public String getLetterSpacing() {
934 if (styleDeclaration_ == null) {
935 return null;
936 }
937 return styleDeclaration_.getLetterSpacing();
938 }
939
940
941
942
943
944 @JsxSetter
945 public void setLetterSpacing(final Object letterSpacing) {
946 setStyleLengthAttribute(Definition.LETTER_SPACING.getAttributeName(), letterSpacing, "",
947 false, false, false, null);
948 }
949
950
951
952
953
954 @JsxGetter
955 public String getMargin() {
956 if (styleDeclaration_ == null) {
957 return null;
958 }
959 return styleDeclaration_.getMargin();
960 }
961
962
963
964
965
966 @JsxSetter
967 public void setMargin(final String margin) {
968 setStyleAttribute(Definition.MARGIN.getAttributeName(), margin);
969 }
970
971
972
973
974
975 @JsxGetter
976 public String getMarginBottom() {
977 if (styleDeclaration_ == null) {
978 return null;
979 }
980 return styleDeclaration_.getMarginBottom();
981 }
982
983
984
985
986
987 @JsxSetter
988 public void setMarginBottom(final Object marginBottom) {
989 setStyleLengthAttribute(Definition.MARGIN_BOTTOM.getAttributeName(), marginBottom, "", true, true, false, null);
990 }
991
992
993
994
995
996 @JsxGetter
997 public String getMarginLeft() {
998 if (styleDeclaration_ == null) {
999 return null;
1000 }
1001 return styleDeclaration_.getMarginLeft();
1002 }
1003
1004
1005
1006
1007
1008 @JsxSetter
1009 public void setMarginLeft(final Object marginLeft) {
1010 setStyleLengthAttribute(Definition.MARGIN_LEFT.getAttributeName(), marginLeft, "", true, true, false, null);
1011 }
1012
1013
1014
1015
1016
1017 @JsxGetter
1018 public String getMarginRight() {
1019 if (styleDeclaration_ == null) {
1020 return null;
1021 }
1022 return styleDeclaration_.getMarginRight();
1023 }
1024
1025
1026
1027
1028
1029 @JsxSetter
1030 public void setMarginRight(final Object marginRight) {
1031 setStyleLengthAttribute(Definition.MARGIN_RIGHT.getAttributeName(), marginRight, "", true, true, false, null);
1032 }
1033
1034
1035
1036
1037
1038 @JsxGetter
1039 public String getMarginTop() {
1040 if (styleDeclaration_ == null) {
1041 return null;
1042 }
1043 return styleDeclaration_.getMarginTop();
1044 }
1045
1046
1047
1048
1049
1050 @JsxSetter
1051 public void setMarginTop(final Object marginTop) {
1052 setStyleLengthAttribute(Definition.MARGIN_TOP.getAttributeName(), marginTop, "", true, true, false, null);
1053 }
1054
1055
1056
1057
1058
1059 @JsxGetter
1060 public String getMaxHeight() {
1061 if (styleDeclaration_ == null) {
1062 return null;
1063 }
1064 return styleDeclaration_.getMaxHeight();
1065 }
1066
1067
1068
1069
1070
1071 @JsxSetter
1072 public void setMaxHeight(final Object maxHeight) {
1073 setStyleLengthAttribute(Definition.MAX_HEIGHT.getAttributeName(), maxHeight, "", false, true, false, null);
1074 }
1075
1076
1077
1078
1079
1080 @JsxGetter
1081 public String getMaxWidth() {
1082 if (styleDeclaration_ == null) {
1083 return null;
1084 }
1085 return styleDeclaration_.getMaxWidth();
1086 }
1087
1088
1089
1090
1091
1092 @JsxSetter
1093 public void setMaxWidth(final Object maxWidth) {
1094 setStyleLengthAttribute(Definition.MAX_WIDTH.getAttributeName(), maxWidth, "", false, true, false, null);
1095 }
1096
1097
1098
1099
1100
1101 @JsxGetter
1102 public String getMinHeight() {
1103 if (styleDeclaration_ == null) {
1104 return null;
1105 }
1106 return styleDeclaration_.getMinHeight();
1107 }
1108
1109
1110
1111
1112
1113 @JsxSetter
1114 public void setMinHeight(final Object minHeight) {
1115 setStyleLengthAttribute(Definition.MIN_HEIGHT.getAttributeName(), minHeight, "", true, true, false, null);
1116 }
1117
1118
1119
1120
1121
1122 @JsxGetter
1123 public String getMinWidth() {
1124 if (styleDeclaration_ == null) {
1125 return null;
1126 }
1127 return styleDeclaration_.getMinWidth();
1128 }
1129
1130
1131
1132
1133
1134 @JsxSetter
1135 public void setMinWidth(final Object minWidth) {
1136 setStyleLengthAttribute(Definition.MIN_WIDTH.getAttributeName(), minWidth, "", true, true, false, null);
1137 }
1138
1139
1140
1141
1142 @Override
1143 public Object get(final String name, final Scriptable start) {
1144 if (this != start) {
1145 return super.get(name, start);
1146 }
1147
1148 Scriptable prototype = getPrototype();
1149 while (prototype != null) {
1150 Object value = prototype.get(name, start);
1151 if (value != Scriptable.NOT_FOUND) {
1152 return value;
1153 }
1154
1155 final String camel = org.htmlunit.util.StringUtils.cssCamelize(name);
1156 if (!name.equals(camel)) {
1157 value = prototype.get(camel, start);
1158 if (value != Scriptable.NOT_FOUND) {
1159 return value;
1160 }
1161 }
1162 prototype = prototype.getPrototype();
1163 }
1164
1165 final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
1166 if (style != null) {
1167 return getStyleAttribute(style);
1168 }
1169
1170 return super.get(name, start);
1171 }
1172
1173 @Override
1174 public Object get(final int index, final Scriptable start) {
1175 if (index < 0) {
1176 return JavaScriptEngine.UNDEFINED;
1177 }
1178
1179 final Map<String, StyleElement> style = getStyleMap();
1180 final int size = style.size();
1181 if (index >= size) {
1182 return JavaScriptEngine.UNDEFINED;
1183 }
1184 return style.keySet().toArray(new String[0])[index];
1185 }
1186
1187
1188
1189
1190
1191
1192 public final String getStyleAttribute(final Definition definition) {
1193 return getStyleAttribute(definition, true);
1194 }
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204 public String getStyleAttribute(final Definition definition, final boolean getDefaultValueIfEmpty) {
1205 if (styleDeclaration_ == null) {
1206 return "";
1207 }
1208 return styleDeclaration_.getStyleAttribute(definition, getDefaultValueIfEmpty);
1209 }
1210
1211 @Override
1212 public void put(final String name, final Scriptable start, final Object value) {
1213 if (this != start) {
1214 super.put(name, start, value);
1215 return;
1216 }
1217
1218 final Scriptable prototype = getPrototype();
1219 if (prototype != null && !"constructor".equals(name)) {
1220 if (prototype.get(name, start) != Scriptable.NOT_FOUND) {
1221 prototype.put(name, start, value);
1222 return;
1223 }
1224 final String camel = org.htmlunit.util.StringUtils.cssCamelize(name);
1225 if (!name.equals(camel) && prototype.get(camel, start) != Scriptable.NOT_FOUND) {
1226 prototype.put(camel, start, value);
1227 return;
1228 }
1229 }
1230
1231 if (getDomNodeOrNull() != null) {
1232 final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
1233 if (style != null) {
1234 final String stringValue = JavaScriptEngine.toString(value);
1235 setStyleAttribute(style.getAttributeName(), stringValue);
1236 return;
1237 }
1238 }
1239
1240 super.put(name, start, value);
1241 }
1242
1243 @Override
1244 public boolean has(final String name, final Scriptable start) {
1245 if (this != start) {
1246 return super.has(name, start);
1247 }
1248
1249 final BrowserVersion browserVersion = getBrowserVersion();
1250 if (browserVersion != null) {
1251 final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
1252 if (style != null) {
1253 return true;
1254 }
1255 }
1256
1257 return super.has(name, start);
1258 }
1259
1260 @Override
1261 public Object[] getIds() {
1262 final List<Object> ids = new ArrayList<>();
1263 for (final Definition styleAttribute : StyleAttributes.getDefinitions(getBrowserVersion())) {
1264 ids.add(styleAttribute.getPropertyName());
1265 }
1266 final Object[] normalIds = super.getIds();
1267 for (final Object o : normalIds) {
1268 if (!ids.contains(o)) {
1269 ids.add(o);
1270 }
1271 }
1272 return ids.toArray();
1273 }
1274
1275
1276
1277
1278
1279 @JsxGetter
1280 public String getOpacity() {
1281 if (styleDeclaration_ == null) {
1282 return null;
1283 }
1284 return styleDeclaration_.getOpacity();
1285 }
1286
1287
1288
1289
1290
1291 @JsxSetter
1292 public void setOpacity(final Object opacity) {
1293 if (JavaScriptEngine.isNaN(opacity)) {
1294 return;
1295 }
1296
1297 final double doubleValue;
1298 if (opacity instanceof Number) {
1299 doubleValue = ((Number) opacity).doubleValue();
1300 }
1301 else {
1302 String valueString = JavaScriptEngine.toString(opacity);
1303
1304 if (valueString.isEmpty()) {
1305 setStyleAttribute(Definition.OPACITY.getAttributeName(), valueString);
1306 return;
1307 }
1308
1309 valueString = valueString.trim();
1310 try {
1311 doubleValue = Double.parseDouble(valueString);
1312 }
1313 catch (final NumberFormatException e) {
1314
1315 return;
1316 }
1317 }
1318
1319 if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
1320 return;
1321 }
1322 setStyleAttribute(Definition.OPACITY.getAttributeName(), Double.toString(doubleValue));
1323 }
1324
1325
1326
1327
1328
1329 @JsxGetter
1330 public String getOutline() {
1331 if (styleDeclaration_ == null) {
1332 return null;
1333 }
1334 return styleDeclaration_.getOutline();
1335 }
1336
1337
1338
1339
1340
1341 @JsxSetter
1342 public void setOutline(final String outline) {
1343 setStyleAttribute(Definition.OUTLINE.getAttributeName(), outline);
1344 }
1345
1346
1347
1348
1349
1350 @JsxGetter
1351 public String getOutlineWidth() {
1352 if (styleDeclaration_ == null) {
1353 return null;
1354 }
1355 return styleDeclaration_.getOutlineWidth();
1356 }
1357
1358
1359
1360
1361
1362 @JsxSetter
1363 public void setOutlineWidth(final Object outlineWidth) {
1364 setStyleLengthAttribute(Definition.OUTLINE_WIDTH.getAttributeName(), outlineWidth, "",
1365 false, false, true, THIN_MED_THICK);
1366 }
1367
1368
1369
1370
1371
1372 @JsxGetter
1373 public String getPadding() {
1374 if (styleDeclaration_ == null) {
1375 return null;
1376 }
1377 return styleDeclaration_.getPadding();
1378 }
1379
1380
1381
1382
1383
1384 @JsxSetter
1385 public void setPadding(final String padding) {
1386 setStyleAttribute(Definition.PADDING.getAttributeName(), padding);
1387 }
1388
1389
1390
1391
1392
1393 @JsxGetter
1394 public String getPaddingBottom() {
1395 if (styleDeclaration_ == null) {
1396 return null;
1397 }
1398 return styleDeclaration_.getPaddingBottom();
1399 }
1400
1401
1402
1403
1404
1405 @JsxSetter
1406 public void setPaddingBottom(final Object paddingBottom) {
1407 setStyleLengthAttribute(Definition.PADDING_BOTTOM.getAttributeName(),
1408 paddingBottom, "", false, true, false, null);
1409 }
1410
1411
1412
1413
1414
1415 @JsxGetter
1416 public String getPaddingLeft() {
1417 if (styleDeclaration_ == null) {
1418 return null;
1419 }
1420 return styleDeclaration_.getPaddingLeft();
1421 }
1422
1423
1424
1425
1426
1427 @JsxSetter
1428 public void setPaddingLeft(final Object paddingLeft) {
1429 setStyleLengthAttribute(Definition.PADDING_LEFT.getAttributeName(), paddingLeft, "", false, true, false, null);
1430 }
1431
1432
1433
1434
1435
1436 @JsxGetter
1437 public String getPaddingRight() {
1438 if (styleDeclaration_ == null) {
1439 return null;
1440 }
1441 return styleDeclaration_.getPaddingRight();
1442 }
1443
1444
1445
1446
1447
1448 @JsxSetter
1449 public void setPaddingRight(final Object paddingRight) {
1450 setStyleLengthAttribute(Definition.PADDING_RIGHT.getAttributeName(),
1451 paddingRight, "", false, true, false, null);
1452 }
1453
1454
1455
1456
1457
1458 @JsxGetter
1459 public String getPaddingTop() {
1460 if (styleDeclaration_ == null) {
1461 return null;
1462 }
1463 return styleDeclaration_.getPaddingTop();
1464 }
1465
1466
1467
1468
1469
1470 @JsxSetter
1471 public void setPaddingTop(final Object paddingTop) {
1472 setStyleLengthAttribute(Definition.PADDING_TOP.getAttributeName(), paddingTop, "", false, true, false, null);
1473 }
1474
1475
1476
1477
1478
1479
1480
1481 @JsxGetter
1482 public CSSRule getParentRule() {
1483 final AbstractCSSRuleImpl parentRule = styleDeclaration_.getParentRule();
1484 if (parentRule != null) {
1485 return CSSRule.create((CSSStyleSheet) getParentScope(), parentRule);
1486 }
1487 return null;
1488 }
1489
1490
1491
1492
1493
1494 @JsxSetter
1495 public void setParentRule(final CSSRule parentRule) {
1496
1497 }
1498
1499
1500
1501
1502
1503 @JsxGetter
1504 public String getRight() {
1505 if (styleDeclaration_ == null) {
1506 return null;
1507 }
1508 return styleDeclaration_.getRight();
1509 }
1510
1511
1512
1513
1514
1515 @JsxSetter
1516 public void setRight(final Object right) {
1517 setStyleLengthAttribute(Definition.RIGHT.getAttributeName(), right, "", true, true, false, null);
1518 }
1519
1520
1521
1522
1523
1524 @JsxGetter
1525 public String getRubyAlign() {
1526 if (styleDeclaration_ == null) {
1527 return null;
1528 }
1529 return styleDeclaration_.getRubyAlign();
1530 }
1531
1532
1533
1534
1535
1536 @JsxSetter
1537 public void setRubyAlign(final String rubyAlign) {
1538 setStyleAttribute(Definition.RUBY_ALIGN.getAttributeName(), rubyAlign);
1539 }
1540
1541
1542
1543
1544
1545 @JsxGetter({CHROME, EDGE})
1546 public String getSize() {
1547 if (styleDeclaration_ == null) {
1548 return null;
1549 }
1550 return styleDeclaration_.getSize();
1551 }
1552
1553
1554
1555
1556
1557 @JsxSetter({CHROME, EDGE})
1558 public void setSize(final String size) {
1559 setStyleAttribute(Definition.SIZE.getAttributeName(), size);
1560 }
1561
1562
1563
1564
1565
1566 @JsxGetter
1567 public String getTextIndent() {
1568 if (styleDeclaration_ == null) {
1569 return null;
1570 }
1571 return styleDeclaration_.getTextIndent();
1572 }
1573
1574
1575
1576
1577
1578 @JsxSetter
1579 public void setTextIndent(final Object textIndent) {
1580 setStyleLengthAttribute(Definition.TEXT_INDENT.getAttributeName(), textIndent, "", false, true, false, null);
1581 }
1582
1583
1584
1585
1586
1587 @JsxGetter
1588 public String getTop() {
1589 if (styleDeclaration_ == null) {
1590 return null;
1591 }
1592 return styleDeclaration_.getTop();
1593 }
1594
1595
1596
1597
1598
1599 @JsxSetter
1600 public void setTop(final Object top) {
1601 setStyleLengthAttribute(Definition.TOP.getAttributeName(), top, "", true, true, false, null);
1602 }
1603
1604
1605
1606
1607
1608 @JsxGetter
1609 public String getVerticalAlign() {
1610 if (styleDeclaration_ == null) {
1611 return null;
1612 }
1613 return styleDeclaration_.getVerticalAlign();
1614 }
1615
1616
1617
1618
1619
1620 @JsxSetter
1621 public void setVerticalAlign(final Object verticalAlign) {
1622 setStyleLengthAttribute(Definition.VERTICAL_ALIGN.getAttributeName(),
1623 verticalAlign, "", false, true, false, ALIGN_KEYWORDS);
1624 }
1625
1626
1627
1628
1629
1630 @JsxGetter
1631 public String getWidth() {
1632 if (styleDeclaration_ == null) {
1633 return null;
1634 }
1635 return styleDeclaration_.getWidth();
1636 }
1637
1638
1639
1640
1641
1642 @JsxSetter
1643 public void setWidth(final Object width) {
1644 setStyleLengthAttribute(Definition.WIDTH.getAttributeName(), width, "", true, true, false, null);
1645 }
1646
1647
1648
1649
1650
1651 @JsxGetter({CHROME, EDGE})
1652 public String getWidows() {
1653 if (styleDeclaration_ == null) {
1654 return null;
1655 }
1656 return styleDeclaration_.getWidows();
1657 }
1658
1659
1660
1661
1662
1663 @JsxSetter({CHROME, EDGE})
1664 public void setWidows(final String widows) {
1665 if (getBrowserVersion().hasFeature(CSS_BACKGROUND_INITIAL)) {
1666 try {
1667 if (Integer.parseInt(widows) <= 0) {
1668 return;
1669 }
1670 }
1671 catch (final NumberFormatException e) {
1672 return;
1673 }
1674 }
1675 setStyleAttribute(Definition.WIDOWS.getAttributeName(), widows);
1676 }
1677
1678
1679
1680
1681
1682 @JsxGetter({CHROME, EDGE})
1683 public String getOrphans() {
1684 if (styleDeclaration_ == null) {
1685 return null;
1686 }
1687 return styleDeclaration_.getOrphans();
1688 }
1689
1690
1691
1692
1693
1694 @JsxSetter({CHROME, EDGE})
1695 public void setOrphans(final String orphans) {
1696 if (getBrowserVersion().hasFeature(CSS_BACKGROUND_INITIAL)) {
1697 try {
1698 if (Integer.parseInt(orphans) <= 0) {
1699 return;
1700 }
1701 }
1702 catch (final NumberFormatException e) {
1703 return;
1704 }
1705 }
1706 setStyleAttribute(Definition.ORPHANS.getAttributeName(), orphans);
1707 }
1708
1709
1710
1711
1712
1713 @JsxGetter
1714 public String getPosition() {
1715 if (styleDeclaration_ == null) {
1716 return null;
1717 }
1718 return styleDeclaration_.getPosition();
1719 }
1720
1721
1722
1723
1724
1725 @JsxSetter
1726 public void setPosition(final String position) {
1727 if (position.isEmpty() || STATIC.equalsIgnoreCase(position) || ABSOLUTE.equalsIgnoreCase(position)
1728 || FIXED.equalsIgnoreCase(position) || RELATIVE.equalsIgnoreCase(position)
1729 || INITIAL.equalsIgnoreCase(position) || INHERIT.equalsIgnoreCase(position)) {
1730 setStyleAttribute(Definition.POSITION.getAttributeName(), position.toLowerCase(Locale.ROOT));
1731 }
1732 }
1733
1734
1735
1736
1737
1738 @JsxGetter
1739 public String getWordSpacing() {
1740 if (styleDeclaration_ == null) {
1741 return null;
1742 }
1743 return styleDeclaration_.getWordSpacing();
1744 }
1745
1746
1747
1748
1749
1750 @JsxSetter
1751 public void setWordSpacing(final Object wordSpacing) {
1752 setStyleLengthAttribute(Definition.WORD_SPACING.getAttributeName(), wordSpacing, "",
1753 false, getBrowserVersion().hasFeature(JS_STYLE_WORD_SPACING_ACCEPTS_PERCENT), false, null);
1754 }
1755
1756
1757
1758
1759
1760 @JsxGetter
1761 public String getZIndex() {
1762 if (styleDeclaration_ == null) {
1763 return null;
1764 }
1765 return styleDeclaration_.getZIndex();
1766 }
1767
1768
1769
1770
1771
1772 @JsxSetter
1773 public void setZIndex(final Object zIndex) {
1774
1775 if (zIndex == null || StringUtils.isEmpty(zIndex.toString())) {
1776 setStyleAttribute(Definition.Z_INDEX_.getAttributeName(), "");
1777 return;
1778 }
1779
1780 if (JavaScriptEngine.isUndefined(zIndex)) {
1781 return;
1782 }
1783
1784
1785 if (zIndex instanceof Number) {
1786 final Number number = (Number) zIndex;
1787 if (number.doubleValue() % 1 == 0) {
1788 setStyleAttribute(Definition.Z_INDEX_.getAttributeName(), Integer.toString(number.intValue()));
1789 }
1790 return;
1791 }
1792 try {
1793 final int i = Integer.parseInt(zIndex.toString());
1794 setStyleAttribute(Definition.Z_INDEX_.getAttributeName(), Integer.toString(i));
1795 }
1796 catch (final NumberFormatException ignored) {
1797
1798 }
1799 }
1800
1801
1802
1803
1804
1805
1806 @JsxFunction
1807 public String getPropertyValue(final String name) {
1808 if (name != null && name.contains("-")) {
1809 final Object value = getProperty(this, org.htmlunit.util.StringUtils.cssCamelize(name));
1810 if (value instanceof String) {
1811 return (String) value;
1812 }
1813 }
1814
1815 return styleDeclaration_.getStyleAttribute(name);
1816 }
1817
1818
1819
1820
1821
1822
1823 @JsxFunction
1824 public String getPropertyPriority(final String name) {
1825 return getStylePriority(name);
1826 }
1827
1828
1829
1830
1831
1832
1833
1834
1835 @JsxFunction
1836 public void setProperty(final String name, final Object value, final String important) {
1837 String imp = "";
1838 if (!StringUtils.isEmpty(important) && !"null".equals(important)) {
1839 if (!StyleElement.PRIORITY_IMPORTANT.equalsIgnoreCase(important)) {
1840 return;
1841 }
1842 imp = StyleElement.PRIORITY_IMPORTANT;
1843 }
1844
1845 if (LENGTH_PROPERTIES_FFFF.contains(name)) {
1846 setStyleLengthAttribute(name, value, imp, false, false, false, null);
1847 }
1848 else if (LENGTH_PROPERTIES_TTFF.contains(name)) {
1849 setStyleLengthAttribute(name, value, imp, true, true, false, null);
1850 }
1851 else if (LENGTH_PROPERTIES_FTFF.contains(name)) {
1852 setStyleLengthAttribute(name, value, imp, false, true, false, null);
1853 }
1854 else if (Definition.OUTLINE_WIDTH.getAttributeName().equals(name)) {
1855 setStyleLengthAttribute(Definition.OUTLINE_WIDTH.getAttributeName(),
1856 value, imp, false, false, true, THIN_MED_THICK);
1857 }
1858 else if (Definition.WORD_SPACING.getAttributeName().equals(name)) {
1859 setStyleLengthAttribute(Definition.WORD_SPACING.getAttributeName(), value, imp,
1860 false, getBrowserVersion().hasFeature(JS_STYLE_WORD_SPACING_ACCEPTS_PERCENT), false, null);
1861 }
1862 else if (Definition.VERTICAL_ALIGN.getAttributeName().equals(name)) {
1863 setStyleLengthAttribute(Definition.VERTICAL_ALIGN.getAttributeName(), value, imp, false, true, false, null);
1864 }
1865 else {
1866 setStyleAttribute(name, JavaScriptEngine.toString(value), imp);
1867 }
1868 }
1869
1870
1871
1872
1873
1874
1875 @JsxFunction
1876 public String removeProperty(final Object name) {
1877 return removeStyleAttribute(JavaScriptEngine.toString(name));
1878 }
1879
1880
1881
1882
1883
1884
1885 static boolean isLength(String token) {
1886 if (token.endsWith("em") || token.endsWith("ex") || token.endsWith("px") || token.endsWith("in")
1887 || token.endsWith("cm") || token.endsWith("mm") || token.endsWith("pt") || token.endsWith("pc")
1888 || token.endsWith("%")) {
1889
1890 if (token.endsWith("%")) {
1891 token = token.substring(0, token.length() - 1);
1892 }
1893 else {
1894 token = token.substring(0, token.length() - 2);
1895 }
1896 try {
1897 Double.parseDouble(token);
1898 return true;
1899 }
1900 catch (final NumberFormatException ignored) {
1901
1902 }
1903 }
1904 return false;
1905 }
1906
1907
1908
1909
1910 @Override
1911 public String toString() {
1912 if (styleDeclaration_ == null) {
1913 return "CSSStyleDeclaration for 'null'";
1914 }
1915
1916 return "CSSStyleDeclaration for '" + styleDeclaration_ + "'";
1917 }
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929 private void setStyleLengthAttribute(final String name, final Object value, final String important,
1930 final boolean auto, final boolean percent, final boolean unitRequired, final String[] validValues) {
1931
1932 if (JavaScriptEngine.isNaN(value)) {
1933 return;
1934 }
1935
1936 final double doubleValue;
1937 String unit = "px";
1938 if (value instanceof Number) {
1939 if (unitRequired) {
1940 return;
1941 }
1942 doubleValue = ((Number) value).doubleValue();
1943 }
1944 else {
1945 String valueString = JavaScriptEngine.toString(value);
1946 if (null == value) {
1947 valueString = "";
1948 }
1949
1950 if (StringUtils.isEmpty(valueString)) {
1951 setStyleAttribute(name, valueString, important);
1952 return;
1953 }
1954
1955 if ((auto && AUTO.equals(valueString))
1956 || INITIAL.equals(valueString)
1957 || INHERIT.equals(valueString)) {
1958 setStyleAttribute(name, valueString, important);
1959 return;
1960 }
1961
1962 if (validValues != null && ArrayUtils.contains(validValues, valueString)) {
1963 setStyleAttribute(name, valueString, important);
1964 return;
1965 }
1966
1967 if (percent && valueString.endsWith("%")) {
1968 unit = valueString.substring(valueString.length() - 1);
1969 valueString = valueString.substring(0, valueString.length() - 1);
1970 }
1971 else if (valueString.endsWith("px")
1972 || valueString.endsWith("em")
1973 || valueString.endsWith("ex")
1974 || valueString.endsWith("pt")
1975 || valueString.endsWith("cm")
1976 || valueString.endsWith("mm")
1977 || valueString.endsWith("in")
1978 || valueString.endsWith("pc")
1979 || valueString.endsWith("ch")
1980 || valueString.endsWith("vh")
1981 || valueString.endsWith("vw")) {
1982 unit = valueString.substring(valueString.length() - 2);
1983 valueString = valueString.substring(0, valueString.length() - 2);
1984 }
1985 else if (valueString.endsWith("rem")
1986 || valueString.endsWith("vmin")
1987 || valueString.endsWith("vmax")) {
1988 unit = valueString.substring(valueString.length() - 3);
1989 valueString = valueString.substring(0, valueString.length() - 3);
1990 }
1991 else if (unitRequired) {
1992 return;
1993 }
1994
1995 if (!valueString.equals(valueString.trim())) {
1996
1997 return;
1998 }
1999 doubleValue = JavaScriptEngine.toNumber(valueString);
2000 }
2001
2002 try {
2003 if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
2004 return;
2005 }
2006
2007 final String valueString;
2008 if (doubleValue % 1 == 0) {
2009 valueString = (int) doubleValue + unit;
2010 }
2011 else {
2012 valueString = doubleValue + unit;
2013 }
2014
2015 setStyleAttribute(name, valueString, important);
2016 }
2017 catch (final Exception ignored) {
2018
2019 }
2020 }
2021 }