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_LETTER_SPACING_ACCEPTS_PERCENT;
19 import static org.htmlunit.BrowserVersionFeatures.JS_STYLE_WORD_SPACING_ACCEPTS_PERCENT;
20 import static org.htmlunit.css.CssStyleSheet.ABSOLUTE;
21 import static org.htmlunit.css.CssStyleSheet.AUTO;
22 import static org.htmlunit.css.CssStyleSheet.FIXED;
23 import static org.htmlunit.css.CssStyleSheet.INHERIT;
24 import static org.htmlunit.css.CssStyleSheet.INITIAL;
25 import static org.htmlunit.css.CssStyleSheet.RELATIVE;
26 import static org.htmlunit.css.CssStyleSheet.STATIC;
27 import static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
28 import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
29
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.HashSet;
34 import java.util.LinkedHashMap;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.Map;
38 import java.util.Set;
39
40 import org.apache.commons.lang3.ArrayUtils;
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.cssparser.dom.DOMExceptionImpl;
51 import org.htmlunit.javascript.HtmlUnitScriptable;
52 import org.htmlunit.javascript.JavaScriptEngine;
53 import org.htmlunit.javascript.configuration.JsxClass;
54 import org.htmlunit.javascript.configuration.JsxConstructor;
55 import org.htmlunit.javascript.configuration.JsxFunction;
56 import org.htmlunit.javascript.configuration.JsxGetter;
57 import org.htmlunit.javascript.configuration.JsxSetter;
58 import org.htmlunit.javascript.configuration.JsxSymbol;
59 import org.htmlunit.javascript.host.Element;
60 import org.htmlunit.util.StringUtils;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 @JsxClass
78 public class CSSStyleDeclaration extends HtmlUnitScriptable {
79
80 private static final Set<String> LENGTH_PROPERTIES_FFFF = new HashSet<>(Arrays.asList(
81 Definition.BORDER_TOP_WIDTH.getAttributeName(),
82 Definition.BORDER_LEFT_WIDTH.getAttributeName(),
83 Definition.BORDER_BOTTOM_WIDTH.getAttributeName(),
84 Definition.BORDER_RIGHT_WIDTH.getAttributeName()));
85
86 private static final Set<String> LENGTH_PROPERTIES_TTFF = new HashSet<>(Arrays.asList(
87 Definition.HEIGHT.getAttributeName(),
88 Definition.WIDTH.getAttributeName(),
89 Definition.TOP.getAttributeName(),
90 Definition.LEFT.getAttributeName(),
91 Definition.BOTTOM.getAttributeName(),
92 Definition.RIGHT.getAttributeName(),
93 Definition.MARGIN_TOP.getAttributeName(),
94 Definition.MARGIN_LEFT.getAttributeName(),
95 Definition.MARGIN_BOTTOM.getAttributeName(),
96 Definition.MARGIN_RIGHT.getAttributeName(),
97 Definition.MIN_HEIGHT.getAttributeName(),
98 Definition.MIN_WIDTH.getAttributeName()
99 ));
100
101 private static final Set<String> LENGTH_PROPERTIES_FTFF = new HashSet<>(Arrays.asList(
102 Definition.FONT_SIZE.getAttributeName(),
103 Definition.TEXT_INDENT.getAttributeName(),
104 Definition.PADDING_TOP.getAttributeName(),
105 Definition.PADDING_LEFT.getAttributeName(),
106 Definition.PADDING_BOTTOM.getAttributeName(),
107 Definition.PADDING_RIGHT.getAttributeName(),
108 Definition.MAX_HEIGHT.getAttributeName(),
109 Definition.MAX_WIDTH.getAttributeName()
110 ));
111
112 private static final String[] THIN_MED_THICK = {"thin", "medium", "thick"};
113 private static final String[] ALIGN_KEYWORDS =
114 {"baseline", "sub", "super", "text-top", "text-bottom", "middle", "top", "bottom",
115 "inherit", "initial", "revert", "unset"};
116 private static final String[] FONT_SIZES =
117 {"xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large",
118 "smaller", "larger"};
119
120
121
122
123 private AbstractCssStyleDeclaration styleDeclaration_;
124
125
126
127
128 public CSSStyleDeclaration() {
129 super();
130 }
131
132
133
134
135
136
137
138 @JsxConstructor
139 public void jsConstructor(final String type, final ScriptableObject details) {
140 throw JavaScriptEngine.typeError("CSSStyleDeclaration ctor is not available");
141 }
142
143
144
145
146
147
148 public CSSStyleDeclaration(final Element element, final AbstractCssStyleDeclaration styleDeclaration) {
149 super();
150 setParentScope(element.getParentScope());
151 setPrototype(getPrototype(getClass()));
152
153 setDomNode(element.getDomNodeOrNull(), false);
154
155 if (styleDeclaration == null) {
156 throw new IllegalStateException("styleDeclaration can't be null");
157 }
158 styleDeclaration_ = styleDeclaration;
159 }
160
161
162
163
164
165
166 CSSStyleDeclaration(final CSSStyleSheet parentStyleSheet, final WrappedCssStyleDeclaration styleDeclaration) {
167 super();
168 setParentScope(parentStyleSheet);
169 setPrototype(getPrototype(getClass()));
170
171 if (styleDeclaration == null) {
172 throw new IllegalStateException("styleDeclaration can't be null");
173 }
174 styleDeclaration_ = styleDeclaration;
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, "",
969 false, getBrowserVersion().hasFeature(JS_STYLE_LETTER_SPACING_ACCEPTS_PERCENT), null);
970 }
971
972
973
974
975
976 @JsxGetter
977 public String getMargin() {
978 if (styleDeclaration_ == null) {
979 return null;
980 }
981 return styleDeclaration_.getMargin();
982 }
983
984
985
986
987
988 @JsxSetter
989 public void setMargin(final String margin) {
990 setStyleAttribute(Definition.MARGIN.getAttributeName(), margin);
991 }
992
993
994
995
996
997 @JsxGetter
998 public String getMarginBottom() {
999 if (styleDeclaration_ == null) {
1000 return null;
1001 }
1002 return styleDeclaration_.getMarginBottom();
1003 }
1004
1005
1006
1007
1008
1009 @JsxSetter
1010 public void setMarginBottom(final Object marginBottom) {
1011 setStyleLengthAttribute(Definition.MARGIN_BOTTOM.getAttributeName(), marginBottom, "", true, true, null);
1012 }
1013
1014
1015
1016
1017
1018 @JsxGetter
1019 public String getMarginLeft() {
1020 if (styleDeclaration_ == null) {
1021 return null;
1022 }
1023 return styleDeclaration_.getMarginLeft();
1024 }
1025
1026
1027
1028
1029
1030 @JsxSetter
1031 public void setMarginLeft(final Object marginLeft) {
1032 setStyleLengthAttribute(Definition.MARGIN_LEFT.getAttributeName(), marginLeft, "", true, true, null);
1033 }
1034
1035
1036
1037
1038
1039 @JsxGetter
1040 public String getMarginRight() {
1041 if (styleDeclaration_ == null) {
1042 return null;
1043 }
1044 return styleDeclaration_.getMarginRight();
1045 }
1046
1047
1048
1049
1050
1051 @JsxSetter
1052 public void setMarginRight(final Object marginRight) {
1053 setStyleLengthAttribute(Definition.MARGIN_RIGHT.getAttributeName(), marginRight, "", true, true, null);
1054 }
1055
1056
1057
1058
1059
1060 @JsxGetter
1061 public String getMarginTop() {
1062 if (styleDeclaration_ == null) {
1063 return null;
1064 }
1065 return styleDeclaration_.getMarginTop();
1066 }
1067
1068
1069
1070
1071
1072 @JsxSetter
1073 public void setMarginTop(final Object marginTop) {
1074 setStyleLengthAttribute(Definition.MARGIN_TOP.getAttributeName(), marginTop, "", true, true, null);
1075 }
1076
1077
1078
1079
1080
1081 @JsxGetter
1082 public String getMaxHeight() {
1083 if (styleDeclaration_ == null) {
1084 return null;
1085 }
1086 return styleDeclaration_.getMaxHeight();
1087 }
1088
1089
1090
1091
1092
1093 @JsxSetter
1094 public void setMaxHeight(final Object maxHeight) {
1095 setStyleLengthAttribute(Definition.MAX_HEIGHT.getAttributeName(), maxHeight, "", false, true, null);
1096 }
1097
1098
1099
1100
1101
1102 @JsxGetter
1103 public String getMaxWidth() {
1104 if (styleDeclaration_ == null) {
1105 return null;
1106 }
1107 return styleDeclaration_.getMaxWidth();
1108 }
1109
1110
1111
1112
1113
1114 @JsxSetter
1115 public void setMaxWidth(final Object maxWidth) {
1116 setStyleLengthAttribute(Definition.MAX_WIDTH.getAttributeName(), maxWidth, "", false, true, null);
1117 }
1118
1119
1120
1121
1122
1123 @JsxGetter
1124 public String getMinHeight() {
1125 if (styleDeclaration_ == null) {
1126 return null;
1127 }
1128 return styleDeclaration_.getMinHeight();
1129 }
1130
1131
1132
1133
1134
1135 @JsxSetter
1136 public void setMinHeight(final Object minHeight) {
1137 setStyleLengthAttribute(Definition.MIN_HEIGHT.getAttributeName(), minHeight, "", true, true, null);
1138 }
1139
1140
1141
1142
1143
1144 @JsxGetter
1145 public String getMinWidth() {
1146 if (styleDeclaration_ == null) {
1147 return null;
1148 }
1149 return styleDeclaration_.getMinWidth();
1150 }
1151
1152
1153
1154
1155
1156 @JsxSetter
1157 public void setMinWidth(final Object minWidth) {
1158 setStyleLengthAttribute(Definition.MIN_WIDTH.getAttributeName(), minWidth, "", true, true, null);
1159 }
1160
1161
1162
1163
1164 @Override
1165 public Object get(final String name, final Scriptable start) {
1166 if (this != start) {
1167 return super.get(name, start);
1168 }
1169
1170 Scriptable prototype = getPrototype();
1171 while (prototype != null) {
1172 Object value = prototype.get(name, start);
1173 if (value != Scriptable.NOT_FOUND) {
1174 return value;
1175 }
1176
1177 final String camel = StringUtils.cssCamelize(name);
1178 if (!name.equals(camel)) {
1179 value = prototype.get(camel, start);
1180 if (value != Scriptable.NOT_FOUND) {
1181 return value;
1182 }
1183 }
1184 prototype = prototype.getPrototype();
1185 }
1186
1187 final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
1188 if (style != null) {
1189 return getStyleAttribute(style);
1190 }
1191
1192 return super.get(name, start);
1193 }
1194
1195 @Override
1196 public Object get(final int index, final Scriptable start) {
1197 if (index < 0) {
1198 return JavaScriptEngine.UNDEFINED;
1199 }
1200
1201 final Map<String, StyleElement> style = getStyleMap();
1202 final int size = style.size();
1203 if (index >= size) {
1204 return JavaScriptEngine.UNDEFINED;
1205 }
1206 return style.keySet().toArray(new String[0])[index];
1207 }
1208
1209
1210
1211
1212
1213
1214 public final String getStyleAttribute(final Definition definition) {
1215 return getStyleAttribute(definition, true);
1216 }
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 public String getStyleAttribute(final Definition definition, final boolean getDefaultValueIfEmpty) {
1227 if (styleDeclaration_ == null) {
1228 return "";
1229 }
1230 return styleDeclaration_.getStyleAttribute(definition, getDefaultValueIfEmpty);
1231 }
1232
1233 @Override
1234 public void put(final String name, final Scriptable start, final Object value) {
1235 if (this != start) {
1236 super.put(name, start, value);
1237 return;
1238 }
1239
1240 final Scriptable prototype = getPrototype();
1241 if (prototype != null && !"constructor".equals(name)) {
1242 if (prototype.get(name, start) != Scriptable.NOT_FOUND) {
1243 prototype.put(name, start, value);
1244 return;
1245 }
1246 final String camel = StringUtils.cssCamelize(name);
1247 if (!name.equals(camel) && prototype.get(camel, start) != Scriptable.NOT_FOUND) {
1248 prototype.put(camel, start, value);
1249 return;
1250 }
1251 }
1252
1253 if (getDomNodeOrNull() != null) {
1254 final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
1255 if (style != null) {
1256 final String stringValue = JavaScriptEngine.toString(value);
1257 setStyleAttribute(style.getAttributeName(), stringValue);
1258 return;
1259 }
1260 }
1261
1262 super.put(name, start, value);
1263 }
1264
1265 @Override
1266 public boolean has(final String name, final Scriptable start) {
1267 if (this != start) {
1268 return super.has(name, start);
1269 }
1270
1271 final BrowserVersion browserVersion = getBrowserVersion();
1272 if (browserVersion != null) {
1273 final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
1274 if (style != null) {
1275 return true;
1276 }
1277 }
1278
1279 return super.has(name, start);
1280 }
1281
1282 @Override
1283 public Object[] getIds() {
1284 final List<Object> ids = new ArrayList<>();
1285 for (final Definition styleAttribute : StyleAttributes.getDefinitions(getBrowserVersion())) {
1286 ids.add(styleAttribute.getPropertyName());
1287 }
1288 final Object[] normalIds = super.getIds();
1289 for (final Object o : normalIds) {
1290 if (!ids.contains(o)) {
1291 ids.add(o);
1292 }
1293 }
1294 return ids.toArray();
1295 }
1296
1297
1298
1299
1300
1301 @JsxGetter
1302 public String getOpacity() {
1303 if (styleDeclaration_ == null) {
1304 return null;
1305 }
1306 return styleDeclaration_.getOpacity();
1307 }
1308
1309
1310
1311
1312
1313 @JsxSetter
1314 public void setOpacity(final Object opacity) {
1315 if (JavaScriptEngine.isNaN(opacity)) {
1316 return;
1317 }
1318
1319 final double doubleValue;
1320 if (opacity instanceof Number) {
1321 doubleValue = ((Number) opacity).doubleValue();
1322 }
1323 else {
1324 String valueString = JavaScriptEngine.toString(opacity);
1325
1326 if (valueString.isEmpty()) {
1327 setStyleAttribute(Definition.OPACITY.getAttributeName(), valueString);
1328 return;
1329 }
1330
1331 valueString = valueString.trim();
1332 try {
1333 doubleValue = Double.parseDouble(valueString);
1334 }
1335 catch (final NumberFormatException e) {
1336
1337 return;
1338 }
1339 }
1340
1341 if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
1342 return;
1343 }
1344 setStyleAttribute(Definition.OPACITY.getAttributeName(), Double.toString(doubleValue));
1345 }
1346
1347
1348
1349
1350
1351 @JsxGetter
1352 public String getOutline() {
1353 if (styleDeclaration_ == null) {
1354 return null;
1355 }
1356 return styleDeclaration_.getOutline();
1357 }
1358
1359
1360
1361
1362
1363 @JsxSetter
1364 public void setOutline(final String outline) {
1365 setStyleAttribute(Definition.OUTLINE.getAttributeName(), outline);
1366 }
1367
1368
1369
1370
1371
1372 @JsxGetter
1373 public String getOutlineWidth() {
1374 if (styleDeclaration_ == null) {
1375 return null;
1376 }
1377 return styleDeclaration_.getOutlineWidth();
1378 }
1379
1380
1381
1382
1383
1384 @JsxSetter
1385 public void setOutlineWidth(final Object outlineWidth) {
1386 setStyleLengthAttribute(Definition.OUTLINE_WIDTH.getAttributeName(), outlineWidth, "",
1387 false, false, THIN_MED_THICK);
1388 }
1389
1390
1391
1392
1393
1394 @JsxGetter
1395 public String getPadding() {
1396 if (styleDeclaration_ == null) {
1397 return null;
1398 }
1399 return styleDeclaration_.getPadding();
1400 }
1401
1402
1403
1404
1405
1406 @JsxSetter
1407 public void setPadding(final String padding) {
1408 setStyleAttribute(Definition.PADDING.getAttributeName(), padding);
1409 }
1410
1411
1412
1413
1414
1415 @JsxGetter
1416 public String getPaddingBottom() {
1417 if (styleDeclaration_ == null) {
1418 return null;
1419 }
1420 return styleDeclaration_.getPaddingBottom();
1421 }
1422
1423
1424
1425
1426
1427 @JsxSetter
1428 public void setPaddingBottom(final Object paddingBottom) {
1429 setStyleLengthAttribute(Definition.PADDING_BOTTOM.getAttributeName(),
1430 paddingBottom, "", false, true, null);
1431 }
1432
1433
1434
1435
1436
1437 @JsxGetter
1438 public String getPaddingLeft() {
1439 if (styleDeclaration_ == null) {
1440 return null;
1441 }
1442 return styleDeclaration_.getPaddingLeft();
1443 }
1444
1445
1446
1447
1448
1449 @JsxSetter
1450 public void setPaddingLeft(final Object paddingLeft) {
1451 setStyleLengthAttribute(Definition.PADDING_LEFT.getAttributeName(), paddingLeft, "", false, true, null);
1452 }
1453
1454
1455
1456
1457
1458 @JsxGetter
1459 public String getPaddingRight() {
1460 if (styleDeclaration_ == null) {
1461 return null;
1462 }
1463 return styleDeclaration_.getPaddingRight();
1464 }
1465
1466
1467
1468
1469
1470 @JsxSetter
1471 public void setPaddingRight(final Object paddingRight) {
1472 setStyleLengthAttribute(Definition.PADDING_RIGHT.getAttributeName(),
1473 paddingRight, "", false, true, null);
1474 }
1475
1476
1477
1478
1479
1480 @JsxGetter
1481 public String getPaddingTop() {
1482 if (styleDeclaration_ == null) {
1483 return null;
1484 }
1485 return styleDeclaration_.getPaddingTop();
1486 }
1487
1488
1489
1490
1491
1492 @JsxSetter
1493 public void setPaddingTop(final Object paddingTop) {
1494 setStyleLengthAttribute(Definition.PADDING_TOP.getAttributeName(), paddingTop, "", false, true, null);
1495 }
1496
1497
1498
1499
1500
1501
1502
1503 @JsxGetter
1504 public CSSRule getParentRule() {
1505 final AbstractCSSRuleImpl parentRule = styleDeclaration_.getParentRule();
1506 if (parentRule != null) {
1507 return CSSRule.create((CSSStyleSheet) getParentScope(), parentRule);
1508 }
1509 return null;
1510 }
1511
1512
1513
1514
1515
1516 @JsxSetter
1517 public void setParentRule(final CSSRule parentRule) {
1518
1519 }
1520
1521
1522
1523
1524
1525 @JsxGetter
1526 public String getRight() {
1527 if (styleDeclaration_ == null) {
1528 return null;
1529 }
1530 return styleDeclaration_.getRight();
1531 }
1532
1533
1534
1535
1536
1537 @JsxSetter
1538 public void setRight(final Object right) {
1539 setStyleLengthAttribute(Definition.RIGHT.getAttributeName(), right, "", true, true, null);
1540 }
1541
1542
1543
1544
1545
1546 @JsxGetter
1547 public String getRubyAlign() {
1548 if (styleDeclaration_ == null) {
1549 return null;
1550 }
1551 return styleDeclaration_.getRubyAlign();
1552 }
1553
1554
1555
1556
1557
1558 @JsxSetter
1559 public void setRubyAlign(final String rubyAlign) {
1560 setStyleAttribute(Definition.RUBY_ALIGN.getAttributeName(), rubyAlign);
1561 }
1562
1563
1564
1565
1566
1567 @JsxGetter({CHROME, EDGE})
1568 public String getSize() {
1569 if (styleDeclaration_ == null) {
1570 return null;
1571 }
1572 return styleDeclaration_.getSize();
1573 }
1574
1575
1576
1577
1578
1579 @JsxSetter({CHROME, EDGE})
1580 public void setSize(final String size) {
1581 setStyleAttribute(Definition.SIZE.getAttributeName(), size);
1582 }
1583
1584
1585
1586
1587
1588 @JsxGetter
1589 public String getTextIndent() {
1590 if (styleDeclaration_ == null) {
1591 return null;
1592 }
1593 return styleDeclaration_.getTextIndent();
1594 }
1595
1596
1597
1598
1599
1600 @JsxSetter
1601 public void setTextIndent(final Object textIndent) {
1602 setStyleLengthAttribute(Definition.TEXT_INDENT.getAttributeName(), textIndent, "", false, true, null);
1603 }
1604
1605
1606
1607
1608
1609 @JsxGetter
1610 public String getTop() {
1611 if (styleDeclaration_ == null) {
1612 return null;
1613 }
1614 return styleDeclaration_.getTop();
1615 }
1616
1617
1618
1619
1620
1621 @JsxSetter
1622 public void setTop(final Object top) {
1623 setStyleLengthAttribute(Definition.TOP.getAttributeName(), top, "", true, true, null);
1624 }
1625
1626
1627
1628
1629
1630 @JsxGetter
1631 public String getVerticalAlign() {
1632 if (styleDeclaration_ == null) {
1633 return null;
1634 }
1635 return styleDeclaration_.getVerticalAlign();
1636 }
1637
1638
1639
1640
1641
1642 @JsxSetter
1643 public void setVerticalAlign(final Object verticalAlign) {
1644 setStyleLengthAttribute(Definition.VERTICAL_ALIGN.getAttributeName(),
1645 verticalAlign, "", false, true, ALIGN_KEYWORDS);
1646 }
1647
1648
1649
1650
1651
1652 @JsxGetter
1653 public String getWidth() {
1654 if (styleDeclaration_ == null) {
1655 return null;
1656 }
1657 return styleDeclaration_.getWidth();
1658 }
1659
1660
1661
1662
1663
1664 @JsxSetter
1665 public void setWidth(final Object width) {
1666 setStyleLengthAttribute(Definition.WIDTH.getAttributeName(), width, "", true, true, null);
1667 }
1668
1669
1670
1671
1672
1673 @JsxGetter({CHROME, EDGE})
1674 public String getWidows() {
1675 if (styleDeclaration_ == null) {
1676 return null;
1677 }
1678 return styleDeclaration_.getWidows();
1679 }
1680
1681
1682
1683
1684
1685 @JsxSetter({CHROME, EDGE})
1686 public void setWidows(final String widows) {
1687 if (getBrowserVersion().hasFeature(CSS_BACKGROUND_INITIAL)) {
1688 try {
1689 if (Integer.parseInt(widows) <= 0) {
1690 return;
1691 }
1692 }
1693 catch (final NumberFormatException e) {
1694 return;
1695 }
1696 }
1697 setStyleAttribute(Definition.WIDOWS.getAttributeName(), widows);
1698 }
1699
1700
1701
1702
1703
1704 @JsxGetter({CHROME, EDGE})
1705 public String getOrphans() {
1706 if (styleDeclaration_ == null) {
1707 return null;
1708 }
1709 return styleDeclaration_.getOrphans();
1710 }
1711
1712
1713
1714
1715
1716 @JsxSetter({CHROME, EDGE})
1717 public void setOrphans(final String orphans) {
1718 if (getBrowserVersion().hasFeature(CSS_BACKGROUND_INITIAL)) {
1719 try {
1720 if (Integer.parseInt(orphans) <= 0) {
1721 return;
1722 }
1723 }
1724 catch (final NumberFormatException e) {
1725 return;
1726 }
1727 }
1728 setStyleAttribute(Definition.ORPHANS.getAttributeName(), orphans);
1729 }
1730
1731
1732
1733
1734
1735 @JsxGetter
1736 public String getPosition() {
1737 if (styleDeclaration_ == null) {
1738 return null;
1739 }
1740 return styleDeclaration_.getPosition();
1741 }
1742
1743
1744
1745
1746
1747 @JsxSetter
1748 public void setPosition(final String position) {
1749 if (position.isEmpty() || STATIC.equalsIgnoreCase(position) || ABSOLUTE.equalsIgnoreCase(position)
1750 || FIXED.equalsIgnoreCase(position) || RELATIVE.equalsIgnoreCase(position)
1751 || INITIAL.equalsIgnoreCase(position) || INHERIT.equalsIgnoreCase(position)) {
1752 setStyleAttribute(Definition.POSITION.getAttributeName(), position.toLowerCase(Locale.ROOT));
1753 }
1754 }
1755
1756
1757
1758
1759
1760 @JsxGetter
1761 public String getWordSpacing() {
1762 if (styleDeclaration_ == null) {
1763 return null;
1764 }
1765 return styleDeclaration_.getWordSpacing();
1766 }
1767
1768
1769
1770
1771
1772 @JsxSetter
1773 public void setWordSpacing(final Object wordSpacing) {
1774 setStyleLengthAttribute(Definition.WORD_SPACING.getAttributeName(), wordSpacing, "",
1775 false, getBrowserVersion().hasFeature(JS_STYLE_WORD_SPACING_ACCEPTS_PERCENT), null);
1776 }
1777
1778
1779
1780
1781
1782 @JsxGetter
1783 public String getZIndex() {
1784 if (styleDeclaration_ == null) {
1785 return null;
1786 }
1787 return styleDeclaration_.getZIndex();
1788 }
1789
1790
1791
1792
1793
1794 @JsxSetter
1795 public void setZIndex(final Object zIndex) {
1796
1797 if (zIndex == null || StringUtils.isEmptyOrNull(zIndex.toString())) {
1798 setStyleAttribute(Definition.Z_INDEX_.getAttributeName(), "");
1799 return;
1800 }
1801
1802 if (JavaScriptEngine.isUndefined(zIndex)) {
1803 return;
1804 }
1805
1806
1807 if (zIndex instanceof Number) {
1808 final Number number = (Number) zIndex;
1809 if (number.doubleValue() % 1 == 0) {
1810 setStyleAttribute(Definition.Z_INDEX_.getAttributeName(), Integer.toString(number.intValue()));
1811 }
1812 return;
1813 }
1814 try {
1815 final int i = Integer.parseInt(zIndex.toString());
1816 setStyleAttribute(Definition.Z_INDEX_.getAttributeName(), Integer.toString(i));
1817 }
1818 catch (final NumberFormatException ignored) {
1819
1820 }
1821 }
1822
1823
1824
1825
1826
1827
1828 @JsxFunction
1829 public String getPropertyValue(final String name) {
1830 if (name != null && name.contains("-")) {
1831 final Object value = getProperty(this, StringUtils.cssCamelize(name));
1832 if (value instanceof String) {
1833 return (String) value;
1834 }
1835 }
1836
1837 return styleDeclaration_.getStyleAttribute(name);
1838 }
1839
1840
1841
1842
1843
1844
1845 @JsxFunction
1846 public String getPropertyPriority(final String name) {
1847 return getStylePriority(name);
1848 }
1849
1850
1851
1852
1853
1854
1855
1856
1857 @JsxFunction
1858 public void setProperty(final String name, final Object value, final String important) {
1859 String imp = "";
1860 if (!StringUtils.isEmptyOrNull(important) && !"null".equals(important)) {
1861 if (!StyleElement.PRIORITY_IMPORTANT.equalsIgnoreCase(important)) {
1862 return;
1863 }
1864 imp = StyleElement.PRIORITY_IMPORTANT;
1865 }
1866
1867 if (LENGTH_PROPERTIES_FFFF.contains(name)) {
1868 setStyleLengthAttribute(name, value, imp, false, false, null);
1869 }
1870 else if (LENGTH_PROPERTIES_TTFF.contains(name)) {
1871 setStyleLengthAttribute(name, value, imp, true, true, null);
1872 }
1873 else if (LENGTH_PROPERTIES_FTFF.contains(name)) {
1874 setStyleLengthAttribute(name, value, imp, false, true, null);
1875 }
1876 else if (Definition.OUTLINE_WIDTH.getAttributeName().equals(name)) {
1877 setStyleLengthAttribute(Definition.OUTLINE_WIDTH.getAttributeName(),
1878 value, imp, false, false, THIN_MED_THICK);
1879 }
1880 else if (Definition.LETTER_SPACING.getAttributeName().equals(name)) {
1881 setStyleLengthAttribute(Definition.LETTER_SPACING.getAttributeName(), value, imp,
1882 false, getBrowserVersion().hasFeature(JS_STYLE_LETTER_SPACING_ACCEPTS_PERCENT), null);
1883 }
1884 else if (Definition.WORD_SPACING.getAttributeName().equals(name)) {
1885 setStyleLengthAttribute(Definition.WORD_SPACING.getAttributeName(), value, imp,
1886 false, getBrowserVersion().hasFeature(JS_STYLE_WORD_SPACING_ACCEPTS_PERCENT), null);
1887 }
1888 else if (Definition.VERTICAL_ALIGN.getAttributeName().equals(name)) {
1889 setStyleLengthAttribute(Definition.VERTICAL_ALIGN.getAttributeName(), value, imp, false, true, null);
1890 }
1891 else {
1892 setStyleAttribute(name, JavaScriptEngine.toString(value), imp);
1893 }
1894 }
1895
1896
1897
1898
1899
1900
1901 @JsxFunction
1902 public String removeProperty(final Object name) {
1903 return removeStyleAttribute(JavaScriptEngine.toString(name));
1904 }
1905
1906
1907
1908
1909
1910
1911 static boolean isLength(String token) {
1912 if (token.endsWith("em") || token.endsWith("ex") || token.endsWith("px") || token.endsWith("in")
1913 || token.endsWith("cm") || token.endsWith("mm") || token.endsWith("pt") || token.endsWith("pc")
1914 || token.endsWith("%")) {
1915
1916 if (token.endsWith("%")) {
1917 token = token.substring(0, token.length() - 1);
1918 }
1919 else {
1920 token = token.substring(0, token.length() - 2);
1921 }
1922 try {
1923 Double.parseDouble(token);
1924 return true;
1925 }
1926 catch (final NumberFormatException ignored) {
1927
1928 }
1929 }
1930 return false;
1931 }
1932
1933
1934
1935
1936 @Override
1937 public String toString() {
1938 if (styleDeclaration_ == null) {
1939 return "CSSStyleDeclaration for 'null'";
1940 }
1941
1942 return "CSSStyleDeclaration for '" + styleDeclaration_ + "'";
1943 }
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954 private void setStyleLengthAttribute(final String name, final Object value, final String important,
1955 final boolean auto, final boolean percent, final String[] validValues) {
1956 if (JavaScriptEngine.isNaN(value)) {
1957 return;
1958 }
1959
1960 if (value instanceof Number) {
1961 return;
1962 }
1963
1964 String valueString = JavaScriptEngine.toString(value);
1965 if (null == value) {
1966 valueString = "";
1967 }
1968
1969 if (StringUtils.isEmptyOrNull(valueString)) {
1970 setStyleAttribute(name, valueString, important);
1971 return;
1972 }
1973
1974 if ((auto && AUTO.equals(valueString))
1975 || INITIAL.equals(valueString)
1976 || INHERIT.equals(valueString)) {
1977 setStyleAttribute(name, valueString, important);
1978 return;
1979 }
1980
1981 if (validValues != null && ArrayUtils.contains(validValues, valueString)) {
1982 setStyleAttribute(name, valueString, important);
1983 return;
1984 }
1985
1986 String unit = "px";
1987 if (percent && valueString.endsWith("%")) {
1988 unit = valueString.substring(valueString.length() - 1);
1989 valueString = valueString.substring(0, valueString.length() - 1);
1990 }
1991 else if (valueString.endsWith("px")
1992 || valueString.endsWith("em")
1993 || valueString.endsWith("ex")
1994 || valueString.endsWith("pt")
1995 || valueString.endsWith("cm")
1996 || valueString.endsWith("mm")
1997 || valueString.endsWith("in")
1998 || valueString.endsWith("pc")
1999 || valueString.endsWith("ch")
2000 || valueString.endsWith("vh")
2001 || valueString.endsWith("vw")) {
2002 unit = valueString.substring(valueString.length() - 2);
2003 valueString = valueString.substring(0, valueString.length() - 2);
2004 }
2005 else if (valueString.endsWith("rem")
2006 || valueString.endsWith("vmin")
2007 || valueString.endsWith("vmax")) {
2008 unit = valueString.substring(valueString.length() - 3);
2009 valueString = valueString.substring(0, valueString.length() - 3);
2010 }
2011 else {
2012 return;
2013 }
2014
2015 if (!valueString.equals(valueString.trim())) {
2016
2017 return;
2018 }
2019 final double doubleValue = JavaScriptEngine.toNumber(valueString);
2020
2021 try {
2022 if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
2023 return;
2024 }
2025
2026 final String valueStr;
2027 if (doubleValue % 1 == 0) {
2028 valueStr = (int) doubleValue + unit;
2029 }
2030 else {
2031 valueStr = doubleValue + unit;
2032 }
2033
2034 setStyleAttribute(name, valueStr, important);
2035 }
2036 catch (final Exception ignored) {
2037
2038 }
2039 }
2040 }