1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.css;
16
17 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTHEIGHT_INPUT_17;
18 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTHEIGHT_INPUT_18;
19 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTHEIGHT_RADIO_CHECKBOX_14;
20 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTHEIGHT_RB_17;
21 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTHEIGHT_RT_9;
22 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTHEIGHT_RUBY_17;
23 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTWIDTH_INPUT_TEXT_157;
24 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTWIDTH_INPUT_TEXT_173;
25 import static org.htmlunit.BrowserVersionFeatures.JS_CLIENTWIDTH_RADIO_CHECKBOX_14;
26 import static org.htmlunit.css.CssStyleSheet.ABSOLUTE;
27 import static org.htmlunit.css.CssStyleSheet.AUTO;
28 import static org.htmlunit.css.CssStyleSheet.BLOCK;
29 import static org.htmlunit.css.CssStyleSheet.FIXED;
30 import static org.htmlunit.css.CssStyleSheet.INHERIT;
31 import static org.htmlunit.css.CssStyleSheet.INLINE;
32 import static org.htmlunit.css.CssStyleSheet.NONE;
33 import static org.htmlunit.css.CssStyleSheet.RELATIVE;
34 import static org.htmlunit.css.CssStyleSheet.SCROLL;
35 import static org.htmlunit.css.CssStyleSheet.STATIC;
36
37 import java.util.EnumSet;
38 import java.util.HashSet;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.SortedMap;
42 import java.util.TreeMap;
43
44 import org.htmlunit.BrowserVersion;
45 import org.htmlunit.BrowserVersionFeatures;
46 import org.htmlunit.Page;
47 import org.htmlunit.SgmlPage;
48 import org.htmlunit.WebWindow;
49 import org.htmlunit.css.CssPixelValueConverter.CssValue;
50 import org.htmlunit.css.StyleAttributes.Definition;
51 import org.htmlunit.cssparser.dom.AbstractCSSRuleImpl;
52 import org.htmlunit.cssparser.dom.CSSStyleDeclarationImpl;
53 import org.htmlunit.cssparser.dom.Property;
54 import org.htmlunit.cssparser.parser.selector.Selector;
55 import org.htmlunit.cssparser.parser.selector.SelectorSpecificity;
56 import org.htmlunit.html.BaseFrameElement;
57 import org.htmlunit.html.DomElement;
58 import org.htmlunit.html.DomNode;
59 import org.htmlunit.html.DomText;
60 import org.htmlunit.html.HtmlAbbreviated;
61 import org.htmlunit.html.HtmlAcronym;
62 import org.htmlunit.html.HtmlAddress;
63 import org.htmlunit.html.HtmlArticle;
64 import org.htmlunit.html.HtmlAside;
65 import org.htmlunit.html.HtmlBaseFont;
66 import org.htmlunit.html.HtmlBidirectionalIsolation;
67 import org.htmlunit.html.HtmlBidirectionalOverride;
68 import org.htmlunit.html.HtmlBig;
69 import org.htmlunit.html.HtmlBody;
70 import org.htmlunit.html.HtmlBold;
71 import org.htmlunit.html.HtmlButton;
72 import org.htmlunit.html.HtmlButtonInput;
73 import org.htmlunit.html.HtmlCanvas;
74 import org.htmlunit.html.HtmlCenter;
75 import org.htmlunit.html.HtmlCheckBoxInput;
76 import org.htmlunit.html.HtmlCitation;
77 import org.htmlunit.html.HtmlCode;
78 import org.htmlunit.html.HtmlData;
79 import org.htmlunit.html.HtmlDefinition;
80 import org.htmlunit.html.HtmlDefinitionDescription;
81 import org.htmlunit.html.HtmlDefinitionTerm;
82 import org.htmlunit.html.HtmlDivision;
83 import org.htmlunit.html.HtmlElement;
84 import org.htmlunit.html.HtmlElement.DisplayStyle;
85 import org.htmlunit.html.HtmlEmphasis;
86 import org.htmlunit.html.HtmlFigure;
87 import org.htmlunit.html.HtmlFigureCaption;
88 import org.htmlunit.html.HtmlFileInput;
89 import org.htmlunit.html.HtmlFooter;
90 import org.htmlunit.html.HtmlFrame;
91 import org.htmlunit.html.HtmlHeader;
92 import org.htmlunit.html.HtmlHeading1;
93 import org.htmlunit.html.HtmlHeading2;
94 import org.htmlunit.html.HtmlHeading3;
95 import org.htmlunit.html.HtmlHeading4;
96 import org.htmlunit.html.HtmlHeading5;
97 import org.htmlunit.html.HtmlHeading6;
98 import org.htmlunit.html.HtmlHiddenInput;
99 import org.htmlunit.html.HtmlImage;
100 import org.htmlunit.html.HtmlInlineFrame;
101 import org.htmlunit.html.HtmlInput;
102 import org.htmlunit.html.HtmlItalic;
103 import org.htmlunit.html.HtmlKeyboard;
104 import org.htmlunit.html.HtmlLayer;
105 import org.htmlunit.html.HtmlLegend;
106 import org.htmlunit.html.HtmlMain;
107 import org.htmlunit.html.HtmlMark;
108 import org.htmlunit.html.HtmlNav;
109 import org.htmlunit.html.HtmlNoBreak;
110 import org.htmlunit.html.HtmlNoEmbed;
111 import org.htmlunit.html.HtmlNoFrames;
112 import org.htmlunit.html.HtmlNoLayer;
113 import org.htmlunit.html.HtmlNoScript;
114 import org.htmlunit.html.HtmlOutput;
115 import org.htmlunit.html.HtmlPage;
116 import org.htmlunit.html.HtmlPasswordInput;
117 import org.htmlunit.html.HtmlPlainText;
118 import org.htmlunit.html.HtmlRadioButtonInput;
119 import org.htmlunit.html.HtmlRb;
120 import org.htmlunit.html.HtmlResetInput;
121 import org.htmlunit.html.HtmlRp;
122 import org.htmlunit.html.HtmlRt;
123 import org.htmlunit.html.HtmlRtc;
124 import org.htmlunit.html.HtmlRuby;
125 import org.htmlunit.html.HtmlS;
126 import org.htmlunit.html.HtmlSample;
127 import org.htmlunit.html.HtmlSection;
128 import org.htmlunit.html.HtmlSelect;
129 import org.htmlunit.html.HtmlSlot;
130 import org.htmlunit.html.HtmlSmall;
131 import org.htmlunit.html.HtmlSpan;
132 import org.htmlunit.html.HtmlStrike;
133 import org.htmlunit.html.HtmlStrong;
134 import org.htmlunit.html.HtmlSubmitInput;
135 import org.htmlunit.html.HtmlSubscript;
136 import org.htmlunit.html.HtmlSummary;
137 import org.htmlunit.html.HtmlSuperscript;
138 import org.htmlunit.html.HtmlTableCell;
139 import org.htmlunit.html.HtmlTableRow;
140 import org.htmlunit.html.HtmlTeletype;
141 import org.htmlunit.html.HtmlTextArea;
142 import org.htmlunit.html.HtmlTextInput;
143 import org.htmlunit.html.HtmlTime;
144 import org.htmlunit.html.HtmlUnderlined;
145 import org.htmlunit.html.HtmlUnknownElement;
146 import org.htmlunit.html.HtmlVariable;
147 import org.htmlunit.html.HtmlWordBreak;
148 import org.htmlunit.platform.Platform;
149 import org.htmlunit.util.StringUtils;
150
151
152
153
154
155
156
157
158
159
160
161
162
163 @SuppressWarnings("PMD.AvoidDuplicateLiterals")
164 public class ComputedCssStyleDeclaration extends AbstractCssStyleDeclaration {
165
166
167 private static final Set<Definition> INHERITABLE_DEFINITIONS = EnumSet.of(
168 Definition.BORDER_COLLAPSE,
169 Definition.BORDER_SPACING,
170 Definition.CAPTION_SIDE,
171 Definition.COLOR,
172 Definition.CURSOR,
173 Definition.DIRECTION,
174 Definition.EMPTY_CELLS,
175 Definition.FONT_FAMILY,
176 Definition.FONT_SIZE,
177 Definition.FONT_STYLE,
178 Definition.FONT_VARIANT,
179 Definition.FONT_WEIGHT,
180 Definition.FONT,
181 Definition.LETTER_SPACING,
182 Definition.LINE_HEIGHT,
183 Definition.LIST_STYLE_IMAGE,
184 Definition.LIST_STYLE_POSITION,
185 Definition.LIST_STYLE_TYPE,
186 Definition.LIST_STYLE,
187 Definition.ORPHANS,
188 Definition.QUOTES,
189 Definition.SPEAK,
190 Definition.TEXT_ALIGN,
191 Definition.TEXT_INDENT,
192 Definition.TEXT_TRANSFORM,
193 Definition.VISIBILITY,
194 Definition.WHITE_SPACE,
195 Definition.WIDOWS,
196 Definition.WORD_SPACING);
197
198
199 public static final String EMPTY_FINAL = new String("");
200
201
202 private Integer width_;
203
204
205
206
207
208 private Integer height_;
209
210
211
212
213
214 private Integer emptyHeight_;
215
216
217 private Integer paddingHorizontal_;
218
219
220 private Integer paddingVertical_;
221
222
223 private Integer borderHorizontal_;
224
225
226 private Integer borderVertical_;
227
228
229 private Integer top_;
230
231
232
233
234
235 private final SortedMap<String, StyleElement> localModifications_ = new TreeMap<>();
236
237
238 private final ElementCssStyleDeclaration elementStyleDeclaration_;
239
240
241
242
243
244 public ComputedCssStyleDeclaration(final ElementCssStyleDeclaration styleDeclaration) {
245 super();
246 elementStyleDeclaration_ = styleDeclaration;
247 elementStyleDeclaration_.getDomElement().setDefaults(this);
248 }
249
250
251
252
253 @Override
254 public String getStylePriority(final String name) {
255 return elementStyleDeclaration_.getStylePriority(name);
256 }
257
258
259
260
261 @Override
262 public String getCssText() {
263 return elementStyleDeclaration_.getCssText();
264 }
265
266
267
268
269 @Override
270 public String getStyleAttribute(final String name) {
271 final StyleElement element = getStyleElement(name);
272 if (element != null && element.getValue() != null) {
273 final String value = element.getValue();
274 if (!"content".equals(name)
275 && !value.contains("url")) {
276 return StringUtils.toRootLowerCase(value);
277 }
278 return value;
279 }
280 return "";
281 }
282
283
284
285
286 @Override
287 public String getStyleAttribute(final Definition definition, final boolean getDefaultValueIfEmpty) {
288 final BrowserVersion browserVersion = getDomElement().getPage().getWebClient().getBrowserVersion();
289 final boolean isDefInheritable = INHERITABLE_DEFINITIONS.contains(definition);
290
291
292 final ComputedCssStyleDeclaration[] queue = {this};
293 String value = null;
294 while (queue[0] != null) {
295 value = getStyleAttributeWorker(definition, getDefaultValueIfEmpty,
296 browserVersion, true, isDefInheritable, queue);
297 }
298
299 return value;
300 }
301
302 private static String getStyleAttributeWorker(final Definition definition,
303 final boolean getDefaultValueIfEmpty, final BrowserVersion browserVersion,
304 final boolean feature, final boolean isDefInheritable,
305 final ComputedCssStyleDeclaration[] queue) {
306 final ComputedCssStyleDeclaration decl = queue[0];
307 queue[0] = null;
308
309 final DomElement domElem = decl.getDomElement();
310 if (!domElem.isAttachedToPage() && feature) {
311 return EMPTY_FINAL;
312 }
313
314 String value = decl.getStyleAttribute(definition.getAttributeName());
315 if (value.isEmpty()) {
316 final DomNode parent = domElem.getParentNode();
317 if (isDefInheritable && parent instanceof DomElement element) {
318 final WebWindow window = domElem.getPage().getEnclosingWindow();
319
320 queue[0] = window.getComputedStyle(element, null);
321 }
322 else if (getDefaultValueIfEmpty) {
323 value = definition.getDefaultComputedValue(browserVersion);
324 }
325 }
326
327 return value;
328 }
329
330
331
332
333
334
335 private String getStyleAttribute(final Definition definition, final String toReturnIfEmptyOrDefault,
336 final String defaultValue) {
337 final DomElement domElement = getDomElement();
338
339 if (!domElement.isAttachedToPage()) {
340 return EMPTY_FINAL;
341 }
342
343 final boolean isDefInheritable = INHERITABLE_DEFINITIONS.contains(definition);
344
345
346 final BrowserVersion browserVersion = domElement.getPage().getWebClient().getBrowserVersion();
347 final ComputedCssStyleDeclaration[] queue = {this};
348 String value = null;
349 while (queue[0] != null) {
350 value = getStyleAttributeWorker(definition, false,
351 browserVersion, true, isDefInheritable, queue);
352 }
353
354 if (value == null || value.isEmpty() || value.equals(defaultValue)) {
355 return toReturnIfEmptyOrDefault;
356 }
357
358 return value;
359 }
360
361
362
363
364 @Override
365 public void setCssText(final String value) {
366
367 }
368
369
370
371
372 @Override
373 public void setStyleAttribute(final String name, final String newValue, final String important) {
374
375 }
376
377
378
379
380 @Override
381 public String removeStyleAttribute(final String name) {
382
383 return null;
384 }
385
386
387
388
389 @Override
390 public int getLength() {
391 return elementStyleDeclaration_.getLength();
392 }
393
394
395
396
397 @Override
398 public String getWidth() {
399 if (NONE.equals(getDisplay())) {
400 return AUTO;
401 }
402
403 final DomElement domElem = getDomElement();
404 if (!domElem.isAttachedToPage()) {
405 return "";
406 }
407
408 final int windowWidth = domElem.getPage().getEnclosingWindow().getInnerWidth();
409 return CssPixelValueConverter.pixelString(domElem, new CssPixelValueConverter.CssValue(0, windowWidth) {
410 @Override
411 public String get(final ComputedCssStyleDeclaration style) {
412 final String value = style.getStyleAttribute(Definition.WIDTH, true);
413 if (StringUtils.isEmptyOrNull(value)) {
414 final String position = getStyleAttribute(Definition.POSITION, true);
415 if (ABSOLUTE.equals(position) || FIXED.equals(position)) {
416 final String content = domElem.getVisibleText();
417
418
419 if (null != content && content.length() < 13) {
420 return (content.length() * 7) + "px";
421 }
422 }
423
424 int windowDefaultValue = getWindowDefaultValue();
425 if (domElem instanceof HtmlBody) {
426 windowDefaultValue -= 16;
427 }
428 return windowDefaultValue + "px";
429 }
430 else if (AUTO.equals(value)) {
431 int windowDefaultValue = getWindowDefaultValue();
432 if (domElem instanceof HtmlBody) {
433 windowDefaultValue -= 16;
434 }
435 return windowDefaultValue + "px";
436 }
437
438 return value;
439 }
440 });
441 }
442
443
444
445
446 @Override
447 public String item(final int index) {
448 return elementStyleDeclaration_.item(index);
449 }
450
451
452
453
454 @Override
455 public AbstractCSSRuleImpl getParentRule() {
456 return elementStyleDeclaration_.getParentRule();
457 }
458
459
460
461
462 @Override
463 public StyleElement getStyleElement(final String name) {
464 final StyleElement existent = elementStyleDeclaration_.getStyleElement(name);
465
466 final StyleElement localStyleMod = localModifications_.get(name);
467 if (localStyleMod == null) {
468 return existent;
469 }
470
471 if (existent == null) {
472
473
474
475 return localStyleMod;
476 }
477
478
479 if (StyleElement.PRIORITY_IMPORTANT.equals(localStyleMod.getPriority())) {
480 if (existent.isImportant()) {
481 if (existent.getSpecificity().compareTo(localStyleMod.getSpecificity()) < 0) {
482 return localStyleMod;
483 }
484 }
485 else {
486 return localStyleMod;
487 }
488 }
489 return existent;
490 }
491
492
493
494
495 @Override
496 public StyleElement getStyleElementCaseInSensitive(final String name) {
497 return elementStyleDeclaration_.getStyleElementCaseInSensitive(name);
498 }
499
500
501
502
503 @Override
504 public Map<String, StyleElement> getStyleMap() {
505 return elementStyleDeclaration_.getStyleMap();
506 }
507
508
509
510
511
512 public DomElement getDomElement() {
513 return elementStyleDeclaration_.getDomElement();
514 }
515
516
517
518
519 @Override
520 public String getBackgroundAttachment() {
521 return defaultIfEmpty(super.getBackgroundAttachment(), Definition.BACKGROUND_ATTACHMENT);
522 }
523
524
525
526
527 @Override
528 public String getBackgroundColor() {
529 if (!getDomElement().isAttachedToPage()) {
530 return EMPTY_FINAL;
531 }
532
533 final String value = super.getBackgroundColor();
534 if (StringUtils.isEmptyOrNull(value)) {
535 return Definition.BACKGROUND_COLOR.getDefaultComputedValue(getBrowserVersion());
536 }
537 return CssColors.toRGBColor(value);
538 }
539
540
541
542
543 @Override
544 public String getBackgroundImage() {
545 return defaultIfEmpty(super.getBackgroundImage(), Definition.BACKGROUND_IMAGE);
546 }
547
548
549
550
551
552 @Override
553 public String getBackgroundPosition() {
554 return defaultIfEmpty(super.getBackgroundPosition(), Definition.BACKGROUND_POSITION);
555 }
556
557
558
559
560 @Override
561 public String getBackgroundRepeat() {
562 return defaultIfEmpty(super.getBackgroundRepeat(), Definition.BACKGROUND_REPEAT);
563 }
564
565
566
567
568 @Override
569 public String getBlockSize() {
570 if (NONE.equals(getDisplay())) {
571 return defaultIfEmpty(super.getBlockSize(), Definition.BLOCK_SIZE);
572 }
573
574 final DomElement domElem = getDomElement();
575 if (!domElem.isAttachedToPage()) {
576 return defaultIfEmpty(super.getBlockSize(), Definition.BLOCK_SIZE);
577 }
578
579 return CssPixelValueConverter.pixelString(domElem, new CssPixelValueConverter.CssValue(0, 0) {
580 @Override
581 public String get(final ComputedCssStyleDeclaration style) {
582 final String value = style.getStyleAttribute(Definition.HEIGHT, true);
583 if (StringUtils.isEmptyOrNull(value)) {
584 final String content = domElem.getVisibleText();
585
586
587 if (null == content) {
588 return getDefaultValue() + "px";
589 }
590 return getEmptyHeight(domElem) + "px";
591 }
592 return value;
593 }
594 });
595 }
596
597
598
599
600 @Override
601 public String getBorderBottomColor() {
602 return defaultIfEmpty(super.getBorderBottomColor(), Definition.BORDER_BOTTOM_COLOR);
603 }
604
605
606
607
608 @Override
609 public String getBorderBottomStyle() {
610 return defaultIfEmpty(super.getBorderBottomStyle(), Definition.BORDER_BOTTOM_STYLE);
611 }
612
613
614
615
616 @Override
617 public String getBorderBottomWidth() {
618 return pixelString(defaultIfEmpty(super.getBorderBottomWidth(), Definition.BORDER_BOTTOM_WIDTH));
619 }
620
621
622
623
624 @Override
625 public String getBorderLeftColor() {
626 return defaultIfEmpty(super.getBorderLeftColor(), Definition.BORDER_LEFT_COLOR);
627 }
628
629
630
631
632 @Override
633 public String getBorderLeftStyle() {
634 return defaultIfEmpty(super.getBorderLeftStyle(), Definition.BORDER_LEFT_STYLE);
635 }
636
637
638
639
640 @Override
641 public String getBorderLeftWidth() {
642 return pixelString(defaultIfEmpty(super.getBorderLeftWidth(), "0px", null));
643 }
644
645
646
647
648 @Override
649 public String getBorderRightColor() {
650 return defaultIfEmpty(super.getBorderRightColor(), "rgb(0, 0, 0)", null);
651 }
652
653
654
655
656 @Override
657 public String getBorderRightStyle() {
658 return defaultIfEmpty(super.getBorderRightStyle(), NONE, null);
659 }
660
661
662
663
664 @Override
665 public String getBorderRightWidth() {
666 return pixelString(defaultIfEmpty(super.getBorderRightWidth(), "0px", null));
667 }
668
669
670
671
672 @Override
673 public String getBorderTopColor() {
674 return defaultIfEmpty(super.getBorderTopColor(), "rgb(0, 0, 0)", null);
675 }
676
677
678
679
680 @Override
681 public String getBorderTopStyle() {
682 return defaultIfEmpty(super.getBorderTopStyle(), NONE, null);
683 }
684
685
686
687
688 @Override
689 public String getBorderTopWidth() {
690 return pixelString(defaultIfEmpty(super.getBorderTopWidth(), "0px", null));
691 }
692
693
694
695
696 @Override
697 public String getBottom() {
698 return getStyleAttribute(Definition.BOTTOM, AUTO, null);
699 }
700
701
702
703
704 @Override
705 public String getColor() {
706 final String value = getStyleAttribute(Definition.COLOR, "rgb(0, 0, 0)", null);
707 return CssColors.toRGBColor(value);
708 }
709
710
711
712
713 @Override
714 public String getCssFloat() {
715 return defaultIfEmpty(super.getCssFloat(), Definition.CSS_FLOAT);
716 }
717
718
719
720
721 @Override
722 public String getDisplay() {
723 final DomElement domElem = getDomElement();
724 if (!domElem.isAttachedToPage()) {
725 return "";
726 }
727
728 if (domElem instanceof HtmlElement element) {
729 if (element.isHidden()) {
730 return DisplayStyle.NONE.value();
731 }
732 }
733
734
735
736 final String value = getStyleAttribute(Definition.DISPLAY.getAttributeName());
737 if (StringUtils.isEmptyOrNull(value)) {
738 if (domElem instanceof HtmlElement element) {
739 return element.getDefaultStyleDisplay().value();
740 }
741 return "";
742 }
743 return value;
744 }
745
746
747
748
749 @Override
750 public String getFont() {
751 final DomElement domElem = getDomElement();
752 if (domElem.isAttachedToPage()) {
753 return getStyleAttribute(Definition.FONT, true);
754 }
755 return "";
756 }
757
758
759
760
761 @Override
762 public String getFontFamily() {
763 return getStyleAttribute(Definition.FONT_FAMILY, true);
764 }
765
766
767
768
769 @Override
770 public String getFontSize() {
771 return getStyleAttribute(Definition.FONT_SIZE, true);
772 }
773
774
775
776
777 @Override
778 public String getLineHeight() {
779 return defaultIfEmpty(super.getLineHeight(), Definition.LINE_HEIGHT);
780 }
781
782
783
784
785 @Override
786 public String getHeight() {
787 if (NONE.equals(getDisplay())) {
788 return AUTO;
789 }
790
791 final DomElement elem = getDomElement();
792 if (!elem.isAttachedToPage()) {
793 return "";
794 }
795
796 final ComputedCssStyleDeclaration style = elem.getPage().getEnclosingWindow().getComputedStyle(elem, null);
797 final String styleValue = style.getStyleAttribute(Definition.HEIGHT, true);
798
799 if (styleValue == null || styleValue.isEmpty() || AUTO.equals(styleValue) || styleValue.endsWith("%")) {
800 final String calculatedHeight = style.getCalculatedHeight(false, false) + "px";
801 return calculatedHeight;
802 }
803
804 if (styleValue.endsWith("px")) {
805 return styleValue;
806 }
807
808 return CssPixelValueConverter.pixelValue(styleValue) + "px";
809 }
810
811
812
813
814 @Override
815 public String getLeft() {
816 if (NONE.equals(getDisplay())) {
817 return AUTO;
818 }
819
820 final DomElement elem = getDomElement();
821 if (!elem.isAttachedToPage()) {
822 return "";
823 }
824
825 final String superLeft = super.getLeft();
826 if (!superLeft.endsWith("%")) {
827 return defaultIfEmpty(superLeft, AUTO, null);
828 }
829
830 return CssPixelValueConverter.pixelString(elem, new CssPixelValueConverter.CssValue(0, 0) {
831 @Override
832 public String get(final ComputedCssStyleDeclaration style) {
833 if (style.getDomElement() == elem) {
834 return style.getStyleAttribute(Definition.LEFT, true);
835 }
836 return style.getStyleAttribute(Definition.WIDTH, true);
837 }
838 });
839 }
840
841
842
843
844 @Override
845 public String getLetterSpacing() {
846 return defaultIfEmpty(super.getLetterSpacing(), "normal", null);
847 }
848
849
850
851
852 @Override
853 public String getMargin() {
854 return defaultIfEmpty(super.getMargin(), Definition.MARGIN, true);
855 }
856
857
858
859
860 @Override
861 public String getMarginBottom() {
862 return pixelString(defaultIfEmpty(super.getMarginBottom(), "0px", null));
863 }
864
865
866
867
868 @Override
869 public String getMarginLeft() {
870 return getMarginX(super.getMarginLeft(), Definition.MARGIN_LEFT);
871 }
872
873
874
875
876 @Override
877 public String getMarginRight() {
878 return getMarginX(super.getMarginRight(), Definition.MARGIN_RIGHT);
879 }
880
881 private String getMarginX(final String superMarginX, final Definition definition) {
882 if (!superMarginX.endsWith("%")) {
883 return pixelString(defaultIfEmpty(superMarginX, "0px", null));
884 }
885 final DomElement element = getDomElement();
886 if (!element.isAttachedToPage()) {
887 return "";
888 }
889
890 final int windowWidth = element.getPage().getEnclosingWindow().getInnerWidth();
891 return CssPixelValueConverter
892 .pixelString(element, new CssPixelValueConverter.CssValue(0, windowWidth) {
893 @Override
894 public String get(final ComputedCssStyleDeclaration style) {
895 if (style.getDomElement() == element) {
896 return style.getStyleAttribute(definition, true);
897 }
898 return style.getStyleAttribute(Definition.WIDTH, true);
899 }
900 });
901 }
902
903
904
905
906 @Override
907 public String getMarginTop() {
908 return pixelString(defaultIfEmpty(super.getMarginTop(), "0px", null));
909 }
910
911
912
913
914 @Override
915 public String getMaxHeight() {
916 return defaultIfEmpty(super.getMaxHeight(), NONE, null);
917 }
918
919
920
921
922 @Override
923 public String getMaxWidth() {
924 return defaultIfEmpty(super.getMaxWidth(), NONE, null);
925 }
926
927
928
929
930 @Override
931 public String getMinHeight() {
932 return defaultIfEmpty(super.getMinHeight(), "0px", null);
933 }
934
935
936
937
938 @Override
939 public String getMinWidth() {
940 return defaultIfEmpty(super.getMinWidth(), "0px", null);
941 }
942
943
944
945
946 @Override
947 public String getOpacity() {
948 return defaultIfEmpty(super.getOpacity(), "1", null);
949 }
950
951
952
953
954 @Override
955 public String getOrphans() {
956 return defaultIfEmpty(super.getOrphans(), Definition.ORPHANS);
957 }
958
959
960
961
962 @Override
963 public String getOutlineWidth() {
964 return defaultIfEmpty(super.getOutlineWidth(), "0px", null);
965 }
966
967
968
969
970 @Override
971 public String getPadding() {
972 return defaultIfEmpty(super.getPadding(), Definition.PADDING, true);
973 }
974
975
976
977
978 @Override
979 public String getPaddingBottom() {
980 return pixelString(defaultIfEmpty(super.getPaddingBottom(), "0px", null));
981 }
982
983
984
985
986 @Override
987 public String getPaddingLeft() {
988 return pixelString(defaultIfEmpty(super.getPaddingLeft(), "0px", null));
989 }
990
991
992
993
994 @Override
995 public String getPaddingRight() {
996 return pixelString(defaultIfEmpty(super.getPaddingRight(), "0px", null));
997 }
998
999
1000
1001
1002 @Override
1003 public String getPaddingTop() {
1004 return pixelString(defaultIfEmpty(super.getPaddingTop(), "0px", null));
1005 }
1006
1007
1008
1009
1010 @Override
1011 public String getRight() {
1012 return defaultIfEmpty(super.getRight(), AUTO, null);
1013 }
1014
1015
1016
1017
1018 @Override
1019 public String getTextIndent() {
1020 return defaultIfEmpty(super.getTextIndent(), "0px", null);
1021 }
1022
1023
1024
1025
1026 @Override
1027 public String getTop() {
1028 if (NONE.equals(getDisplay())) {
1029 return AUTO;
1030 }
1031
1032 final DomElement elem = getDomElement();
1033 if (!elem.isAttachedToPage()) {
1034 return "";
1035 }
1036
1037 final String superTop = super.getTop();
1038 if (!superTop.endsWith("%")) {
1039 return defaultIfEmpty(superTop, Definition.TOP);
1040 }
1041
1042 return CssPixelValueConverter.pixelString(elem, new CssPixelValueConverter.CssValue(0, 0) {
1043 @Override
1044 public String get(final ComputedCssStyleDeclaration style) {
1045 if (style.getDomElement() == elem) {
1046 return style.getStyleAttribute(Definition.TOP, true);
1047 }
1048 return style.getStyleAttribute(Definition.HEIGHT, true);
1049 }
1050 });
1051 }
1052
1053
1054
1055
1056
1057
1058
1059
1060 public int getTop(final boolean includeMargin, final boolean includeBorder, final boolean includePadding) {
1061 Integer cachedTop = getCachedTop();
1062
1063 int top = 0;
1064 if (null == cachedTop) {
1065 final String position = getPositionWithInheritance();
1066 if (ABSOLUTE.equals(position) || FIXED.equals(position)) {
1067 top = getTopForAbsolutePositionWithInheritance();
1068 }
1069 else if (getDomElement() instanceof HtmlTableCell) {
1070 top = 0;
1071 }
1072 else {
1073
1074 DomNode prev = getDomElement().getPreviousSibling();
1075 boolean prevHadComputedTop = false;
1076 while (prev != null && !prevHadComputedTop) {
1077 if (prev instanceof HtmlElement) {
1078 final ComputedCssStyleDeclaration style =
1079 prev.getPage().getEnclosingWindow().getComputedStyle((DomElement) prev, null);
1080
1081
1082 final String display = style.getDisplay();
1083 if (isBlock(display)) {
1084 int prevTop = 0;
1085 final Integer eCachedTop = style.getCachedTop();
1086 if (eCachedTop == null) {
1087 final String prevPosition = style.getPositionWithInheritance();
1088 if (ABSOLUTE.equals(prevPosition) || FIXED.equals(prevPosition)) {
1089 prevTop += style.getTopForAbsolutePositionWithInheritance();
1090 }
1091 else {
1092 if (RELATIVE.equals(prevPosition)) {
1093 final String t = style.getTopWithInheritance();
1094 prevTop += CssPixelValueConverter.pixelValue(t);
1095 }
1096 }
1097 }
1098 else {
1099 prevHadComputedTop = true;
1100 prevTop += eCachedTop.intValue();
1101 }
1102 prevTop += style.getCalculatedHeight(true, true);
1103 final int margin = CssPixelValueConverter.pixelValue(style.getMarginTop());
1104 prevTop += margin;
1105 top += prevTop;
1106 }
1107 }
1108 prev = prev.getPreviousSibling();
1109 }
1110
1111 if (RELATIVE.equals(position)) {
1112 final String t = getTopWithInheritance();
1113 top += CssPixelValueConverter.pixelValue(t);
1114 }
1115 }
1116 cachedTop = Integer.valueOf(top);
1117 setCachedTop(cachedTop);
1118 }
1119 else {
1120 top = cachedTop.intValue();
1121 }
1122
1123 if (includeMargin) {
1124 final int margin = CssPixelValueConverter.pixelValue(getMarginTop());
1125 top += margin;
1126 }
1127
1128 if (includeBorder) {
1129 final int border = CssPixelValueConverter.pixelValue(getBorderTopWidth());
1130 top += border;
1131 }
1132
1133 if (includePadding) {
1134 final int padding = getPaddingTopValue();
1135 top += padding;
1136 }
1137
1138 return top;
1139 }
1140
1141 private static boolean isBlock(final String display) {
1142 return display != null
1143 && !INLINE.equals(display)
1144 && !NONE.equals(display);
1145 }
1146
1147
1148
1149
1150
1151 public String getTopWithInheritance() {
1152 String top = getTop();
1153 if (INHERIT.equals(top)) {
1154 final HtmlElement parent = (HtmlElement) getDomElement().getParentNode();
1155 if (parent == null) {
1156 top = AUTO;
1157 }
1158 else {
1159 final ComputedCssStyleDeclaration style =
1160 parent.getPage().getEnclosingWindow().getComputedStyle(parent, null);
1161 top = style.getTopWithInheritance();
1162 }
1163 }
1164 return top;
1165 }
1166
1167
1168
1169
1170
1171 public String getBottomWithInheritance() {
1172 String bottom = getBottom();
1173 if (INHERIT.equals(bottom)) {
1174 final DomNode parent = getDomElement().getParentNode();
1175 if (parent == null) {
1176 bottom = AUTO;
1177 }
1178 else {
1179 final ComputedCssStyleDeclaration style =
1180 parent.getPage().getEnclosingWindow().getComputedStyle((DomElement) parent, null);
1181 bottom = style.getBottomWithInheritance();
1182 }
1183 }
1184 return bottom;
1185 }
1186
1187
1188
1189
1190 @Override
1191 public String getVerticalAlign() {
1192 return defaultIfEmpty(super.getVerticalAlign(), "baseline", null);
1193 }
1194
1195
1196
1197
1198 @Override
1199 public String getWidows() {
1200 return defaultIfEmpty(super.getWidows(), Definition.WIDOWS);
1201 }
1202
1203
1204
1205
1206 @Override
1207 public String getWordSpacing() {
1208 return defaultIfEmpty(super.getWordSpacing(), Definition.WORD_SPACING);
1209 }
1210
1211
1212
1213
1214 @Override
1215 public String getZIndex() {
1216 if (!getDomElement().isAttachedToPage()) {
1217 return EMPTY_FINAL;
1218 }
1219
1220 final String response = super.getZIndex();
1221 if (response.isEmpty()) {
1222 return AUTO;
1223 }
1224 return response;
1225 }
1226
1227
1228
1229
1230
1231 public int getMarginLeftValue() {
1232 return CssPixelValueConverter.pixelValue(getMarginLeft());
1233 }
1234
1235
1236
1237
1238
1239 public int getMarginRightValue() {
1240 return CssPixelValueConverter.pixelValue(getMarginRight());
1241 }
1242
1243
1244
1245
1246
1247 public int getMarginTopValue() {
1248 return CssPixelValueConverter.pixelValue(getMarginTop());
1249 }
1250
1251
1252
1253
1254
1255 public int getMarginBottomValue() {
1256 return CssPixelValueConverter.pixelValue(getMarginBottom());
1257 }
1258
1259
1260
1261
1262
1263
1264
1265
1266 public int getLeft(final boolean includeMargin, final boolean includeBorder, final boolean includePadding) {
1267 final String p = getPositionWithInheritance();
1268 final String l = getLeftWithInheritance();
1269 final String r = getRightWithInheritance();
1270
1271 int left;
1272 if ((ABSOLUTE.equals(p) || FIXED.equals(p)) && !AUTO.equals(l)) {
1273
1274 left = CssPixelValueConverter.pixelValue(l);
1275 }
1276 else if ((ABSOLUTE.equals(p) || FIXED.equals(p)) && !AUTO.equals(r)) {
1277
1278 final DomNode parent = getDomElement().getParentNode();
1279 final int parentWidth;
1280 if (parent == null) {
1281 parentWidth = getDomElement().getPage().getEnclosingWindow().getInnerWidth();
1282 }
1283 else if (parent instanceof Page page) {
1284 parentWidth = page.getEnclosingWindow().getInnerWidth();
1285 }
1286 else {
1287 final ComputedCssStyleDeclaration parentStyle =
1288 parent.getPage().getEnclosingWindow().getComputedStyle((DomElement) parent, null);
1289 parentWidth = parentStyle.getCalculatedWidth(false, false);
1290 }
1291 left = parentWidth - CssPixelValueConverter.pixelValue(r);
1292 }
1293 else if (FIXED.equals(p) && !AUTO.equals(r)) {
1294 final DomElement e = getDomElement();
1295 final WebWindow win = e.getPage().getEnclosingWindow();
1296 final ComputedCssStyleDeclaration style = win.getComputedStyle(e, null);
1297
1298 final DomNode parent = e.getParentNode();
1299 final int parentWidth;
1300 if (parent == null) {
1301 parentWidth = win.getInnerWidth();
1302 }
1303 else {
1304 final ComputedCssStyleDeclaration parentStyle = win.getComputedStyle((DomElement) parent, null);
1305 parentWidth = CssPixelValueConverter.pixelValue(parentStyle.getWidth())
1306 - CssPixelValueConverter.pixelValue(style.getWidth());
1307 }
1308 left = parentWidth - CssPixelValueConverter.pixelValue(r);
1309 }
1310 else if (FIXED.equals(p) && AUTO.equals(l)) {
1311
1312 final DomNode parent = getDomElement().getParentNode();
1313 if (parent == null || parent instanceof Page) {
1314 left = 0;
1315 }
1316 else {
1317 final ComputedCssStyleDeclaration style =
1318 parent.getPage().getEnclosingWindow().getComputedStyle((DomElement) parent, null);
1319 left = CssPixelValueConverter.pixelValue(style.getLeftWithInheritance());
1320 }
1321 }
1322 else if (STATIC.equals(p)) {
1323
1324 left = 0;
1325 DomNode prev = getDomElement().getPreviousSibling();
1326 while (prev != null) {
1327 if (prev instanceof HtmlElement) {
1328 final ComputedCssStyleDeclaration style =
1329 prev.getPage().getEnclosingWindow().getComputedStyle((DomElement) prev, null);
1330 final String d = style.getDisplay();
1331 if (isBlock(d)) {
1332 break;
1333 }
1334 else if (!NONE.equals(d)) {
1335 left += style.getCalculatedWidth(true, true);
1336 }
1337 }
1338 else if (prev instanceof DomText) {
1339 final String content = prev.getVisibleText();
1340 if (content != null) {
1341 left += content.trim().length()
1342 * getDomElement().getPage().getWebClient().getBrowserVersion().getPixesPerChar();
1343 }
1344 }
1345 prev = prev.getPreviousSibling();
1346 }
1347 }
1348 else {
1349
1350 left = CssPixelValueConverter.pixelValue(l);
1351 }
1352
1353 if (includeMargin) {
1354 final int margin = getMarginLeftValue();
1355 left += margin;
1356 }
1357
1358 if (includeBorder) {
1359 final int border = CssPixelValueConverter.pixelValue(getBorderLeftWidth());
1360 left += border;
1361 }
1362
1363 if (includePadding) {
1364 final int padding = getPaddingLeftValue();
1365 left += padding;
1366 }
1367
1368 return left;
1369 }
1370
1371
1372
1373
1374 @Override
1375 public String getPosition() {
1376 return defaultIfEmpty(super.getPosition(), Definition.POSITION);
1377 }
1378
1379
1380
1381
1382
1383 public String getPositionWithInheritance() {
1384 String p = getStyleAttribute(Definition.POSITION, true);
1385 if (INHERIT.equals(p)) {
1386 final DomNode parent = getDomElement().getParentNode();
1387 if (parent == null) {
1388 p = STATIC;
1389 }
1390 else {
1391 final ComputedCssStyleDeclaration style =
1392 parent.getPage().getEnclosingWindow().getComputedStyle((DomElement) parent, null);
1393 p = style.getPositionWithInheritance();
1394 }
1395 }
1396 return p;
1397 }
1398
1399
1400
1401
1402
1403 public String getLeftWithInheritance() {
1404 String left = getLeft();
1405 if (INHERIT.equals(left)) {
1406 final DomNode parent = getDomElement().getParentNode();
1407 if (parent == null) {
1408 left = AUTO;
1409 }
1410 else {
1411 final ComputedCssStyleDeclaration style =
1412 parent.getPage().getEnclosingWindow().getComputedStyle((DomElement) parent, null);
1413 left = style.getLeftWithInheritance();
1414 }
1415 }
1416 return left;
1417 }
1418
1419
1420
1421
1422
1423 public String getRightWithInheritance() {
1424 String right = getRight();
1425 if (INHERIT.equals(right)) {
1426 final DomNode parent = getDomElement().getParentNode();
1427 if (parent == null) {
1428 right = AUTO;
1429 }
1430 else {
1431 final ComputedCssStyleDeclaration style =
1432 parent.getPage().getEnclosingWindow().getComputedStyle((DomElement) parent, null);
1433 right = style.getRightWithInheritance();
1434 }
1435 }
1436 return right;
1437 }
1438
1439 private int getTopForAbsolutePositionWithInheritance() {
1440 final String t = getTopWithInheritance();
1441
1442 if (!AUTO.equals(t)) {
1443
1444 return CssPixelValueConverter.pixelValue(t);
1445 }
1446
1447 final String b = getBottomWithInheritance();
1448 if (!AUTO.equals(b)) {
1449
1450
1451
1452 int top = 0;
1453 DomNode child = getDomElement().getParentNode().getFirstChild();
1454 while (child != null) {
1455 if (child instanceof HtmlElement && child.mayBeDisplayed()) {
1456 top += 20;
1457 }
1458 child = child.getNextSibling();
1459 }
1460 top -= CssPixelValueConverter.pixelValue(b);
1461 return top;
1462 }
1463
1464 return 0;
1465 }
1466
1467
1468
1469
1470
1471
1472
1473 public int getCalculatedHeight(final boolean includeBorder, final boolean includePadding) {
1474 final DomElement element = getDomElement();
1475
1476 if (!element.isAttachedToPage()) {
1477 return 0;
1478 }
1479 int height = getCalculatedHeight(element);
1480 if (!"border-box".equals(getStyleAttribute(Definition.BOX_SIZING, true))) {
1481 if (includeBorder) {
1482 height += getBorderVertical();
1483 }
1484 else if (isScrollable(element, true, true) && !(element instanceof HtmlBody)) {
1485 height -= 17;
1486 }
1487
1488 if (includePadding) {
1489 height += getPaddingVertical();
1490 }
1491 }
1492 return height;
1493 }
1494
1495
1496
1497
1498
1499 private int getCalculatedHeight(final DomElement element) {
1500 final Integer cachedHeight = getCachedHeight();
1501 if (cachedHeight != null) {
1502 return cachedHeight.intValue();
1503 }
1504
1505 if (element instanceof HtmlImage image) {
1506 return updateCachedHeight(image.getHeightOrDefault());
1507 }
1508
1509 final boolean isInline = INLINE.equals(getDisplay()) && !(element instanceof HtmlInlineFrame);
1510
1511 if (isInline || super.getHeight().isEmpty()) {
1512 final int contentHeight = getContentHeight();
1513 if (contentHeight > 0) {
1514 return updateCachedHeight(contentHeight);
1515 }
1516 }
1517
1518 return updateCachedHeight(getEmptyHeight(element));
1519 }
1520
1521
1522
1523
1524
1525
1526
1527 public int getCalculatedWidth(final boolean includeBorder, final boolean includePadding) {
1528 final DomElement element = getDomElement();
1529
1530 if (!element.isAttachedToPage()) {
1531 return 0;
1532 }
1533 int width = getCalculatedWidth(element);
1534 if (!"border-box".equals(getStyleAttribute(Definition.BOX_SIZING, true))) {
1535 if (includeBorder) {
1536 width += getBorderHorizontal();
1537 }
1538 else if (isScrollable(element, false, true) && !(element instanceof HtmlBody)) {
1539 width -= 17;
1540 }
1541
1542 if (includePadding) {
1543 width += getPaddingHorizontal();
1544 }
1545 }
1546 return width;
1547 }
1548
1549 private int getCalculatedWidth(final DomElement element) {
1550 final Integer cachedWidth = getCachedWidth();
1551 if (cachedWidth != null) {
1552 return cachedWidth.intValue();
1553 }
1554
1555 if (!element.mayBeDisplayed()) {
1556 return updateCachedWidth(0);
1557 }
1558
1559 final String display = getDisplay();
1560 if (NONE.equals(display)) {
1561 return updateCachedWidth(0);
1562 }
1563
1564 final int width;
1565 final String styleWidth = getStyleAttribute(Definition.WIDTH, true);
1566 final DomNode parent = element.getParentNode();
1567
1568
1569 if ((INLINE.equals(display) || StringUtils.isEmptyOrNull(styleWidth))
1570 && parent instanceof HtmlElement) {
1571
1572 if (element instanceof HtmlCanvas) {
1573 return updateCachedWidth(300);
1574 }
1575
1576
1577 if (element instanceof HtmlInlineFrame iframe) {
1578 final String widthAttribute = iframe.getAttributeDirect("width");
1579 if (DomElement.ATTRIBUTE_NOT_DEFINED != widthAttribute) {
1580 return updateCachedWidth(CssPixelValueConverter.pixelValue(widthAttribute));
1581 }
1582
1583 return updateCachedWidth(300);
1584 }
1585
1586 if (element instanceof HtmlFrame) {
1587 return updateCachedWidth(element.getPage().getEnclosingWindow().getInnerWidth());
1588 }
1589
1590
1591 final String cssFloat = getCssFloat();
1592 final String position = getStyleAttribute(Definition.POSITION, true);
1593 if ("right".equals(cssFloat)
1594 || "left".equals(cssFloat)
1595 || ABSOLUTE.equals(position)
1596 || FIXED.equals(position)) {
1597
1598
1599
1600 final int contentWidth = getContentWidth();
1601 if (contentWidth > 0) {
1602 width = contentWidth;
1603 }
1604 else {
1605
1606 final BrowserVersion browserVersion =
1607 getDomElement().getPage().getWebClient().getBrowserVersion();
1608 width = element.getVisibleText().length() * browserVersion.getPixesPerChar();
1609 }
1610 }
1611 else if (BLOCK.equals(display)) {
1612 final int windowWidth = element.getPage().getEnclosingWindow().getInnerWidth();
1613 if (element instanceof HtmlBody) {
1614 width = windowWidth - 16;
1615 }
1616 else {
1617
1618 final ComputedCssStyleDeclaration parentStyle =
1619 parent.getPage().getEnclosingWindow().getComputedStyle((DomElement) parent, null);
1620 width = parentStyle.getCalculatedWidth(false, false)
1621 - (getBorderHorizontal() + getPaddingHorizontal());
1622 }
1623 }
1624 else if (element instanceof HtmlSubmitInput
1625 || element instanceof HtmlResetInput
1626 || element instanceof HtmlButtonInput
1627 || element instanceof HtmlButton
1628 || element instanceof HtmlFileInput) {
1629
1630
1631 final String text = element.asNormalizedText();
1632 final BrowserVersion browserVersion = getDomElement().getPage().getWebClient().getBrowserVersion();
1633
1634 width = 10 + (int) (text.length() * browserVersion.getPixesPerChar() * 0.9);
1635 }
1636 else if (element instanceof HtmlTextInput || element instanceof HtmlPasswordInput) {
1637 final BrowserVersion browserVersion = getDomElement().getPage().getWebClient().getBrowserVersion();
1638 if (browserVersion.hasFeature(JS_CLIENTWIDTH_INPUT_TEXT_173)) {
1639 return 173;
1640 }
1641 if (browserVersion.hasFeature(JS_CLIENTWIDTH_INPUT_TEXT_157)) {
1642 return 157;
1643 }
1644 width = 161;
1645 }
1646 else if (element instanceof HtmlRadioButtonInput || element instanceof HtmlCheckBoxInput) {
1647 final BrowserVersion browserVersion = getDomElement().getPage().getWebClient().getBrowserVersion();
1648 if (browserVersion.hasFeature(JS_CLIENTWIDTH_RADIO_CHECKBOX_14)) {
1649 width = 14;
1650 }
1651 else {
1652 width = 13;
1653 }
1654 }
1655 else if (element instanceof HtmlTextArea) {
1656 width = 100;
1657 }
1658 else if (element instanceof HtmlImage image) {
1659 width = image.getWidthOrDefault();
1660 }
1661 else {
1662
1663 width = getContentWidth();
1664 }
1665 }
1666 else if (AUTO.equals(styleWidth)) {
1667 width = element.getPage().getEnclosingWindow().getInnerWidth();
1668 }
1669 else {
1670
1671 width = CssPixelValueConverter.pixelValue(element,
1672 new CssPixelValueConverter.CssValue(0, element.getPage().getEnclosingWindow().getInnerWidth()) {
1673 @Override public String get(final ComputedCssStyleDeclaration style) {
1674 return style.getStyleAttribute(Definition.WIDTH, true);
1675 }
1676 });
1677 }
1678
1679 return updateCachedWidth(width);
1680 }
1681
1682
1683
1684
1685
1686 public int getContentWidth() {
1687 int inlineWidth = 0;
1688 int maxBlockWidth = 0;
1689 final DomElement element = getDomElement();
1690 Iterable<DomNode> children = element.getChildren();
1691 if (element instanceof BaseFrameElement frameElement) {
1692 final Page enclosedPage = frameElement.getEnclosedPage();
1693 if (enclosedPage != null && enclosedPage.isHtmlPage()) {
1694 children = ((DomNode) enclosedPage).getChildren();
1695 }
1696 }
1697 final WebWindow webWindow = element.getPage().getEnclosingWindow();
1698 for (final DomNode child : children) {
1699 if (child instanceof HtmlElement e) {
1700 final ComputedCssStyleDeclaration style = webWindow.getComputedStyle(e, null);
1701 final String childDisplay = style.getDisplay();
1702 final int w;
1703 if (BLOCK.equals(childDisplay)) {
1704
1705
1706
1707 final String childStyleWidth = style.getStyleAttribute(Definition.WIDTH, true);
1708 if (StringUtils.isEmptyOrNull(childStyleWidth) || AUTO.equals(childStyleWidth)) {
1709
1710
1711 w = style.getContentWidth()
1712 + style.getBorderHorizontal()
1713 + style.getPaddingHorizontal();
1714 }
1715 else {
1716 w = style.getCalculatedWidth(true, true);
1717 }
1718 if (w > maxBlockWidth) {
1719 maxBlockWidth = w;
1720 }
1721 }
1722 else {
1723
1724 w = style.getCalculatedWidth(true, true);
1725 inlineWidth += w;
1726 }
1727 }
1728 else if (child instanceof DomText) {
1729 final BrowserVersion browserVersion = getDomElement().getPage().getWebClient().getBrowserVersion();
1730 final DomNode parent = child.getParentNode();
1731 if (parent instanceof HtmlElement) {
1732 final ComputedCssStyleDeclaration style = webWindow.getComputedStyle((DomElement) parent, null);
1733 final int height = browserVersion.getFontHeight(
1734 style.getStyleAttribute(Definition.FONT_SIZE, true));
1735 inlineWidth += child.getVisibleText().length() * (int) (height / 1.8f);
1736 }
1737 else {
1738 inlineWidth += child.getVisibleText().length() * browserVersion.getPixesPerChar();
1739 }
1740 }
1741 }
1742 return Math.max(maxBlockWidth, inlineWidth);
1743 }
1744
1745
1746
1747
1748
1749 private int getEmptyHeight(final DomElement element) {
1750 final Integer cachedEmptyHeight = getCachedEmptyHeight();
1751 if (cachedEmptyHeight != null) {
1752 return cachedEmptyHeight.intValue();
1753 }
1754
1755 if (!element.mayBeDisplayed()) {
1756 return updateCachedEmptyHeight(0);
1757 }
1758
1759 final String display = getDisplay();
1760 if (NONE.equals(display)) {
1761 return updateCachedEmptyHeight(0);
1762 }
1763
1764 final SgmlPage page = element.getPage();
1765 final WebWindow webWindow = page.getEnclosingWindow();
1766 final int windowHeight = webWindow.getInnerHeight();
1767
1768 if (element instanceof HtmlBody) {
1769 if (page instanceof HtmlPage htmlPage && htmlPage.isQuirksMode()) {
1770 return updateCachedEmptyHeight(windowHeight);
1771 }
1772
1773 return updateCachedEmptyHeight(0);
1774 }
1775
1776 int defaultHeight;
1777 if ((element instanceof HtmlAbbreviated
1778 || element instanceof HtmlAcronym
1779 || element instanceof HtmlAddress
1780 || element instanceof HtmlArticle
1781 || element instanceof HtmlAside
1782 || element instanceof HtmlBaseFont
1783 || element instanceof HtmlBidirectionalIsolation
1784 || element instanceof HtmlBidirectionalOverride
1785 || element instanceof HtmlBig
1786 || element instanceof HtmlBold
1787 || element instanceof HtmlCenter
1788 || element instanceof HtmlCitation
1789 || element instanceof HtmlCode
1790 || element instanceof HtmlDefinition
1791 || element instanceof HtmlDefinitionDescription
1792 || element instanceof HtmlDefinitionTerm
1793 || element instanceof HtmlEmphasis
1794 || element instanceof HtmlFigure
1795 || element instanceof HtmlFigureCaption
1796 || element instanceof HtmlFooter
1797 || element instanceof HtmlHeader
1798 || element instanceof HtmlItalic
1799 || element instanceof HtmlKeyboard
1800 || element instanceof HtmlLayer
1801 || element instanceof HtmlMark
1802 || element instanceof HtmlNav
1803 || element instanceof HtmlNoBreak
1804 || element instanceof HtmlNoEmbed
1805 || element instanceof HtmlNoFrames
1806 || element instanceof HtmlNoLayer
1807 || element instanceof HtmlNoScript
1808 || element instanceof HtmlPlainText
1809 || element instanceof HtmlRp
1810 || element instanceof HtmlRtc
1811 || element instanceof HtmlS
1812 || element instanceof HtmlSample
1813 || element instanceof HtmlSection
1814 || element instanceof HtmlSmall
1815 || element instanceof HtmlStrike
1816 || element instanceof HtmlStrong
1817 || element instanceof HtmlSubscript
1818 || element instanceof HtmlSummary
1819 || element instanceof HtmlSuperscript
1820 || element instanceof HtmlTeletype
1821 || element instanceof HtmlUnderlined
1822 || element instanceof HtmlUnknownElement
1823 || element instanceof HtmlWordBreak
1824 || element instanceof HtmlMain
1825 || element instanceof HtmlVariable
1826
1827 || element instanceof HtmlDivision
1828 || element instanceof HtmlData
1829 || element instanceof HtmlTime
1830 || element instanceof HtmlOutput
1831 || element instanceof HtmlSlot
1832 || element instanceof HtmlLegend)
1833 && StringUtils.isBlank(element.getTextContent())) {
1834 defaultHeight = 0;
1835 }
1836 else if (element.getFirstChild() == null) {
1837 if (element instanceof HtmlRadioButtonInput || element instanceof HtmlCheckBoxInput) {
1838 final BrowserVersion browser = webWindow.getWebClient().getBrowserVersion();
1839 if (browser.hasFeature(JS_CLIENTHEIGHT_RADIO_CHECKBOX_14)) {
1840 defaultHeight = 14;
1841 }
1842 else {
1843 defaultHeight = 13;
1844 }
1845 }
1846 else if (element instanceof HtmlButton) {
1847 defaultHeight = 20;
1848 }
1849 else if (element instanceof HtmlInput && !(element instanceof HtmlHiddenInput)) {
1850 final BrowserVersion browser = webWindow.getWebClient().getBrowserVersion();
1851 if (browser.hasFeature(JS_CLIENTHEIGHT_INPUT_17)) {
1852 defaultHeight = 17;
1853 }
1854 else if (browser.hasFeature(JS_CLIENTHEIGHT_INPUT_18)) {
1855 defaultHeight = 18;
1856 }
1857 else {
1858 defaultHeight = 20;
1859 }
1860 }
1861 else if (element instanceof HtmlSelect) {
1862 defaultHeight = 20;
1863 }
1864 else if (element instanceof HtmlTextArea) {
1865 defaultHeight = 49;
1866 }
1867 else {
1868 defaultHeight = 0;
1869 }
1870 }
1871 else if (element instanceof HtmlRb) {
1872 final BrowserVersion browser = webWindow.getWebClient().getBrowserVersion();
1873 if (browser.hasFeature(JS_CLIENTHEIGHT_RB_17)) {
1874 defaultHeight = 17;
1875 }
1876 else {
1877 defaultHeight = 0;
1878 }
1879 }
1880 else if (element instanceof HtmlRt) {
1881 final BrowserVersion browser = webWindow.getWebClient().getBrowserVersion();
1882 if (browser.hasFeature(JS_CLIENTHEIGHT_RT_9)) {
1883 defaultHeight = 9;
1884 }
1885 else {
1886 defaultHeight = 0;
1887 }
1888 }
1889 else if (element instanceof HtmlRuby) {
1890 final BrowserVersion browser = webWindow.getWebClient().getBrowserVersion();
1891 if (browser.hasFeature(JS_CLIENTHEIGHT_RUBY_17)) {
1892 defaultHeight = 17;
1893 }
1894 else {
1895 defaultHeight = 0;
1896 }
1897 }
1898 else {
1899 final String fontSize;
1900
1901 boolean isHeading = false;
1902 if (element instanceof HtmlHeading1) {
1903 isHeading = true;
1904 final String value = getStyleAttribute(Definition.FONT_SIZE, false);
1905 if (value.isEmpty()) {
1906 fontSize = "32px";
1907 }
1908 else {
1909 fontSize = getStyleAttribute(Definition.FONT_SIZE, true);
1910 }
1911 }
1912 else if (element instanceof HtmlHeading2) {
1913 isHeading = true;
1914 final String value = getStyleAttribute(Definition.FONT_SIZE, false);
1915 if (value.isEmpty()) {
1916 fontSize = "24px";
1917 }
1918 else {
1919 fontSize = getStyleAttribute(Definition.FONT_SIZE, true);
1920 }
1921 }
1922 else if (element instanceof HtmlHeading3) {
1923 isHeading = true;
1924 final String value = getStyleAttribute(Definition.FONT_SIZE, false);
1925 if (value.isEmpty()) {
1926 fontSize = "19px";
1927 }
1928 else {
1929 fontSize = getStyleAttribute(Definition.FONT_SIZE, true);
1930 }
1931 }
1932 else if (element instanceof HtmlHeading4) {
1933 isHeading = true;
1934 final String value = getStyleAttribute(Definition.FONT_SIZE, false);
1935 if (value.isEmpty()) {
1936 fontSize = "16px";
1937 }
1938 else {
1939 fontSize = getStyleAttribute(Definition.FONT_SIZE, true);
1940 }
1941 }
1942 else if (element instanceof HtmlHeading5) {
1943 isHeading = true;
1944 final String value = getStyleAttribute(Definition.FONT_SIZE, false);
1945 if (value.isEmpty()) {
1946 fontSize = "13px";
1947 }
1948 else {
1949 fontSize = getStyleAttribute(Definition.FONT_SIZE, true);
1950 }
1951 }
1952 else if (element instanceof HtmlHeading6) {
1953 isHeading = true;
1954 final String value = getStyleAttribute(Definition.FONT_SIZE, false);
1955 if (value.isEmpty()) {
1956 fontSize = "11px";
1957 }
1958 else {
1959 fontSize = getStyleAttribute(Definition.FONT_SIZE, true);
1960 }
1961 }
1962 else {
1963 fontSize = getStyleAttribute(Definition.FONT_SIZE, true);
1964 }
1965
1966 defaultHeight = webWindow.getWebClient().getBrowserVersion().getFontHeight(fontSize);
1967
1968 if (isHeading
1969 || element instanceof HtmlDivision
1970 || element instanceof HtmlSpan) {
1971 String width = getStyleAttribute(Definition.WIDTH, false);
1972
1973
1974 DomNode parent = getDomElement().getParentNode();
1975 final WebWindow win = parent.getPage().getEnclosingWindow();
1976 while (width.isEmpty() && parent != null) {
1977 if (parent instanceof DomElement domElement) {
1978 final ComputedCssStyleDeclaration computedCss = win.getComputedStyle(domElement, null);
1979 width = computedCss.getStyleAttribute(Definition.WIDTH, false);
1980 }
1981 parent = parent.getParentNode();
1982 if (parent instanceof Page) {
1983 break;
1984 }
1985 }
1986 final int pixelWidth = CssPixelValueConverter.pixelValue(width);
1987 final String content = element.getVisibleText();
1988
1989 if (pixelWidth > 0
1990 && !width.isEmpty()
1991 && StringUtils.isNotBlank(content)) {
1992 final int lineCount = Platform.getFontUtil().countLines(content, pixelWidth, fontSize);
1993 defaultHeight *= lineCount;
1994 }
1995 else {
1996 if (element instanceof HtmlSpan && StringUtils.isEmptyOrNull(content)) {
1997 defaultHeight = 0;
1998 }
1999 else {
2000 defaultHeight *= org.apache.commons.lang3.StringUtils.countMatches(content, '\n') + 1;
2001 }
2002 }
2003
2004 final String styleHeight = getStyleAttribute(Definition.HEIGHT, true);
2005 if (styleHeight.endsWith("%")) {
2006 if (page instanceof HtmlPage htmlPage && !htmlPage.isQuirksMode()) {
2007 return defaultHeight;
2008 }
2009 }
2010 }
2011 }
2012
2013 if (element instanceof HtmlInlineFrame iframe) {
2014 final String heightAttribute = iframe.getAttributeDirect("height");
2015 if (DomElement.ATTRIBUTE_NOT_DEFINED != heightAttribute) {
2016 final int height = CssPixelValueConverter.pixelValue(heightAttribute);
2017 return updateCachedEmptyHeight(height);
2018 }
2019
2020 defaultHeight = 154;
2021 }
2022
2023 final boolean isInline = INLINE.equals(display) && !(element instanceof HtmlInlineFrame);
2024
2025 final int defaultWindowHeight = element instanceof HtmlCanvas ? 150 : windowHeight;
2026
2027 int height = CssPixelValueConverter.pixelValue(element,
2028 new CssPixelValueConverter.CssValue(defaultHeight, defaultWindowHeight) {
2029 @Override public String get(final ComputedCssStyleDeclaration style) {
2030 final DomElement elem = style.getDomElement();
2031 if (elem instanceof HtmlBody) {
2032 return String.valueOf(elem.getPage().getEnclosingWindow().getInnerHeight());
2033 }
2034
2035 if (isInline) {
2036 return "";
2037 }
2038 return style.getStyleAttribute(Definition.HEIGHT, true);
2039 }
2040 });
2041
2042 if (height == 0 && (isInline || super.getHeight().isEmpty())) {
2043 height = defaultHeight;
2044 }
2045
2046 return updateCachedEmptyHeight(height);
2047 }
2048
2049
2050
2051
2052
2053 public int getContentHeight() {
2054
2055
2056
2057
2058 final DomNode node = getDomElement();
2059 if (!node.mayBeDisplayed()) {
2060 return 0;
2061 }
2062
2063 ComputedCssStyleDeclaration lastFlowing = null;
2064 final Set<ComputedCssStyleDeclaration> styles = new HashSet<>();
2065
2066 if (node instanceof HtmlTableRow row) {
2067 for (final HtmlTableCell cell : row.getCellIterator()) {
2068 if (cell.mayBeDisplayed()) {
2069 final ComputedCssStyleDeclaration style =
2070 cell.getPage().getEnclosingWindow().getComputedStyle(cell, null);
2071 styles.add(style);
2072 }
2073 }
2074 }
2075 else {
2076 for (final DomNode child : node.getChildren()) {
2077 if (child.mayBeDisplayed()) {
2078 if (child instanceof HtmlElement e) {
2079 final ComputedCssStyleDeclaration style =
2080 e.getPage().getEnclosingWindow().getComputedStyle(e, null);
2081 final String position = style.getPositionWithInheritance();
2082 if (STATIC.equals(position) || RELATIVE.equals(position)) {
2083 lastFlowing = style;
2084 }
2085 else if (ABSOLUTE.equals(position) || FIXED.equals(position)) {
2086 styles.add(style);
2087 }
2088 }
2089 }
2090 }
2091
2092 if (lastFlowing != null) {
2093 styles.add(lastFlowing);
2094 }
2095 }
2096
2097 int max = 0;
2098 for (final ComputedCssStyleDeclaration style : styles) {
2099 final int h = style.getTop(true, false, false) + style.getCalculatedHeight(true, true);
2100 if (h > max) {
2101 max = h;
2102 }
2103 }
2104 return max;
2105 }
2106
2107
2108
2109
2110
2111
2112
2113 public boolean isScrollable(final boolean horizontal) {
2114 return isScrollable(getDomElement(), horizontal, false);
2115 }
2116
2117
2118
2119
2120 private boolean isScrollable(final DomElement element, final boolean horizontal, final boolean ignoreSize) {
2121 final boolean scrollable;
2122
2123 String overflow;
2124 if (horizontal) {
2125 overflow = getStyleAttribute(Definition.OVERFLOW_X_, false);
2126 if (StringUtils.isEmptyOrNull(overflow)) {
2127 overflow = getStyleAttribute(Definition.OVERFLOW_X, false);
2128 }
2129
2130 if (StringUtils.isEmptyOrNull(overflow)) {
2131 overflow = getStyleAttribute(Definition.OVERFLOW, true);
2132 }
2133 scrollable = (element instanceof HtmlBody || SCROLL.equals(overflow) || AUTO.equals(overflow))
2134 && (ignoreSize || getContentWidth() > getCalculatedWidth(element));
2135 }
2136 else {
2137 overflow = getStyleAttribute(Definition.OVERFLOW_Y_, false);
2138 if (StringUtils.isEmptyOrNull(overflow)) {
2139 overflow = getStyleAttribute(Definition.OVERFLOW_Y, false);
2140 }
2141
2142 if (StringUtils.isEmptyOrNull(overflow)) {
2143 overflow = getStyleAttribute(Definition.OVERFLOW, true);
2144 }
2145
2146 scrollable = (element instanceof HtmlBody || SCROLL.equals(overflow) || AUTO.equals(overflow))
2147 && (ignoreSize || getContentHeight() > getEmptyHeight(element));
2148 }
2149 return scrollable;
2150 }
2151
2152 private int getBorderHorizontal() {
2153 final Integer borderHorizontal = getCachedBorderHorizontal();
2154 if (borderHorizontal != null) {
2155 return borderHorizontal.intValue();
2156 }
2157
2158 final int border = NONE.equals(getDisplay()) ? 0 : getBorderLeftValue() + getBorderRightValue();
2159 return updateCachedBorderHorizontal(border);
2160 }
2161
2162 private int getBorderVertical() {
2163 final Integer borderVertical = getCachedBorderVertical();
2164 if (borderVertical != null) {
2165 return borderVertical.intValue();
2166 }
2167
2168 final int border = NONE.equals(getDisplay()) ? 0 : getBorderTopValue() + getBorderBottomValue();
2169 return updateCachedBorderVertical(border);
2170 }
2171
2172
2173
2174
2175
2176 public int getBorderLeftValue() {
2177 return CssPixelValueConverter.pixelValue(getBorderLeftWidth());
2178 }
2179
2180
2181
2182
2183
2184 public int getBorderRightValue() {
2185 return CssPixelValueConverter.pixelValue(getBorderRightWidth());
2186 }
2187
2188
2189
2190
2191
2192 public int getBorderTopValue() {
2193 return CssPixelValueConverter.pixelValue(getBorderTopWidth());
2194 }
2195
2196
2197
2198
2199
2200 public int getBorderBottomValue() {
2201 return CssPixelValueConverter.pixelValue(getBorderBottomWidth());
2202 }
2203
2204 private int getPaddingHorizontal() {
2205 final Integer paddingHorizontal = getCachedPaddingHorizontal();
2206 if (paddingHorizontal != null) {
2207 return paddingHorizontal.intValue();
2208 }
2209
2210 final int padding = NONE.equals(getDisplay()) ? 0 : getPaddingLeftValue() + getPaddingRightValue();
2211 return updateCachedPaddingHorizontal(padding);
2212 }
2213
2214 private int getPaddingVertical() {
2215 final Integer paddingVertical = getCachedPaddingVertical();
2216 if (paddingVertical != null) {
2217 return paddingVertical.intValue();
2218 }
2219
2220 final int padding = NONE.equals(getDisplay()) ? 0 : getPaddingTopValue() + getPaddingBottomValue();
2221 return updateCachedPaddingVertical(padding);
2222 }
2223
2224
2225
2226
2227
2228 public int getPaddingLeftValue() {
2229 return CssPixelValueConverter.pixelValue(getPaddingLeft());
2230 }
2231
2232
2233
2234
2235
2236 public int getPaddingRightValue() {
2237 return CssPixelValueConverter.pixelValue(getPaddingRight());
2238 }
2239
2240
2241
2242
2243
2244 public int getPaddingTopValue() {
2245 return CssPixelValueConverter.pixelValue(getPaddingTop());
2246 }
2247
2248
2249
2250
2251
2252 public int getPaddingBottomValue() {
2253 return CssPixelValueConverter.pixelValue(getPaddingBottom());
2254 }
2255
2256
2257
2258
2259
2260 public Integer getCachedWidth() {
2261 return width_;
2262 }
2263
2264
2265
2266
2267
2268
2269 public int updateCachedWidth(final int width) {
2270 width_ = Integer.valueOf(width);
2271 return width;
2272 }
2273
2274
2275
2276
2277
2278 public Integer getCachedHeight() {
2279 return height_;
2280 }
2281
2282
2283
2284
2285
2286
2287 public int updateCachedHeight(final int height) {
2288 height_ = Integer.valueOf(height);
2289 return height;
2290 }
2291
2292
2293
2294
2295
2296 public Integer getCachedEmptyHeight() {
2297 return emptyHeight_;
2298 }
2299
2300
2301
2302
2303
2304
2305 public int updateCachedEmptyHeight(final int emptyHeight) {
2306 emptyHeight_ = Integer.valueOf(emptyHeight);
2307 return emptyHeight;
2308 }
2309
2310
2311
2312
2313
2314 public Integer getCachedTop() {
2315 return top_;
2316 }
2317
2318
2319
2320
2321
2322 public void setCachedTop(final Integer top) {
2323 top_ = top;
2324 }
2325
2326
2327
2328
2329
2330 public Integer getCachedPaddingHorizontal() {
2331 return paddingHorizontal_;
2332 }
2333
2334
2335
2336
2337
2338
2339 public int updateCachedPaddingHorizontal(final int paddingHorizontal) {
2340 paddingHorizontal_ = Integer.valueOf(paddingHorizontal);
2341 return paddingHorizontal;
2342 }
2343
2344
2345
2346
2347
2348 public Integer getCachedPaddingVertical() {
2349 return paddingVertical_;
2350 }
2351
2352
2353
2354
2355
2356
2357 public int updateCachedPaddingVertical(final int paddingVertical) {
2358 paddingVertical_ = Integer.valueOf(paddingVertical);
2359 return paddingVertical;
2360 }
2361
2362
2363
2364
2365
2366 public Integer getCachedBorderHorizontal() {
2367 return borderHorizontal_;
2368 }
2369
2370
2371
2372
2373
2374
2375 public int updateCachedBorderHorizontal(final int borderHorizontal) {
2376 borderHorizontal_ = Integer.valueOf(borderHorizontal);
2377 return borderHorizontal;
2378 }
2379
2380
2381
2382
2383
2384 public Integer getCachedBorderVertical() {
2385 return borderVertical_;
2386 }
2387
2388
2389
2390
2391
2392
2393 public int updateCachedBorderVertical(final int borderVertical) {
2394 borderVertical_ = Integer.valueOf(borderVertical);
2395 return borderVertical;
2396 }
2397
2398
2399
2400
2401
2402
2403
2404 public void applyStyleFromSelector(final CSSStyleDeclarationImpl declaration, final Selector selector) {
2405 final SelectorSpecificity specificity = selector.getSelectorSpecificity();
2406 for (final Property prop : declaration.getProperties()) {
2407 final String name = prop.getName();
2408 final String value = declaration.getPropertyValue(name);
2409 final String priority = declaration.getPropertyPriority(name);
2410 applyLocalStyleAttribute(name, value, priority, specificity);
2411 }
2412 }
2413
2414 private void applyLocalStyleAttribute(final String name, final String newValue, final String priority,
2415 final SelectorSpecificity specificity) {
2416 if (!StyleElement.PRIORITY_IMPORTANT.equals(priority)) {
2417 final StyleElement existingElement = localModifications_.get(name);
2418 if (existingElement != null) {
2419 if (existingElement.isImportant()) {
2420 return;
2421 }
2422 else if (specificity.compareTo(existingElement.getSpecificity()) < 0) {
2423 return;
2424 }
2425 }
2426 }
2427 final StyleElement element = new StyleElement(name, newValue, priority, specificity);
2428 localModifications_.put(name, element);
2429 }
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439 public void setDefaultLocalStyleAttribute(final String name, final String newValue) {
2440 final StyleElement element = new StyleElement(name, newValue, "", SelectorSpecificity.DEFAULT_STYLE_ATTRIBUTE);
2441 localModifications_.put(name, element);
2442 }
2443
2444
2445
2446
2447 @Override
2448 public boolean hasFeature(final BrowserVersionFeatures property) {
2449 return getDomElement().hasFeature(property);
2450 }
2451
2452
2453
2454
2455 @Override
2456 public BrowserVersion getBrowserVersion() {
2457 return getDomElement().getPage().getWebClient().getBrowserVersion();
2458 }
2459
2460
2461
2462
2463 @Override
2464 public boolean isComputed() {
2465 return true;
2466 }
2467
2468
2469
2470
2471 @Override
2472 public String toString() {
2473 return "ComputedCssStyleDeclaration for '" + getDomElement() + "'";
2474 }
2475
2476 private String defaultIfEmpty(final String str, final StyleAttributes.Definition definition) {
2477 return defaultIfEmpty(str, definition, false);
2478 }
2479
2480 private String defaultIfEmpty(final String str, final StyleAttributes.Definition definition,
2481 final boolean isPixel) {
2482 if (!getDomElement().isAttachedToPage()) {
2483 return EMPTY_FINAL;
2484 }
2485 if (str == null || str.isEmpty()) {
2486 return definition.getDefaultComputedValue(getBrowserVersion());
2487 }
2488 if (isPixel) {
2489 return pixelString(str);
2490 }
2491 return str;
2492 }
2493
2494
2495
2496
2497
2498
2499 private String defaultIfEmpty(final String str, final String toReturnIfEmptyOrDefault, final String defaultValue) {
2500 if (!getDomElement().isAttachedToPage()) {
2501 return EMPTY_FINAL;
2502 }
2503 if (str == null || str.isEmpty() || str.equals(defaultValue)) {
2504 return toReturnIfEmptyOrDefault;
2505 }
2506 return str;
2507 }
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517 private static String pixelString(final String value) {
2518 if (EMPTY_FINAL == value || value.endsWith("px")) {
2519 return value;
2520 }
2521 return CssPixelValueConverter.pixelValue(value) + "px";
2522 }
2523 }