/*
GNU LESSER GENERAL PUBLIC LICENSE
Copyright (C) 2006 The Lobo Project
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Contact info: lobochief@users.sourceforge.net
*/
/*
* Created on Apr 16, 2005
*/
package org.lobobrowser.html.style;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Toolkit;
import java.awt.font.GlyphVector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringTokenizer;
import org.lobobrowser.html.domimpl.HTMLDocumentImpl;
import org.lobobrowser.html.domimpl.HTMLElementImpl;
import org.lobobrowser.html.renderer.LineBreak;
import org.lobobrowser.util.gui.ColorFactory;
import org.lobobrowser.util.gui.FontFactory;
import org.w3c.dom.css.CSS2Properties;
import org.w3c.dom.html.HTMLElement;
import cz.vutbr.web.css.CSSProperty;
/**
* @author J. H. S.
*/
public class StyleSheetRenderState implements RenderState {
private static final FontFactory FONT_FACTORY = FontFactory.getInstance();
// Default font needs to be something that displays in all languages.
// Serif, SansSerif, Monospaced.
private static final String DEFAULT_FONT_FAMILY = "SansSerif";
private static final Font DEFAULT_FONT = FONT_FACTORY.getFont(DEFAULT_FONT_FAMILY, null, null, null, HtmlValues.DEFAULT_FONT_SIZE, null,
null);
protected static final HtmlInsets INVALID_INSETS = new HtmlInsets();
protected static final BackgroundInfo INVALID_BACKGROUND_INFO = new BackgroundInfo();
protected static final BorderInfo INVALID_BORDER_INFO = new BorderInfo();
protected static final Color INVALID_COLOR = new Color(100, 0, 100);
protected final HTMLElementImpl element;
protected final HTMLDocumentImpl document;
protected final RenderState prevRenderState;
private Font iFont;
private FontMetrics iFontMetrics;
private Color iColor;
private Color iBackgroundColor = INVALID_COLOR;
private Color iTextBackgroundColor = INVALID_COLOR;
private Color iOverlayColor = INVALID_COLOR;
private int iTextDecoration = -1;
private int iTextTransform = -1;
private int iBlankWidth = -1;
private boolean iHighlight;
protected BackgroundInfo iBackgroundInfo = INVALID_BACKGROUND_INFO;
public StyleSheetRenderState(final RenderState prevRenderState, final HTMLElementImpl element) {
this.prevRenderState = prevRenderState;
this.element = element;
this.document = (HTMLDocumentImpl) element.getOwnerDocument();
}
public StyleSheetRenderState(final HTMLDocumentImpl document) {
this.prevRenderState = null;
this.element = null;
this.document = document;
}
// public TextRenderState(RenderState prevRenderState) {
// this.css2properties = new CSS2PropertiesImpl(this);
// this.prevRenderState = prevRenderState;
// }
protected int getDefaultDisplay() {
return DISPLAY_INLINE;
}
private Integer iDisplay;
public int getDisplay() {
final Integer d = this.iDisplay;
if (d != null) {
return d.intValue();
}
final CSS2Properties props = this.getCssProperties();
final String displayText = props == null ? null : props.getDisplay();
int displayInt;
if (displayText != null) {
final String displayTextTL = displayText.toLowerCase();
if ("block".equals(displayTextTL)) {
displayInt = DISPLAY_BLOCK;
} else if ("inline".equals(displayTextTL)) {
displayInt = DISPLAY_INLINE;
} else if ("none".equals(displayTextTL)) {
displayInt = DISPLAY_NONE;
} else if ("list-item".equals(displayTextTL)) {
displayInt = DISPLAY_LIST_ITEM;
} else if ("table-row-group".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE_ROW_GROUP;
} else if ("table-header-group".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE_HEADER_GROUP;
} else if ("table-footer-group".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE_FOOTER_GROUP;
} else if ("table".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE;
} else if ("inline-table".equals(displayTextTL)) {
displayInt = DISPLAY_INLINE_TABLE;
} else if ("table-cell".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE_CELL;
} else if ("table-row".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE_ROW;
} else if ("inline-block".equals(displayTextTL)) {
displayInt = DISPLAY_INLINE_BLOCK;
} else if ("table-column".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE_COLUMN;
} else if ("table-column-group".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE_COLUMN_GROUP;
} else if ("table-caption".equals(displayTextTL)) {
displayInt = DISPLAY_TABLE_CAPTION;
} else {
displayInt = this.getDefaultDisplay();
}
} else {
displayInt = this.getDefaultDisplay();
}
this.iDisplay = new Integer(displayInt);
return displayInt;
}
public int getFontBase() {
return 3;
}
public void repaint() {
// Dummy implementation
}
protected final JStyleProperties getCssProperties() {
final HTMLElementImpl element = this.element;
return element == null ? null : element.getCurrentStyle();
}
public void invalidate() {
final Map<String, WordInfo> map = this.iWordInfoMap;
if (map != null) {
map.clear();
}
this.iFont = null;
this.iFontMetrics = null;
this.iColor = null;
this.iTextDecoration = -1;
this.iBlankWidth = -1;
this.alignXPercent = -1;
this.iBackgroundColor = INVALID_COLOR;
this.iTextBackgroundColor = INVALID_COLOR;
this.iOverlayColor = INVALID_COLOR;
this.iBackgroundInfo = INVALID_BACKGROUND_INFO;
this.iDisplay = null;
this.iTextIndentText = null;
this.iWhiteSpace = null;
this.marginInsets = INVALID_INSETS;
this.paddingInsets = INVALID_INSETS;
this.overflowX = -1;
this.overflowY = -1;
this.borderInfo = INVALID_BORDER_INFO;
// Should NOT invalidate parent render state.
}
public Font getFont() {
Font f = this.iFont;
if (f != null) {
return f;
}
final JStyleProperties style = this.getCssProperties();
final RenderState prs = this.prevRenderState;
if (style == null) {
if (prs != null) {
final Font font = prs.getFont();
return font;
}
f = DEFAULT_FONT;
this.iFont = f;
return f;
}
Float fontSize = null;
String fontStyle = null;
String fontVariant = null;
String fontWeight = null;
String fontFamily = null;
final String newFontSize = style.getFontSize();
final String newFontFamily = style.getFontFamily();
final String newFontStyle = style.getFontStyle();
final String newFontVariant = style.getFontVariant();
final String newFontWeight = style.getFontWeight();
final String verticalAlign = style.getVerticalAlign();
final boolean isSuper = (verticalAlign != null) && verticalAlign.equalsIgnoreCase("super");
final boolean isSub = (verticalAlign != null) && verticalAlign.equalsIgnoreCase("sub");
if ((newFontSize == null) && (newFontWeight == null) && (newFontStyle == null) && (newFontFamily == null) && (newFontVariant == null)) {
if (!isSuper && !isSub) {
if (prs != null) {
return prs.getFont();
} else {
f = DEFAULT_FONT;
this.iFont = f;
return f;
}
}
}
if (newFontSize != null) {
try {
fontSize = new Float(HtmlValues.getFontSize(newFontSize, prs));
} catch (final Exception err) {
fontSize = HtmlValues.DEFAULT_FONT_SIZE_BOX;
}
} else {
if (prs != null) {
fontSize = new Float(prs.getFont().getSize());
} else {
fontSize = HtmlValues.DEFAULT_FONT_SIZE_BOX;
}
}
if (newFontFamily != null) {
fontFamily = newFontFamily;
}
if (fontFamily == null) {
fontFamily = DEFAULT_FONT_FAMILY;
}
if (newFontStyle != null) {
fontStyle = newFontStyle;
}
if (newFontVariant != null) {
fontVariant = newFontVariant;
}
if (newFontWeight != null) {
fontWeight = newFontWeight;
}
final HTMLDocumentImpl document = this.document;
final Set<Locale> locales = document == null ? null : document.getLocales();
Integer superscript = null;
if (isSuper) {
superscript = new Integer(1);
} else if (isSub) {
superscript = new Integer(-1);
}
f = FONT_FACTORY.getFont(fontFamily, fontStyle, fontVariant, fontWeight, fontSize.floatValue(), locales, superscript);
this.iFont = f;
return f;
}
public Color getColor() {
Color c = this.iColor;
if (c != null) {
return c;
}
final JStyleProperties props = this.getCssProperties();
String colorValue = props == null ? null : props.getColor();
if ((colorValue == null) || "".equals(colorValue)) {
colorValue = "black";
}
c = ColorFactory.getInstance().getColor(colorValue);
this.iColor = c;
return c;
}
public Color getBackgroundColor() {
final Color c = this.iBackgroundColor;
if (c != INVALID_COLOR) {
return c;
}
Color localColor;
final BackgroundInfo binfo = this.getBackgroundInfo();
localColor = binfo == null ? null : binfo.backgroundColor;
this.iBackgroundColor = localColor;
return localColor;
}
public Color getTextBackgroundColor() {
final Color c = this.iTextBackgroundColor;
if (c != INVALID_COLOR) {
return c;
}
Color localColor;
if (this.getDisplay() != DISPLAY_INLINE) {
// Background painted by block.
localColor = null;
} else {
final BackgroundInfo binfo = this.getBackgroundInfo();
localColor = binfo == null ? null : binfo.backgroundColor;
}
this.iTextBackgroundColor = localColor;
return localColor;
}
public Color getOverlayColor() {
Color c = this.iOverlayColor;
if (c != INVALID_COLOR) {
return c;
}
final JStyleProperties props = this.getCssProperties();
String colorValue = props == null ? null : props.getOverlayColor();
if ((colorValue == null) || (colorValue.length() == 0)) {
colorValue = null;
}
c = colorValue == null ? null : ColorFactory.getInstance().getColor(colorValue);
this.iOverlayColor = c;
return c;
}
public int getTextDecorationMask() {
int td = this.iTextDecoration;
if (td != -1) {
return td;
}
final JStyleProperties props = this.getCssProperties();
final String tdText = props == null ? null : props.getTextDecoration();
td = 0;
if (tdText != null) {
final StringTokenizer tok = new StringTokenizer(tdText.toLowerCase(), ", \t\n\r");
while (tok.hasMoreTokens()) {
final String token = tok.nextToken();
if ("none".equals(token)) {
// continue
} else if ("underline".equals(token)) {
td |= RenderState.MASK_TEXTDECORATION_UNDERLINE;
} else if ("line-through".equals(token)) {
td |= RenderState.MASK_TEXTDECORATION_LINE_THROUGH;
} else if ("blink".equals(token)) {
td |= RenderState.MASK_TEXTDECORATION_BLINK;
} else if ("overline".equals(token)) {
td |= RenderState.MASK_TEXTDECORATION_OVERLINE;
}
}
}
this.iTextDecoration = td;
return td;
}
public int getTextTransform() {
int tt = this.iTextTransform;
if (tt != -1) {
return tt;
}
final JStyleProperties props = this.getCssProperties();
final String tdText = props == null ? null : props.getTextTransform();
tt = 0;
if (tdText != null) {
if ("none".equals(tdText)) {
// continue
} else if ("capitalize".equals(tdText)) {
tt = TEXTTRANSFORM_CAPITALIZE;
} else if ("uppercase".equals(tdText)) {
tt = TEXTTRANSFORM_UPPERCASE;
} else if ("lowercase".equals(tdText)) {
tt = TEXTTRANSFORM_LOWERCASE;
}
// TODO how the explicit "inherit" value is to be handled?
// Who is responsible for CSS cascading?
// ... painting code? prevRenderState?
//
// else if("inherit".equals(tdText)) {
// tt = TEXTTRANSFORM_INHERIT;
// }
}
this.iTextTransform = tt;
return tt;
}
public final FontMetrics getFontMetrics() {
FontMetrics fm = this.iFontMetrics;
if (fm == null) {
// TODO getFontMetrics deprecated. How to get text width?
fm = Toolkit.getDefaultToolkit().getFontMetrics(this.getFont());
this.iFontMetrics = fm;
}
return fm;
}
public int getBlankWidth() {
int bw = this.iBlankWidth;
if (bw == -1) {
bw = this.getFontMetrics().charWidth(' ');
this.iBlankWidth = bw;
}
return bw;
}
/**
* @return Returns the iHighlight.
*/
public boolean isHighlight() {
return this.iHighlight;
}
/**
* @param highlight
* The iHighlight to set.
*/
public void setHighlight(final boolean highlight) {
this.iHighlight = highlight;
}
Map<String, WordInfo> iWordInfoMap = null;
public final WordInfo getWordInfo(final String word) {
// Expected to be called only in the GUI (rendering) thread.
// No synchronization necessary.
Map<String, WordInfo> map = this.iWordInfoMap;
if (map == null) {
map = new HashMap<>(1);
this.iWordInfoMap = map;
}
WordInfo wi = map.get(word);
if (wi != null) {
return wi;
}
wi = new WordInfo();
final FontMetrics fm = this.getFontMetrics();
wi.fontMetrics = fm;
wi.ascentPlusLeading = fm.getAscent() + fm.getLeading();
wi.descent = fm.getDescent();
wi.height = fm.getHeight();
wi.width = fm.stringWidth(word);
map.put(word, wi);
return wi;
}
private int alignXPercent = -1;
public int getAlignXPercent() {
int axp = this.alignXPercent;
if (axp != -1) {
return axp;
}
final CSS2Properties props = this.getCssProperties();
String textAlign = props == null ? null : props.getTextAlign();
if ((textAlign == null) || (textAlign.length() == 0)) {
// Fall back to align attribute.
final HTMLElement element = this.element;
if (element != null) {
textAlign = element.getAttribute("align");
if ((textAlign == null) || (textAlign.length() == 0)) {
textAlign = null;
}
}
}
if (textAlign == null) {
axp = 0;
} else if ("center".equalsIgnoreCase(textAlign)) {
axp = 50;
} else if ("right".equalsIgnoreCase(textAlign)) {
axp = 100;
} else {
// TODO: justify, <string>
axp = 0;
}
this.alignXPercent = axp;
return axp;
}
public int getAlignYPercent() {
// This is only settable in table cells.
// TODO: Does it work with display: table-cell?
return 0;
}
private Map<String, ArrayList<Integer>> counters = null;
public int getCount(final String counter, final int nesting) {
// Expected to be called only in GUI thread.
final RenderState prs = this.prevRenderState;
if (prs != null) {
return prs.getCount(counter, nesting);
}
final Map<String, ArrayList<Integer>> counters = this.counters;
if (counters == null) {
return 0;
}
final ArrayList<Integer> counterArray = counters.get(counter);
if ((nesting < 0) || (nesting >= counterArray.size())) {
return 0;
}
final Integer integer = counterArray.get(nesting);
return integer == null ? 0 : integer.intValue();
}
public void resetCount(final String counter, final int nesting, final int value) {
// Expected to be called only in the GUI thread.
final RenderState prs = this.prevRenderState;
if (prs != null) {
prs.resetCount(counter, nesting, value);
} else {
Map<String, ArrayList<Integer>> counters = this.counters;
if (counters == null) {
counters = new HashMap<>(2);
this.counters = counters;
counters.put(counter, new ArrayList<Integer>(0));
}
final ArrayList<Integer> counterArray = counters.get(counter);
while (counterArray.size() <= nesting) {
counterArray.add(null);
}
counterArray.set(nesting, new Integer(value));
}
}
public int incrementCount(final String counter, final int nesting) {
// Expected to be called only in the GUI thread.
final RenderState prs = this.prevRenderState;
if (prs != null) {
return prs.incrementCount(counter, nesting);
}
Map<String, ArrayList<Integer>> counters = this.counters;
if (counters == null) {
counters = new HashMap<>(2);
this.counters = counters;
counters.put(counter, new ArrayList<Integer>(0));
}
final ArrayList<Integer> counterArray = counters.get(counter);
while (counterArray.size() <= nesting) {
counterArray.add(null);
}
final Integer integer = counterArray.get(nesting);
final int prevValue = integer == null ? 0 : integer.intValue();
counterArray.set(nesting, new Integer(prevValue + 1));
return prevValue;
}
public BackgroundInfo getBackgroundInfo() {
{
final BackgroundInfo binfo = this.iBackgroundInfo;
if (binfo != INVALID_BACKGROUND_INFO) {
return binfo;
}
}
BackgroundInfo binfo = null;
final JStyleProperties props = this.getCssProperties();
if (props != null) {
final String backgroundColorText = props.getBackgroundColor();
if (backgroundColorText != null) {
binfo = new BackgroundInfo();
binfo.backgroundColor = ColorFactory.getInstance().getColor(backgroundColorText);
}
final String backgroundImageText = props.getBackgroundImage();
if ((backgroundImageText != null) && (backgroundImageText.length() > 0)) {
final java.net.URL backgroundImage = HtmlValues.getURIFromStyleValue(backgroundImageText);
if (backgroundImage != null) {
if (binfo == null) {
binfo = new BackgroundInfo();
}
binfo.backgroundImage = backgroundImage;
}
}
final String backgroundRepeatText = props.getBackgroundRepeat();
if (backgroundRepeatText != null) {
if (binfo == null) {
binfo = new BackgroundInfo();
}
applyBackgroundRepeat(binfo, backgroundRepeatText);
}
final String backgroundPositionText = props.getBackgroundPosition();
if (backgroundPositionText != null) {
if (binfo == null) {
binfo = new BackgroundInfo();
}
this.applyBackgroundPosition(binfo, backgroundPositionText);
}
}
this.iBackgroundInfo = binfo;
return binfo;
}
private String iTextIndentText = null;
public String getTextIndentText() {
String tiText = this.iTextIndentText;
if (tiText != null) {
return tiText;
}
final JStyleProperties props = this.getCssProperties();
tiText = props == null ? null : props.getTextIndent();
if (tiText == null) {
tiText = "";
}
return tiText;
}
public int getTextIndent(final int availSize) {
// No caching for this one.
final String tiText = this.getTextIndentText();
if (tiText.length() == 0) {
return 0;
} else {
return HtmlValues.getPixelSize(tiText, this, 0, availSize);
}
}
protected Integer iWhiteSpace;
public int getWhiteSpace() {
if (RenderThreadState.getState().overrideNoWrap) {
return WS_NOWRAP;
}
final Integer ws = this.iWhiteSpace;
if (ws != null) {
return ws.intValue();
}
final JStyleProperties props = this.getCssProperties();
final String whiteSpaceText = props == null ? null : props.getWhiteSpace();
int wsValue;
if (whiteSpaceText == null) {
wsValue = WS_NORMAL;
} else {
final String whiteSpaceTextTL = whiteSpaceText.toLowerCase();
if ("nowrap".equals(whiteSpaceTextTL)) {
wsValue = WS_NOWRAP;
} else if ("pre".equals(whiteSpaceTextTL)) {
wsValue = WS_PRE;
} else {
wsValue = WS_NORMAL;
}
}
this.iWhiteSpace = new Integer(wsValue);
return wsValue;
}
protected HtmlInsets marginInsets = INVALID_INSETS;
protected HtmlInsets paddingInsets = INVALID_INSETS;
public HtmlInsets getMarginInsets() {
HtmlInsets mi = this.marginInsets;
if (mi != INVALID_INSETS) {
return mi;
}
final JStyleProperties props = this.getCssProperties();
if (props == null) {
mi = null;
} else {
mi = HtmlValues.getMarginInsets(props, this);
}
this.marginInsets = mi;
return mi;
}
public HtmlInsets getPaddingInsets() {
HtmlInsets mi = this.paddingInsets;
if (mi != INVALID_INSETS) {
return mi;
}
final JStyleProperties props = this.getCssProperties();
if (props == null) {
mi = null;
} else {
mi = HtmlValues.getPaddingInsets(props, this);
this.paddingInsets = mi;
}
return mi;
}
private void applyBackgroundHorizontalPositon(final BackgroundInfo binfo, final String xposition) {
if (xposition.endsWith("%")) {
binfo.backgroundXPositionAbsolute = false;
try {
binfo.backgroundXPosition = (int) Double.parseDouble(xposition.substring(0, xposition.length() - 1).trim());
} catch (final NumberFormatException nfe) {
binfo.backgroundXPosition = 0;
}
} else if ("center".equalsIgnoreCase(xposition)) {
binfo.backgroundXPositionAbsolute = false;
binfo.backgroundXPosition = 50;
} else if ("right".equalsIgnoreCase(xposition)) {
binfo.backgroundXPositionAbsolute = false;
binfo.backgroundXPosition = 100;
} else if ("left".equalsIgnoreCase(xposition)) {
binfo.backgroundXPositionAbsolute = false;
binfo.backgroundXPosition = 0;
} else if ("bottom".equalsIgnoreCase(xposition)) {
// Can happen
binfo.backgroundYPositionAbsolute = false;
binfo.backgroundYPosition = 100;
} else if ("top".equalsIgnoreCase(xposition)) {
// Can happen
binfo.backgroundYPositionAbsolute = false;
binfo.backgroundYPosition = 0;
} else {
binfo.backgroundXPositionAbsolute = true;
binfo.backgroundXPosition = HtmlValues.getPixelSize(xposition, this, 0);
}
}
private void applyBackgroundVerticalPosition(final BackgroundInfo binfo, final String yposition) {
if (yposition.endsWith("%")) {
binfo.backgroundYPositionAbsolute = false;
try {
binfo.backgroundYPosition = (int) Double.parseDouble(yposition.substring(0, yposition.length() - 1).trim());
} catch (final NumberFormatException nfe) {
binfo.backgroundYPosition = 0;
}
} else if ("center".equalsIgnoreCase(yposition)) {
binfo.backgroundYPositionAbsolute = false;
binfo.backgroundYPosition = 50;
} else if ("bottom".equalsIgnoreCase(yposition)) {
binfo.backgroundYPositionAbsolute = false;
binfo.backgroundYPosition = 100;
} else if ("top".equalsIgnoreCase(yposition)) {
binfo.backgroundYPositionAbsolute = false;
binfo.backgroundYPosition = 0;
} else if ("right".equalsIgnoreCase(yposition)) {
// Can happen
binfo.backgroundXPositionAbsolute = false;
binfo.backgroundXPosition = 100;
} else if ("left".equalsIgnoreCase(yposition)) {
// Can happen
binfo.backgroundXPositionAbsolute = false;
binfo.backgroundXPosition = 0;
} else {
binfo.backgroundYPositionAbsolute = true;
binfo.backgroundYPosition = HtmlValues.getPixelSize(yposition, this, 0);
}
}
private void applyBackgroundPosition(final BackgroundInfo binfo, final String position) {
binfo.backgroundXPositionAbsolute = false;
binfo.backgroundYPositionAbsolute = false;
binfo.backgroundXPosition = 50;
binfo.backgroundYPosition = 50;
final StringTokenizer tok = new StringTokenizer(position, " \t\r\n");
if (tok.hasMoreTokens()) {
final String xposition = tok.nextToken();
this.applyBackgroundHorizontalPositon(binfo, xposition);
if (tok.hasMoreTokens()) {
final String yposition = tok.nextToken();
this.applyBackgroundVerticalPosition(binfo, yposition);
}
}
}
// private void applyBackground(BackgroundInfo binfo, String background,
// CSSStyleDeclaration declaration) {
// String[] tokens = HtmlValues.splitCssValue(background);
// boolean hasXPosition = false;
// for(int i = 0; i < tokens.length; i++) {
// String token = tokens[i];
// if(ColorFactory.getInstance().isColor(token)) {
// binfo.backgroundColor = ColorFactory.getInstance().getColor(token);
// }
// else if(HtmlValues.isUrl(token)) {
// binfo.backgroundImage = HtmlValues.getURIFromStyleValue(token, declaration,
// this.document);
// }
// else if(isBackgroundRepeat(token)) {
// this.applyBackgroundRepeat(binfo, token);
// }
// else if(isBackgroundPosition(token)) {
// if(hasXPosition) {
// this.applyBackgroundVerticalPosition(binfo, token);
// }
// else {
// hasXPosition = true;
// this.applyBackgroundHorizontalPositon(binfo, token);
// }
// }
// }
// }
private static void applyBackgroundRepeat(final BackgroundInfo binfo, final String backgroundRepeatText) {
final String brtl = backgroundRepeatText.toLowerCase();
if ("repeat".equals(brtl)) {
binfo.backgroundRepeat = BackgroundInfo.BR_REPEAT;
} else if ("repeat-x".equals(brtl)) {
binfo.backgroundRepeat = BackgroundInfo.BR_REPEAT_X;
} else if ("repeat-y".equals(brtl)) {
binfo.backgroundRepeat = BackgroundInfo.BR_REPEAT_Y;
} else if ("no-repeat".equals(brtl)) {
binfo.backgroundRepeat = BackgroundInfo.BR_NO_REPEAT;
}
}
private Integer cachedVisibility;
public int getVisibility() {
final Integer v = this.cachedVisibility;
if (v != null) {
return v.intValue();
}
final JStyleProperties props = this.getCssProperties();
int visibility;
if (props == null) {
visibility = VISIBILITY_VISIBLE;
} else {
final String visibText = props.getVisibility();
if ((visibText == null) || (visibText.length() == 0)) {
visibility = VISIBILITY_VISIBLE;
} else {
final String visibTextTL = visibText.toLowerCase();
if (visibTextTL.equals("hidden")) {
visibility = VISIBILITY_HIDDEN;
} else if (visibTextTL.equals("visible")) {
visibility = VISIBILITY_VISIBLE;
} else if (visibTextTL.equals("collapse")) {
visibility = VISIBILITY_COLLAPSE;
} else {
visibility = VISIBILITY_VISIBLE;
}
}
}
this.cachedVisibility = new Integer(visibility);
return visibility;
}
private Integer cachedPosition;
public int getPosition() {
final Integer p = this.cachedPosition;
if (p != null) {
return p.intValue();
}
final JStyleProperties props = this.getCssProperties();
int position;
if (props == null) {
position = POSITION_STATIC;
} else {
final String positionText = props.getPosition();
if ((positionText == null) || (positionText.length() == 0)) {
position = POSITION_STATIC;
} else {
final String positionTextTL = positionText.toLowerCase();
if (positionTextTL.equals("absolute")) {
position = POSITION_ABSOLUTE;
} else if (positionTextTL.equals("static")) {
position = POSITION_STATIC;
} else if (positionTextTL.equals("relative")) {
position = POSITION_RELATIVE;
} else if (positionTextTL.equals("fixed")) {
position = POSITION_FIXED;
} else {
position = POSITION_STATIC;
}
}
}
this.cachedPosition = new Integer(position);
return position;
}
private Integer cachedFloat;
public int getFloat() {
final Integer p = this.cachedFloat;
if (p != null) {
return p.intValue();
}
final JStyleProperties props = this.getCssProperties();
int floatValue;
if (props == null) {
floatValue = FLOAT_NONE;
} else {
final String floatText = props.getFloat();
if ((floatText == null) || (floatText.length() == 0)) {
floatValue = FLOAT_NONE;
} else {
final String floatTextTL = floatText.toLowerCase();
if (floatTextTL.equals("left")) {
floatValue = FLOAT_LEFT;
} else if (floatTextTL.equals("right")) {
floatValue = FLOAT_RIGHT;
} else {
floatValue = FLOAT_NONE;
}
}
}
this.cachedFloat = new Integer(floatValue);
return floatValue;
}
private Integer cachedClear = null;
public int getClear() {
if (cachedClear == null) {
final JStyleProperties props = this.getCssProperties();
if (props == null) {
cachedClear = new Integer(LineBreak.NONE);
} else {
final String clearStr = getCssProperties().getClear();
if ("both".equals(clearStr)) {
cachedClear = new Integer(LineBreak.ALL);
} else if ("left".equals(clearStr)) {
cachedClear = new Integer(LineBreak.LEFT);
} else if ("right".equals(clearStr)) {
cachedClear = new Integer(LineBreak.RIGHT);
} else {
cachedClear = new Integer(LineBreak.NONE);
}
}
}
return cachedClear;
}
@Override
public String toString() {
return "StyleSheetRenderState[font=" + this.getFont() + ",textDecoration=" + this.getTextDecorationMask() + "]";
}
protected int overflowX = -1;
protected int overflowY = -1;
public int getOverflowX() {
int overflow = this.overflowX;
if (overflow != -1) {
return overflow;
}
final JStyleProperties props = this.getCssProperties();
if (props == null) {
overflow = OVERFLOW_NONE;
} else {
// TODO need to implement specific method for this instead of using getPropertyValue.
String overflowText = props.getPropertyValue("overflow-x");
if (overflowText == null) {
overflowText = props.getOverflow();
}
if (overflowText == null) {
overflow = OVERFLOW_NONE;
} else {
final String overflowTextTL = overflowText.toLowerCase();
if ("scroll".equals(overflowTextTL)) {
overflow = OVERFLOW_SCROLL;
} else if ("auto".equals(overflowTextTL)) {
overflow = OVERFLOW_AUTO;
} else if ("hidden".equals(overflowTextTL)) {
overflow = OVERFLOW_HIDDEN;
} else if ("visible".equals(overflowTextTL)) {
overflow = OVERFLOW_VISIBLE;
} else {
overflow = OVERFLOW_NONE;
}
}
}
this.overflowX = overflow;
return overflow;
}
public int getOverflowY() {
int overflow = this.overflowY;
if (overflow != -1) {
return overflow;
}
final JStyleProperties props = this.getCssProperties();
if (props == null) {
overflow = OVERFLOW_NONE;
} else {
// TODO need to implement specific method for this instead of using getPropertyValue.
String overflowText = props.getPropertyValue("overflow-y");
if (overflowText == null) {
overflowText = props.getOverflow();
}
if (overflowText == null) {
overflow = OVERFLOW_NONE;
} else {
final String overflowTextTL = overflowText.toLowerCase();
if ("scroll".equals(overflowTextTL)) {
overflow = OVERFLOW_SCROLL;
} else if ("auto".equals(overflowTextTL)) {
overflow = OVERFLOW_AUTO;
} else if ("hidden".equals(overflowTextTL)) {
overflow = OVERFLOW_HIDDEN;
} else if ("visible".equals(overflowTextTL)) {
overflow = OVERFLOW_VISIBLE;
} else {
overflow = OVERFLOW_NONE;
}
}
}
this.overflowY = overflow;
return overflow;
}
protected BorderInfo borderInfo = INVALID_BORDER_INFO;
public BorderInfo getBorderInfo() {
BorderInfo binfo = this.borderInfo;
if (binfo != INVALID_BORDER_INFO) {
return binfo;
}
final JStyleProperties props = this.getCssProperties();
if (props != null) {
binfo = HtmlValues.getBorderInfo(props, this);
} else {
binfo = null;
}
this.borderInfo = binfo;
return binfo;
}
public Optional<Cursor> getCursor() {
final Optional<Cursor> prevCursorOpt = Optional.empty();
final JStyleProperties props = this.getCssProperties();
if (props == null) {
return prevCursorOpt;
} else {
// TODO need to implement specific method for this instead of using getPropertyValue.
final String cursor = props.getPropertyValue("cursor");
if (cursor == null) {
return prevCursorOpt;
} else {
final String cursorTL = cursor.toLowerCase();
// TODO: Handle more cursor types, defined here:
if ("default".equals(cursorTL)) {
return Optional.of(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
} else if ("pointer".equals(cursorTL)) {
return Optional.of(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else if ("crosshair".equals(cursorTL)) {
return Optional.of(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
} else if ("move".equals(cursorTL)) {
return Optional.of(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
} else if ("text".equals(cursorTL)) {
return Optional.of(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
} else if ("wait".equals(cursorTL)) {
return Optional.of(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
} else {
return prevCursorOpt;
}
}
}
}
public String getLeft() {
final JStyleProperties props = this.getCssProperties();
return props == null ? null : props.getLeft();
}
public String getTop() {
final JStyleProperties props = this.getCssProperties();
return props == null ? null : props.getTop();
}
public String getRight() {
final JStyleProperties props = this.getCssProperties();
return props == null ? null : props.getRight();
}
public String getBottom() {
final JStyleProperties props = this.getCssProperties();
return props == null ? null : props.getBottom();
}
public double getFontXHeight() {
// TODO: Cache this
final FontMetrics fm = getFontMetrics();
final Font font = fm.getFont();
if (font.getFamily().contains("Ahem")) {
// This kludge is for https://github.com/UprootLabs/gngr/issues/195
return 0.8 * font.getSize2D();
} else {
/*
if (font instanceof OpenType) {
final OpenType openType = (OpenType) font;
final ByteBuffer bbOs2 = ByteBuffer.wrap(openType.getFontTable(OpenType.TAG_OS2));
final short version = bbOs2.getShort();
System.out.println("Version:" + version);
}*/
final GlyphVector glyphVector = font.createGlyphVector(fm.getFontRenderContext(), "xuwz");
return glyphVector.getVisualBounds().getHeight();
}
}
// TODO: This should return a more abstract type that can represent values like length and percentage
public CSSProperty.VerticalAlign getVerticalAlign() {
final JStyleProperties props = this.getCssProperties();
final CSSProperty.VerticalAlign valignProperty = props.getNodeData().getProperty("vertical-align");
return valignProperty;
}
}