org.htmlunit.javascript.host.css.CSSStyleDeclaration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xlt Show documentation
Show all versions of xlt Show documentation
XLT (Xceptance LoadTest) is an extensive load and performance test tool developed and maintained by Xceptance.
The newest version!
/*
* Copyright (c) 2002-2024 Gargoyle Software Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.htmlunit.javascript.host.css;
import static org.htmlunit.BrowserVersionFeatures.CSS_BACKGROUND_INITIAL;
import static org.htmlunit.BrowserVersionFeatures.CSS_LENGTH_INITIAL;
import static org.htmlunit.BrowserVersionFeatures.CSS_OUTLINE_WIDTH_UNIT_NOT_REQUIRED;
import static org.htmlunit.BrowserVersionFeatures.CSS_VERTICAL_ALIGN_SUPPORTS_AUTO;
import static org.htmlunit.BrowserVersionFeatures.CSS_ZINDEX_TYPE_INTEGER;
import static org.htmlunit.BrowserVersionFeatures.JS_STYLE_UNSUPPORTED_PROPERTY_GETTER;
import static org.htmlunit.BrowserVersionFeatures.JS_STYLE_WORD_SPACING_ACCEPTS_PERCENT;
import static org.htmlunit.BrowserVersionFeatures.JS_STYLE_WRONG_INDEX_RETURNS_UNDEFINED;
import static org.htmlunit.css.CssStyleSheet.ABSOLUTE;
import static org.htmlunit.css.CssStyleSheet.AUTO;
import static org.htmlunit.css.CssStyleSheet.FIXED;
import static org.htmlunit.css.CssStyleSheet.INHERIT;
import static org.htmlunit.css.CssStyleSheet.INITIAL;
import static org.htmlunit.css.CssStyleSheet.RELATIVE;
import static org.htmlunit.css.CssStyleSheet.STATIC;
import static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
import static org.htmlunit.javascript.configuration.SupportedBrowser.FF;
import static org.htmlunit.javascript.configuration.SupportedBrowser.FF_ESR;
import static org.htmlunit.javascript.configuration.SupportedBrowser.IE;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.htmlunit.BrowserVersion;
import org.htmlunit.corejs.javascript.ES6Iterator;
import org.htmlunit.corejs.javascript.NativeArrayIterator;
import org.htmlunit.corejs.javascript.ScriptRuntime;
import org.htmlunit.corejs.javascript.Scriptable;
import org.htmlunit.corejs.javascript.ScriptableObject;
import org.htmlunit.corejs.javascript.Undefined;
import org.htmlunit.css.AbstractCssStyleDeclaration;
import org.htmlunit.css.ComputedCssStyleDeclaration;
import org.htmlunit.css.CssPixelValueConverter;
import org.htmlunit.css.ElementCssStyleDeclaration;
import org.htmlunit.css.StyleAttributes;
import org.htmlunit.css.StyleAttributes.Definition;
import org.htmlunit.css.StyleElement;
import org.htmlunit.css.WrappedCssStyleDeclaration;
import org.htmlunit.cssparser.dom.AbstractCSSRuleImpl;
import org.htmlunit.javascript.HtmlUnitScriptable;
import org.htmlunit.javascript.JavaScriptEngine;
import org.htmlunit.javascript.configuration.JsxClass;
import org.htmlunit.javascript.configuration.JsxConstructor;
import org.htmlunit.javascript.configuration.JsxFunction;
import org.htmlunit.javascript.configuration.JsxGetter;
import org.htmlunit.javascript.configuration.JsxSetter;
import org.htmlunit.javascript.configuration.JsxSymbol;
import org.htmlunit.javascript.host.Element;
/**
* A JavaScript object for {@code CSSStyleDeclaration}.
*
* @author Mike Bowler
* @author Christian Sell
* @author Daniel Gredler
* @author Chris Erskine
* @author Ahmed Ashour
* @author Rodney Gitzel
* @author Sudhan Moghe
* @author Ronald Brill
* @author Frank Danek
* @author Dennis Duysak
* @see MDN doc
*/
@JsxClass
public class CSSStyleDeclaration extends HtmlUnitScriptable {
private static final Set LENGTH_PROPERTIES_FFFF = new HashSet<>(Arrays.asList(
Definition.BORDER_TOP_WIDTH.getAttributeName(),
Definition.BORDER_LEFT_WIDTH.getAttributeName(),
Definition.BORDER_BOTTOM_WIDTH.getAttributeName(),
Definition.BORDER_RIGHT_WIDTH.getAttributeName(),
Definition.LETTER_SPACING.getAttributeName()));
private static final Set LENGTH_PROPERTIES_TTFF = new HashSet<>(Arrays.asList(
Definition.HEIGHT.getAttributeName(),
Definition.WIDTH.getAttributeName(),
Definition.TOP.getAttributeName(),
Definition.LEFT.getAttributeName(),
Definition.BOTTOM.getAttributeName(),
Definition.RIGHT.getAttributeName(),
Definition.MARGIN_TOP.getAttributeName(),
Definition.MARGIN_LEFT.getAttributeName(),
Definition.MARGIN_BOTTOM.getAttributeName(),
Definition.MARGIN_RIGHT.getAttributeName(),
Definition.MIN_HEIGHT.getAttributeName(),
Definition.MIN_WIDTH.getAttributeName()
));
private static final Set LENGTH_PROPERTIES_FTFF = new HashSet<>(Arrays.asList(
Definition.FONT_SIZE.getAttributeName(),
Definition.TEXT_INDENT.getAttributeName(),
Definition.PADDING_TOP.getAttributeName(),
Definition.PADDING_LEFT.getAttributeName(),
Definition.PADDING_BOTTOM.getAttributeName(),
Definition.PADDING_RIGHT.getAttributeName(),
Definition.MAX_HEIGHT.getAttributeName(),
Definition.MAX_WIDTH.getAttributeName()
));
private static final String[] THIN_MED_THICK = {"thin", "medium", "thick"};
private static final String[] ALIGN_KEYWORDS =
{"baseline", "sub", "super", "text-top", "text-bottom", "middle", "top", "bottom",
"inherit", "initial", "revert", "unset"};
// private static final Log LOG = LogFactory.getLog(CSSStyleDeclaration.class);
/** The wrapped CSSStyleDeclaration */
private AbstractCssStyleDeclaration styleDeclaration_;
/**
* Creates an instance.
*/
public CSSStyleDeclaration() {
}
/**
* JavaScript constructor.
*
* @param type the event type
* @param details the event details (optional)
*/
@JsxConstructor({CHROME, EDGE, FF, FF_ESR})
public void jsConstructor(final String type, final ScriptableObject details) {
throw JavaScriptEngine.typeError("CSSStyleDeclaration ctor is not available");
}
/**
* Creates an instance and sets its parent scope to the one of the provided element.
* @param element the element to which this style is bound
* @param styleDeclaration the style declaration to be based on
*/
public CSSStyleDeclaration(final Element element, final AbstractCssStyleDeclaration styleDeclaration) {
setParentScope(element.getParentScope());
setPrototype(getPrototype(getClass()));
setDomNode(element.getDomNodeOrNull(), false);
if (styleDeclaration == null) {
throw new IllegalStateException("styleDeclaration can't be null");
}
styleDeclaration_ = styleDeclaration;
}
/**
* Creates an instance which wraps the specified style declaration.
* @param parentStyleSheet the parent {@link CSSStyleSheet} to use
* @param styleDeclaration the style declaration to wrap
*/
CSSStyleDeclaration(final CSSStyleSheet parentStyleSheet, final WrappedCssStyleDeclaration styleDeclaration) {
setParentScope(parentStyleSheet);
setPrototype(getPrototype(getClass()));
if (styleDeclaration == null) {
throw new IllegalStateException("styleDeclaration can't be null");
}
styleDeclaration_ = styleDeclaration;
}
protected AbstractCssStyleDeclaration getCssStyleDeclaration() {
return styleDeclaration_;
}
/**
* IE makes unknown style properties accessible.
* @param name the name of the requested property
* @return the object value, {@link #NOT_FOUND} if nothing is found
*/
@Override
protected Object getWithPreemption(final String name) {
if (getBrowserVersion().hasFeature(JS_STYLE_UNSUPPORTED_PROPERTY_GETTER)
&& (styleDeclaration_ instanceof ElementCssStyleDeclaration
|| styleDeclaration_ instanceof ComputedCssStyleDeclaration)) {
final StyleElement element = styleDeclaration_.getStyleElement(name);
if (element != null && element.getValue() != null) {
return element.getValue();
}
}
return NOT_FOUND;
}
/**
* Returns the priority of the named style attribute, or an empty string if it is not found.
*
* @param name the name of the style attribute whose value is to be retrieved
* @return the named style attribute value, or an empty string if it is not found
*/
protected String getStylePriority(final String name) {
return styleDeclaration_.getStylePriority(name);
}
/**
* Determines the StyleElement for the given name.
* This ignores the case of the name.
*
* @param name the name of the requested StyleElement
* @return the StyleElement or null if not found
*/
private StyleElement getStyleElementCaseInSensitive(final String name) {
return styleDeclaration_.getStyleElementCaseInSensitive(name);
}
/**
* Sets the specified style attribute.
* @param name the attribute name (camel-cased)
* @param newValue the attribute value
*/
protected void setStyleAttribute(final String name, final String newValue) {
setStyleAttribute(name, newValue, "");
}
/**
* Sets the specified style attribute.
* @param name the attribute name (camel-cased)
* @param newValue the attribute value
* @param important important value
*/
protected void setStyleAttribute(final String name, String newValue, final String important) {
if (null == newValue || "null".equals(newValue)) {
newValue = "";
}
styleDeclaration_.setStyleAttribute(name, newValue, important);
}
/**
* Removes the specified style attribute, returning the value of the removed attribute.
* @param name the attribute name (delimiter-separated, not camel-cased)
*/
private String removeStyleAttribute(final String name) {
if (styleDeclaration_ == null) {
return null;
}
return styleDeclaration_.removeStyleAttribute(name);
}
/**
* Returns a sorted map containing style elements, keyed on style element name. We use a
* {@link LinkedHashMap} map so that results are deterministic and are thus testable.
*
* @return a sorted map containing style elements, keyed on style element name
*/
private Map getStyleMap() {
if (styleDeclaration_ == null) {
return Collections.emptyMap();
}
return styleDeclaration_.getStyleMap();
}
/**
* Gets the {@code accelerator} style attribute.
* @return the style attribute
*/
@JsxGetter(IE)
public String getAccelerator() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getAccelerator();
}
/**
* Sets the {@code accelerator} style attribute.
* @param accelerator the new attribute
*/
@JsxSetter(IE)
public void setAccelerator(final String accelerator) {
setStyleAttribute(Definition.ACCELERATOR.getAttributeName(), accelerator);
}
/**
* Gets the {@code backgroundAttachment} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBackgroundAttachment() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBackgroundAttachment();
}
/**
* Sets the {@code backgroundAttachment} style attribute.
* @param backgroundAttachment the new attribute
*/
@JsxSetter
public void setBackgroundAttachment(final String backgroundAttachment) {
setStyleAttribute(Definition.BACKGROUND_ATTACHMENT.getAttributeName(), backgroundAttachment);
}
/**
* Gets the {@code backgroundColor} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBackgroundColor() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBackgroundColor();
}
/**
* Sets the {@code backgroundColor} style attribute.
* @param backgroundColor the new attribute
*/
@JsxSetter
public void setBackgroundColor(final String backgroundColor) {
setStyleAttribute(Definition.BACKGROUND_COLOR.getAttributeName(), backgroundColor);
}
/**
* Gets the {@code backgroundImage} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBackgroundImage() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBackgroundImage();
}
/**
* Sets the {@code backgroundImage} style attribute.
* @param backgroundImage the new attribute
*/
@JsxSetter
public void setBackgroundImage(final String backgroundImage) {
setStyleAttribute(Definition.BACKGROUND_IMAGE.getAttributeName(), backgroundImage);
}
/**
* Gets the {@code backgroundPosition} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBackgroundPosition() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBackgroundPosition();
}
/**
* Sets the {@code backgroundPosition} style attribute.
* @param backgroundPosition the new attribute
*/
@JsxSetter
public void setBackgroundPosition(final String backgroundPosition) {
setStyleAttribute(Definition.BACKGROUND_POSITION.getAttributeName(), backgroundPosition);
}
/**
* Gets the {@code backgroundRepeat} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBackgroundRepeat() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBackgroundRepeat();
}
/**
* Sets the {@code backgroundRepeat} style attribute.
* @param backgroundRepeat the new attribute
*/
@JsxSetter
public void setBackgroundRepeat(final String backgroundRepeat) {
setStyleAttribute(Definition.BACKGROUND_REPEAT.getAttributeName(), backgroundRepeat);
}
/**
* Gets the {@code borderBottomColor} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderBottomColor() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderBottomColor();
}
/**
* Sets the {@code borderBottomColor} style attribute.
* @param borderBottomColor the new attribute
*/
@JsxSetter
public void setBorderBottomColor(final String borderBottomColor) {
setStyleAttribute(Definition.BORDER_BOTTOM_COLOR.getAttributeName(), borderBottomColor);
}
/**
* Gets the {@code borderBottomStyle} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderBottomStyle() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderBottomStyle();
}
/**
* Sets the {@code borderBottomStyle} style attribute.
* @param borderBottomStyle the new attribute
*/
@JsxSetter
public void setBorderBottomStyle(final String borderBottomStyle) {
setStyleAttribute(Definition.BORDER_BOTTOM_STYLE.getAttributeName(), borderBottomStyle);
}
/**
* Gets the {@code borderBottomWidth} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderBottomWidth() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderBottomWidth();
}
/**
* Sets the {@code borderBottomWidth} style attribute.
* @param borderBottomWidth the new attribute
*/
@JsxSetter
public void setBorderBottomWidth(final Object borderBottomWidth) {
setStyleLengthAttribute(Definition.BORDER_BOTTOM_WIDTH.getAttributeName(), borderBottomWidth, "",
false, false, false, null);
}
/**
* Gets the {@code borderLeftColor} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderLeftColor() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderLeftColor();
}
/**
* Sets the {@code borderLeftColor} style attribute.
* @param borderLeftColor the new attribute
*/
@JsxSetter
public void setBorderLeftColor(final String borderLeftColor) {
setStyleAttribute(Definition.BORDER_LEFT_COLOR.getAttributeName(), borderLeftColor);
}
/**
* Gets the {@code borderLeftStyle} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderLeftStyle() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderLeftStyle();
}
/**
* Sets the {@code borderLeftStyle} style attribute.
* @param borderLeftStyle the new attribute
*/
@JsxSetter
public void setBorderLeftStyle(final String borderLeftStyle) {
setStyleAttribute(Definition.BORDER_LEFT_STYLE.getAttributeName(), borderLeftStyle);
}
/**
* Gets the {@code borderLeftWidth} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderLeftWidth() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderLeftWidth();
}
/**
* Sets the {@code borderLeftWidth} style attribute.
* @param borderLeftWidth the new attribute
*/
@JsxSetter
public void setBorderLeftWidth(final Object borderLeftWidth) {
setStyleLengthAttribute(Definition.BORDER_LEFT_WIDTH.getAttributeName(), borderLeftWidth, "",
false, false, false, null);
}
/**
* Gets the {@code borderRightColor} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderRightColor() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderRightColor();
}
/**
* Sets the {@code borderRightColor} style attribute.
* @param borderRightColor the new attribute
*/
@JsxSetter
public void setBorderRightColor(final String borderRightColor) {
setStyleAttribute(Definition.BORDER_RIGHT_COLOR.getAttributeName(), borderRightColor);
}
/**
* Gets the {@code borderRightStyle} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderRightStyle() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderRightStyle();
}
/**
* Sets the {@code borderRightStyle} style attribute.
* @param borderRightStyle the new attribute
*/
@JsxSetter
public void setBorderRightStyle(final String borderRightStyle) {
setStyleAttribute(Definition.BORDER_RIGHT_STYLE.getAttributeName(), borderRightStyle);
}
/**
* Gets the {@code borderRightWidth} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderRightWidth() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderRightWidth();
}
/**
* Sets the {@code borderRightWidth} style attribute.
* @param borderRightWidth the new attribute
*/
@JsxSetter
public void setBorderRightWidth(final Object borderRightWidth) {
setStyleLengthAttribute(Definition.BORDER_RIGHT_WIDTH.getAttributeName(), borderRightWidth, "",
false, false, false, null);
}
/**
* Gets the {@code borderTop} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderTop() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderTop();
}
/**
* Sets the {@code borderTop} style attribute.
* @param borderTop the new attribute
*/
@JsxSetter
public void setBorderTop(final String borderTop) {
setStyleAttribute(Definition.BORDER_TOP.getAttributeName(), borderTop);
}
/**
* Gets the {@code borderTopColor} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderTopColor() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderTopColor();
}
/**
* Sets the {@code borderTopColor} style attribute.
* @param borderTopColor the new attribute
*/
@JsxSetter
public void setBorderTopColor(final String borderTopColor) {
setStyleAttribute(Definition.BORDER_TOP_COLOR.getAttributeName(), borderTopColor);
}
/**
* Gets the {@code borderTopStyle} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderTopStyle() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderTopStyle();
}
/**
* Sets the {@code borderTopStyle} style attribute.
* @param borderTopStyle the new attribute
*/
@JsxSetter
public void setBorderTopStyle(final String borderTopStyle) {
setStyleAttribute(Definition.BORDER_TOP_STYLE.getAttributeName(), borderTopStyle);
}
/**
* Gets the {@code borderTopWidth} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBorderTopWidth() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBorderTopWidth();
}
/**
* Sets the {@code borderTopWidth} style attribute.
* @param borderTopWidth the new attribute
*/
@JsxSetter
public void setBorderTopWidth(final Object borderTopWidth) {
setStyleLengthAttribute(Definition.BORDER_TOP_WIDTH.getAttributeName(), borderTopWidth, "",
false, false, false, null);
}
/**
* Gets the {@code bottom} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getBottom() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getBottom();
}
/**
* Sets the {@code bottom} style attribute.
* @param bottom the new attribute
*/
@JsxSetter
public void setBottom(final Object bottom) {
setStyleLengthAttribute(Definition.BOTTOM.getAttributeName(), bottom, "", true, true, false, null);
}
/**
* Gets the {@code color} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getColor() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getColor();
}
/**
* Sets the {@code color} style attribute.
* @param color the new attribute
*/
@JsxSetter
public void setColor(final String color) {
setStyleAttribute(Definition.COLOR.getAttributeName(), color);
}
/**
* Gets the {@code cssFloat} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getCssFloat() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getCssFloat();
}
/**
* Sets the {@code cssFloat} style attribute.
* @param value the new attribute
*/
@JsxSetter
public void setCssFloat(final String value) {
setStyleAttribute(Definition.FLOAT.getAttributeName(), value);
}
/**
* Returns the actual text of the style.
* @return the actual text of the style
*/
@JsxGetter
public String getCssText() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getCssText();
}
/**
* Sets the actual text of the style.
* @param value the new text
*/
@JsxSetter
public void setCssText(final String value) {
String fixedValue = value;
if (fixedValue == null || "null".equals(fixedValue)) {
fixedValue = "";
}
styleDeclaration_.setCssText(fixedValue);
}
/**
* Gets the {@code display} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getDisplay() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getDisplay();
}
/**
* Sets the {@code display} style attribute.
* @param display the new attribute
*/
@JsxSetter
public void setDisplay(final String display) {
setStyleAttribute(Definition.DISPLAY.getAttributeName(), display);
}
/**
* Gets the {@code fontSize} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getFontSize() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getFontSize();
}
/**
* Sets the {@code fontSize} style attribute.
* @param fontSize the new attribute
*/
@JsxSetter
public void setFontSize(final Object fontSize) {
setStyleLengthAttribute(Definition.FONT_SIZE.getAttributeName(), fontSize, "", false, true, false, null);
updateFont(getFont(), false);
}
/**
* Gets the {@code lineHeight} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getLineHeight() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getLineHeight();
}
/**
* Sets the {@code lineHeight} style attribute.
* @param lineHeight the new attribute
*/
@JsxSetter
public void setLineHeight(final String lineHeight) {
setStyleAttribute(Definition.LINE_HEIGHT.getAttributeName(), lineHeight);
updateFont(getFont(), false);
}
/**
* Gets the {@code fontFamily} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getFontFamily() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getFontFamily();
}
/**
* Sets the {@code fontFamily} style attribute.
* @param fontFamily the new attribute
*/
@JsxSetter
public void setFontFamily(final String fontFamily) {
setStyleAttribute(Definition.FONT_FAMILY.getAttributeName(), fontFamily);
updateFont(getFont(), false);
}
private void updateFont(final String font, final boolean force) {
final BrowserVersion browserVersion = getBrowserVersion();
final String[] details = ComputedFont.getDetails(font, browserVersion);
if (details != null || force) {
final StringBuilder newFont = new StringBuilder();
newFont.append(getFontSize());
String lineHeight = getLineHeight();
final String defaultLineHeight = Definition.LINE_HEIGHT.getDefaultComputedValue(browserVersion);
if (lineHeight.isEmpty()) {
lineHeight = defaultLineHeight;
}
if (browserVersion.hasFeature(CSS_ZINDEX_TYPE_INTEGER) || !lineHeight.equals(defaultLineHeight)) {
newFont.append('/');
if (lineHeight.equals(defaultLineHeight)) {
newFont.append(Definition.LINE_HEIGHT.getDefaultComputedValue(browserVersion));
}
else {
newFont.append(lineHeight);
}
}
newFont.append(' ').append(getFontFamily());
setStyleAttribute(Definition.FONT.getAttributeName(), newFont.toString());
}
}
/**
* Gets the {@code font} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getFont() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getFont();
}
/**
* Sets the {@code font} style attribute.
* @param font the new attribute
*/
@JsxSetter
public void setFont(final String font) {
final String[] details = ComputedFont.getDetails(font, getBrowserVersion());
if (details != null) {
setStyleAttribute(Definition.FONT_FAMILY.getAttributeName(), details[ComputedFont.FONT_FAMILY_INDEX]);
final String fontSize = details[ComputedFont.FONT_SIZE_INDEX];
if (details[ComputedFont.LINE_HEIGHT_INDEX] != null) {
setStyleAttribute(Definition.LINE_HEIGHT.getAttributeName(), details[ComputedFont.LINE_HEIGHT_INDEX]);
}
setStyleAttribute(Definition.FONT_SIZE.getAttributeName(), fontSize);
updateFont(font, true);
}
}
/**
* Gets the {@code height} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getHeight() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getHeight();
}
/**
* Sets the {@code height} style attribute.
* @param height the new attribute
*/
@JsxSetter
public void setHeight(final Object height) {
setStyleLengthAttribute(Definition.HEIGHT.getAttributeName(), height, "", true, true, false, null);
}
/**
* Gets the {@code left} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getLeft() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getLeft();
}
/**
* Sets the {@code left} style attribute.
* @param left the new attribute
*/
@JsxSetter
public void setLeft(final Object left) {
setStyleLengthAttribute(Definition.LEFT.getAttributeName(), left, "", true, true, false, null);
}
/**
* Returns the {@code length} property.
* @return the {@code length} property
*/
@JsxGetter
public int getLength() {
if (styleDeclaration_ == null) {
return 0; // prototype
}
return styleDeclaration_.getLength();
}
/**
* Returns the item in the given index.
* @param index the index
* @return the item in the given index
*/
@JsxFunction
public Object item(final int index) {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.item(index);
}
/**
* Returns an Iterator allowing to go through all keys contained in this object.
* @return an {@link NativeArrayIterator}
*/
@JsxSymbol(value = {CHROME, EDGE, FF, FF_ESR}, symbolName = "iterator")
public ES6Iterator values() {
return new NativeArrayIterator(getParentScope(), this, NativeArrayIterator.ARRAY_ITERATOR_TYPE.VALUES);
}
/**
* Gets the {@code letterSpacing} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getLetterSpacing() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getLetterSpacing();
}
/**
* Sets the {@code letterSpacing} style attribute.
* @param letterSpacing the new attribute
*/
@JsxSetter
public void setLetterSpacing(final Object letterSpacing) {
setStyleLengthAttribute(Definition.LETTER_SPACING.getAttributeName(), letterSpacing, "",
false, false, false, null);
}
/**
* Gets the {@code margin} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMargin() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMargin();
}
/**
* Sets the {@code margin} style attribute.
* @param margin the new attribute
*/
@JsxSetter
public void setMargin(final String margin) {
setStyleAttribute(Definition.MARGIN.getAttributeName(), margin);
}
/**
* Gets the {@code marginBottom} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMarginBottom() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMarginBottom();
}
/**
* Sets the {@code marginBottom} style attribute.
* @param marginBottom the new attribute
*/
@JsxSetter
public void setMarginBottom(final Object marginBottom) {
setStyleLengthAttribute(Definition.MARGIN_BOTTOM.getAttributeName(), marginBottom, "", true, true, false, null);
}
/**
* Gets the {@code marginLeft} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMarginLeft() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMarginLeft();
}
/**
* Sets the {@code marginLeft} style attribute.
* @param marginLeft the new attribute
*/
@JsxSetter
public void setMarginLeft(final Object marginLeft) {
setStyleLengthAttribute(Definition.MARGIN_LEFT.getAttributeName(), marginLeft, "", true, true, false, null);
}
/**
* Gets the {@code marginRight} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMarginRight() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMarginRight();
}
/**
* Sets the {@code marginRight} style attribute.
* @param marginRight the new attribute
*/
@JsxSetter
public void setMarginRight(final Object marginRight) {
setStyleLengthAttribute(Definition.MARGIN_RIGHT.getAttributeName(), marginRight, "", true, true, false, null);
}
/**
* Gets the {@code marginTop} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMarginTop() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMarginTop();
}
/**
* Sets the {@code marginTop} style attribute.
* @param marginTop the new attribute
*/
@JsxSetter
public void setMarginTop(final Object marginTop) {
setStyleLengthAttribute(Definition.MARGIN_TOP.getAttributeName(), marginTop, "", true, true, false, null);
}
/**
* Gets the {@code maxHeight} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMaxHeight() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMaxHeight();
}
/**
* Sets the {@code maxHeight} style attribute.
* @param maxHeight the new attribute
*/
@JsxSetter
public void setMaxHeight(final Object maxHeight) {
setStyleLengthAttribute(Definition.MAX_HEIGHT.getAttributeName(), maxHeight, "", false, true, false, null);
}
/**
* Gets the {@code maxWidth} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMaxWidth() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMaxWidth();
}
/**
* Sets the {@code maxWidth} style attribute.
* @param maxWidth the new attribute
*/
@JsxSetter
public void setMaxWidth(final Object maxWidth) {
setStyleLengthAttribute(Definition.MAX_WIDTH.getAttributeName(), maxWidth, "", false, true, false, null);
}
/**
* Gets the {@code minHeight} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMinHeight() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMinHeight();
}
/**
* Sets the {@code minHeight} style attribute.
* @param minHeight the new attribute
*/
@JsxSetter
public void setMinHeight(final Object minHeight) {
setStyleLengthAttribute(Definition.MIN_HEIGHT.getAttributeName(), minHeight, "", true, true, false, null);
}
/**
* Gets the {@code minWidth} style attribute.
* @return the style attribute
*/
@JsxGetter
public String getMinWidth() {
if (styleDeclaration_ == null) {
return null; // prototype
}
return styleDeclaration_.getMinWidth();
}
/**
* Sets the {@code minWidth} style attribute.
* @param minWidth the new attribute
*/
@JsxSetter
public void setMinWidth(final Object minWidth) {
setStyleLengthAttribute(Definition.MIN_WIDTH.getAttributeName(), minWidth, "", true, true, false, null);
}
/**
* {@inheritDoc}
*/
@Override
public Object get(final String name, final Scriptable start) {
if (this != start) {
return super.get(name, start);
}
Scriptable prototype = getPrototype();
while (prototype != null) {
Object value = prototype.get(name, start);
if (value != Scriptable.NOT_FOUND) {
return value;
}
final String camel = org.htmlunit.util.StringUtils.cssCamelize(name);
if (!name.equals(camel)) {
value = prototype.get(camel, start);
if (value != Scriptable.NOT_FOUND) {
return value;
}
}
prototype = prototype.getPrototype();
}
final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
if (style != null) {
return getStyleAttribute(style);
}
return super.get(name, start);
}
@Override
public Object get(final int index, final Scriptable start) {
if (index < 0) {
return Undefined.instance;
}
final Map style = getStyleMap();
final int size = style.size();
if (index >= size) {
if (getBrowserVersion().hasFeature(JS_STYLE_WRONG_INDEX_RETURNS_UNDEFINED)) {
return Undefined.instance;
}
return "";
}
return style.keySet().toArray(new String[size])[index];
}
/**
* Get the value for the style attribute.
* @param definition the definition
* @return the value
*/
public final String getStyleAttribute(final Definition definition) {
return getStyleAttribute(definition, true);
}
/**
* Get the value for the style attribute.
* This impl ignores the default getDefaultValueIfEmpty flag, but there is a overload
* in {@link ComputedCSSStyleDeclaration}.
* @param definition the definition
* @param getDefaultValueIfEmpty whether to get the default value if empty or not
* @return the value
*/
public String getStyleAttribute(final Definition definition, final boolean getDefaultValueIfEmpty) {
if (styleDeclaration_ == null) {
return ""; // prototype
}
return styleDeclaration_.getStyleAttribute(definition, getDefaultValueIfEmpty);
}
@Override
public void put(final String name, final Scriptable start, final Object value) {
if (this != start) {
super.put(name, start, value);
return;
}
final Scriptable prototype = getPrototype();
if (prototype != null && !"constructor".equals(name)) {
if (prototype.get(name, start) != Scriptable.NOT_FOUND) {
prototype.put(name, start, value);
return;
}
final String camel = org.htmlunit.util.StringUtils.cssCamelize(name);
if (!name.equals(camel) && prototype.get(camel, start) != Scriptable.NOT_FOUND) {
prototype.put(camel, start, value);
return;
}
}
if (getDomNodeOrNull() != null) { // check if prototype or not
final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
if (style != null) {
final String stringValue = JavaScriptEngine.toString(value);
setStyleAttribute(style.getAttributeName(), stringValue);
return;
}
}
super.put(name, start, value);
}
@Override
public boolean has(final String name, final Scriptable start) {
if (this != start) {
return super.has(name, start);
}
final BrowserVersion browserVersion = getBrowserVersion();
if (browserVersion != null) {
final Definition style = StyleAttributes.getDefinition(name, getBrowserVersion());
if (style != null) {
return true;
}
}
return super.has(name, start);
}
@Override
public Object[] getIds() {
final List