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