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