/* GNU GENERAL LICENSE Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either verion 3 of the License, or (at your option) any later version. This program 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 General License for more details. You should have received a copy of the GNU General Public along with this program. If not, see <http://www.gnu.org/licenses/>. Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it */ /* * Created on Apr 16, 2005 */ package org.lobobrowser.html.renderstate; import java.awt.Color; import java.awt.Cursor; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Toolkit; import java.awt.font.TextAttribute; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.StringTokenizer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lobobrowser.html.HtmlAttributeProperties; import org.lobobrowser.html.domimpl.HTMLDocumentImpl; import org.lobobrowser.html.domimpl.HTMLElementImpl; import org.lobobrowser.html.info.BackgroundInfo; import org.lobobrowser.html.info.BorderInfo; import org.lobobrowser.html.info.WordInfo; import org.lobobrowser.html.style.AbstractCSS2Properties; import org.lobobrowser.html.style.CSSValuesProperties; import org.lobobrowser.html.style.HtmlInsets; import org.lobobrowser.html.style.HtmlValues; import org.lobobrowser.html.style.RenderThreadState; import org.lobobrowser.util.gui.ColorFactory; import org.lobobrowser.util.gui.FontFactory; import org.lobobrowser.util.gui.LAFSettings; import org.lobobrowser.w3c.html.HTMLElement; import org.w3c.dom.css.CSS2Properties; /** * The Class StyleSheetRenderState. * * @author J. H. S. */ public class StyleSheetRenderState implements RenderState,CSSValuesProperties { /** The Constant logger. */ protected static final Logger logger = LogManager .getLogger(StyleSheetRenderState.class.getName()); /** The Constant FONT_FACTORY. */ private static final FontFactory FONT_FACTORY = FontFactory.getInstance(); /** The Constant DEFAULT_FONT. */ private static final Font DEFAULT_FONT = FONT_FACTORY.getFont(LAFSettings.getInstance().getFont(), null, null, null, LAFSettings.getInstance().getFontSize(), null, null,0,false,0); /** The Constant INVALID_INSETS. */ protected static final HtmlInsets INVALID_INSETS = new HtmlInsets(); /** The Constant INVALID_BACKGROUND_INFO. */ protected static final BackgroundInfo INVALID_BACKGROUND_INFO = new BackgroundInfo(); /** The Constant INVALID_BORDER_INFO. */ protected static final BorderInfo INVALID_BORDER_INFO = new BorderInfo(); /** The Constant INVALID_COLOR. */ protected static final Color INVALID_COLOR = new Color(100, 0, 100); /** The element. */ protected final HTMLElementImpl element; /** The document. */ protected final HTMLDocumentImpl document; /** The prev render state. */ protected final RenderState prevRenderState; /** The i background info. */ protected BackgroundInfo iBackgroundInfo = INVALID_BACKGROUND_INFO; /** The border info. */ protected BorderInfo borderInfo = INVALID_BORDER_INFO; /** The margin insets. */ protected HtmlInsets marginInsets = INVALID_INSETS; /** The padding insets. */ protected HtmlInsets paddingInsets = INVALID_INSETS; /** The i white space. */ protected Integer iWhiteSpace; /** The overflow x. */ protected int overflowX = -1; /** The overflow y. */ protected int overflowY = -1; /** The i font. */ private Font iFont; /** The i font metrics. */ private FontMetrics iFontMetrics; /** The i color. */ private Color iColor; /** The i background color. */ private Color iBackgroundColor = INVALID_COLOR; /** The i text background color. */ private Color iTextBackgroundColor = INVALID_COLOR; /** The i overlay color. */ private Color iOverlayColor = INVALID_COLOR; /** The cursor. */ private Optional<Cursor> cursor; /** The counters. */ private Map<String, ArrayList<Object>> counters = null; /** The i text decoration. */ private int iTextDecoration = -1; /** The i text transform. */ private int iTextTransform = -1; /** The i blank width. */ private int iBlankWidth = -1; /** The i highlight. */ private boolean iHighlight; /** The i display. */ private Integer iDisplay; /** The i text indent text. */ private String iTextIndentText = null; /** The align x percent. */ private int alignXPercent = -1; /** The cached visibility. */ private Integer cachedVisibility; /** The cached position. */ private Integer cachedPosition; /** The cached float. */ private Integer cachedFloat; /** The i word info map. */ private Map<String, WordInfo> iWordInfoMap = null; /** * Instantiates a new style sheet render state. * * @param prevRenderState * the prev render state * @param element * the element */ public StyleSheetRenderState(RenderState prevRenderState, HTMLElementImpl element) { this.prevRenderState = prevRenderState; this.element = element; this.document = (HTMLDocumentImpl) element.getOwnerDocument(); } /** * Instantiates a new style sheet render state. * * @param document * the document */ public StyleSheetRenderState(HTMLDocumentImpl document) { this.prevRenderState = null; this.element = null; this.document = document; } /** * Gets the default display. * * @return the default display */ protected int getDefaultDisplay() { return DISPLAY_INLINE; } /** * Gets the default color. * * @return the default color */ protected Color getDefaultColor() { return LAFSettings.getInstance().getColor(); } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getDisplay() */ @Override public int getDisplay() { Integer d = this.iDisplay; if (d != null) { return d.intValue(); } CSS2Properties props = this.getCssProperties(); String displayText = props == null ? null : props.getDisplay(); int displayInt = 0; if (displayText != null) { String displayTextTL = displayText.toLowerCase(); switch (displayTextTL) { case BLOCK: displayInt = DISPLAY_BLOCK; break; case NONE: displayInt = DISPLAY_NONE; break; case LIST_ITEM: displayInt = DISPLAY_LIST_ITEM; break; case TABLE: displayInt = DISPLAY_TABLE; break; case TABLE_CELL: displayInt = DISPLAY_TABLE_CELL; break; case TABLE_ROW: displayInt = DISPLAY_TABLE_ROW; break; case INLINE: displayInt = DISPLAY_INLINE; break; case INLINE_BLOCK: displayInt = DISPLAY_INLINE_BLOCK; break; case INHERIT: displayInt = this.getPreviousRenderState().getDisplay(); break; case INITIAL: displayInt = this.getDefaultDisplay(); break; default: displayInt = this.getDefaultDisplay(); break; } } else { displayInt = this.getDefaultDisplay(); } d = new Integer(displayInt); this.iDisplay = d; return displayInt; } /* * (non-Javadoc) * * @see * org.lobobrowser.html.renderstate.RenderState#getPreviousRenderState() */ @Override public RenderState getPreviousRenderState() { return this.prevRenderState; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getFontBase() */ @Override public int getFontBase() { RenderState prs = this.prevRenderState; return prs == null ? 3 : prs.getFontBase(); } /** * Repaint. */ public void repaint() { // Dummy implementation } /** * Gets the css properties. * * @return the css properties */ protected final AbstractCSS2Properties getCssProperties() { HTMLElementImpl element = this.element; return element == null ? null : element.getCurrentStyle(); } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#invalidate() */ @Override public void invalidate() { 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. } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getFont() */ @Override public Font getFont() { Font f = this.iFont; if (f != null) { return f; } AbstractCSS2Properties style = this.getCssProperties(); RenderState prs = this.prevRenderState; if (style == null) { if (prs != null) { f = prs.getFont(); this.iFont = f; return f; } f = DEFAULT_FONT; this.iFont = f; return f; } Float fontSize = null; String fontStyle = null; String fontVariant = null; String fontWeight = null; String fontFamily = null; String newFontSize = style == null ? null : style.getFontSize(); String newFontFamily = style == null ? null : style.getFontFamily(); String newFontStyle = style == null ? null : style.getFontStyle(); String newFontVariant = style == null ? null : style.getFontVariant(); String newFontWeight = style == null ? null : style.getFontWeight(); String verticalAlign = style == null ? null : style.getVerticalAlign(); String letterSpacing = style == null ? null : style.getLetterSpacing(); boolean isSuper = (verticalAlign != null) && verticalAlign.equalsIgnoreCase("super"); boolean isSub = (verticalAlign != null) && verticalAlign.equalsIgnoreCase("sub"); if ((newFontSize == null) && (newFontWeight == null) && (newFontStyle == null) && (newFontFamily == null) && (newFontVariant == null)) { if (!isSuper && !isSub) { if (prs != null) { f = prs.getFont(); this.iFont = f; return f; } f = DEFAULT_FONT; this.iFont = f; return f; } } if (newFontSize != null) { try { fontSize = new Float(HtmlValues.getFontSize(newFontSize, prs)); } catch (Exception err) { fontSize = LAFSettings.getInstance().getFontSize(); } } else if (fontSize == null) { if (prs != null) { fontSize = new Float(prs.getFont().getSize()); } else { fontSize = LAFSettings.getInstance().getFontSize(); } } if (newFontFamily != null) { fontFamily = newFontFamily; } else if ((fontFamily == null) && (prs != null)) { fontFamily = prs.getFont().getFamily(); } if (fontFamily == null) { fontFamily = Font.SANS_SERIF; } if (newFontStyle != null) { fontStyle = newFontStyle; } else { if(LAFSettings.getInstance().isItalic()){ fontStyle = "italic"; } } if (newFontVariant != null) { fontVariant = newFontVariant; } else if (prs != null) { // TODO: smallcaps? } if (newFontWeight != null) { fontWeight = newFontWeight; } else { if(LAFSettings.getInstance().isBold()){ fontWeight = "bold"; } } HTMLDocumentImpl document = this.document; Set locales = document == null ? null : document.getLocales(); Integer intLetterSpacing = HtmlValues.getPixelSize(letterSpacing, prs, 0); Integer superscript = null; Integer underline = null; boolean strikethrough = false; if (isSuper || LAFSettings.getInstance().isSuperscript()) { superscript = TextAttribute.SUPERSCRIPT_SUPER; } else if (isSub || LAFSettings.getInstance().isSubscript()) { superscript = TextAttribute.SUPERSCRIPT_SUB; } if ((superscript == null) && (prs != null)) { superscript = (Integer) prs.getFont().getAttributes().get(TextAttribute.SUPERSCRIPT); } if(LAFSettings.getInstance().isUnderline()){ underline = TextAttribute.UNDERLINE_LOW_ONE_PIXEL; } if(LAFSettings.getInstance().isStrikethrough()){ strikethrough = TextAttribute.STRIKETHROUGH_ON; } f = FONT_FACTORY.getFont(fontFamily, fontStyle, fontVariant, fontWeight, fontSize.floatValue(), locales, superscript, intLetterSpacing,strikethrough,underline); this.iFont = f; return f; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getColor() */ @Override public Color getColor() { Color c = this.iColor; if (c != null) { return c; } AbstractCSS2Properties props = this.getCssProperties(); String colorValue = props == null ? null : props.getColor(); if (INHERIT.equals(colorValue) && this.getPreviousRenderState() != null) { return this.getPreviousRenderState().getColor(); } else if (INITIAL.equals(colorValue)) { return getDefaultColor(); } else if ((colorValue == null) || "".equals(colorValue)) { RenderState prs = this.prevRenderState; if (prs != null) { c = prs.getColor(); this.iColor = c; return c; } else { this.iColor = getDefaultColor(); return getDefaultColor(); } } else { c = colorValue == null ? null : ColorFactory.getInstance().getColor(colorValue); this.iColor = c; } return c; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getBackgroundColor() */ @Override public Color getBackgroundColor() { Color c = this.iBackgroundColor; if (c != INVALID_COLOR) { return c; } Color localColor; BackgroundInfo binfo = this.getBackgroundInfo(); localColor = binfo == null ? null : binfo.getBackgroundColor(); if ((localColor == null) && (this.getDisplay() == DISPLAY_INLINE)) { RenderState prs = this.prevRenderState; if (prs != null) { Color ancestorColor = prs.getBackgroundColor(); if (ancestorColor != null) { this.iBackgroundColor = ancestorColor; return ancestorColor; } } } this.iBackgroundColor = localColor; return localColor; } /* * (non-Javadoc) * * @see * org.lobobrowser.html.renderstate.RenderState#getTextBackgroundColor() */ @Override public Color getTextBackgroundColor() { Color c = this.iTextBackgroundColor; if (c != INVALID_COLOR) { return c; } Color localColor; if (this.getDisplay() != DISPLAY_INLINE) { // Background painted by block. localColor = null; } else { BackgroundInfo binfo = this.getBackgroundInfo(); localColor = binfo == null ? null : binfo.getBackgroundColor(); if (localColor == null) { RenderState prs = this.prevRenderState; if (prs != null) { Color ancestorColor = prs.getTextBackgroundColor(); if (ancestorColor != null) { this.iTextBackgroundColor = ancestorColor; return ancestorColor; } } } } this.iTextBackgroundColor = localColor; return localColor; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getOverlayColor() */ @Override public Color getOverlayColor() { Color c = this.iOverlayColor; if (c != INVALID_COLOR) { return c; } AbstractCSS2Properties props = this.getCssProperties(); String colorValue = props == null ? null : props.getOverlayColor(); if ((colorValue == null) || (colorValue.length() == 0)) { RenderState prs = this.prevRenderState; if (prs != null) { c = prs.getOverlayColor(); this.iOverlayColor = c; return c; } else { colorValue = null; } } c = colorValue == null ? null : ColorFactory.getInstance().getColor(colorValue); this.iOverlayColor = c; return c; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getTextDecorationMask() */ @Override public int getTextDecorationMask() { int td = this.iTextDecoration; if (td != -1) { return td; } AbstractCSS2Properties props = this.getCssProperties(); String tdText = props == null ? null : props.getTextDecoration(); if (tdText == null) { RenderState prs = this.prevRenderState; if (prs != null) { td = prs.getTextDecorationMask(); this.iTextDecoration = td; return td; } } td = 0; if (tdText != null) { StringTokenizer tok = new StringTokenizer(tdText.toLowerCase(), ", \t\n\r"); while (tok.hasMoreTokens()) { String token = tok.nextToken(); switch (token) { case NONE: td |= MASK_TEXTDECORATION_NONE; break; case UNDERLINE: td |= MASK_TEXTDECORATION_UNDERLINE; break; case LINE_THROUGH: td |= MASK_TEXTDECORATION_LINE_THROUGH; break; case BLINK: td |= MASK_TEXTDECORATION_BLINK; break; case OVERLINE: td |= MASK_TEXTDECORATION_OVERLINE; break; case INHERIT: td |= this.getPreviousRenderState().getTextDecorationMask(); break; case INITIAL: td |= MASK_TEXTDECORATION_NONE; break; default: td |= MASK_TEXTDECORATION_NONE; break; } } } this.iTextDecoration = td; return td; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getTextTransform() */ @Override public int getTextTransform() { int tt = this.iTextTransform; if (tt != -1) { return tt; } AbstractCSS2Properties props = this.getCssProperties(); String tdText = props == null ? null : props.getTextTransform(); if (tdText == null) { RenderState prs = this.prevRenderState; if (prs != null) { tt = prs.getTextTransform(); this.iTextTransform = tt; return tt; } } tt = 0; if (tdText != null) { switch (tdText) { case NONE: tt |= TEXTTRANSFORM_NONE; break; case CAPITALIZE: tt |= TEXTTRANSFORM_CAPITALIZE; break; case UPPERCASE: tt |= TEXTTRANSFORM_UPPERCASE; break; case LOWERCASE: tt |= TEXTTRANSFORM_LOWERCASE; break; case INHERIT: tt |= this.getPreviousRenderState().getTextTransform(); break; case INITIAL: tt |= TEXTTRANSFORM_NONE; break; default: tt |= TEXTTRANSFORM_NONE; break; } } this.iTextTransform = tt; return tt; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getFontMetrics() */ @Override 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; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getBlankWidth() */ @Override public int getBlankWidth() { int bw = this.iBlankWidth; if (bw == -1) { bw = this.getFontMetrics().charWidth(' '); this.iBlankWidth = bw; } return bw; } /** * Checks if is highlight. * * @return Returns the iHighlight. */ @Override public boolean isHighlight() { return this.iHighlight; } /** * Sets the highlight. * * @param highlight * The iHighlight to set. */ @Override public void setHighlight(boolean highlight) { this.iHighlight = highlight; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getWordInfo(java.lang. * String) */ @Override public final WordInfo getWordInfo(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<String, WordInfo>(1); this.iWordInfoMap = map; } WordInfo wi = map.get(word); if (wi != null) { return wi; } wi = new WordInfo(); FontMetrics fm = this.getFontMetrics(); wi.setFontMetrics(fm); wi.setAscentPlusLeading(fm.getAscent() + fm.getLeading()); wi.setDescent(fm.getDescent()); wi.setHeight(fm.getHeight()); wi.setWidth(fm.stringWidth(word)); map.put(word, wi); return wi; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getAlignXPercent() */ @Override public int getAlignXPercent() { int axp = this.alignXPercent; if (axp != -1) { return axp; } CSS2Properties props = this.getCssProperties(); String textAlign = props == null ? null : props.getTextAlign(); if ((textAlign == null) || (textAlign.length() == 0)) { // Fall back to align attribute. HTMLElement element = this.element; if (element != null) { textAlign = element.getAttribute(HtmlAttributeProperties.ALIGN); if ((textAlign == null) || (textAlign.length() == 0)) { RenderState prs = this.prevRenderState; if (prs != null) { return prs.getAlignXPercent(); } textAlign = null; } } } if (textAlign == null) { axp = 0; } else if (CENTER.equalsIgnoreCase(textAlign)) { axp = 50; } else if (RIGHT.equalsIgnoreCase(textAlign)) { axp = 100; } else if (INHERIT.equalsIgnoreCase(textAlign)) { axp = this.getPreviousRenderState().getAlignXPercent(); } else if (INITIAL.equalsIgnoreCase(textAlign)) { axp = 0; } else { axp = 0; } this.alignXPercent = axp; return axp; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getAlignYPercent() */ @Override public int getAlignYPercent() { // This is only settable in table cells. // TODO: Does it work with display: table-cell? return 0; } /* * (non-Javadoc) * * @see * org.lobobrowser.html.renderstate.RenderState#getCount(java.lang.String, * int) */ @Override public int getCount(String counter, int nesting) { // Expected to be called only in GUI thread. RenderState prs = this.prevRenderState; if (prs != null) { return prs.getCount(counter, nesting); } Map<String, ArrayList<Object>> counters = this.counters; if (counters == null) { return 0; } ArrayList<Object> counterArray = counters.get(counter); if ((nesting < 0) || (nesting >= counterArray.size())) { return 0; } Integer integer = (Integer) counterArray.get(nesting); return integer == null ? 0 : integer.intValue(); } /* * (non-Javadoc) * * @see * org.lobobrowser.html.renderstate.RenderState#resetCount(java.lang.String, * int, int) */ @Override public void resetCount(String counter, int nesting, int value) { // Expected to be called only in the GUI thread. RenderState prs = this.prevRenderState; if (prs != null) { prs.resetCount(counter, nesting, value); } else { Map<String, ArrayList<Object>> counters = this.counters; if (counters == null) { counters = new HashMap<String, ArrayList<Object>>(2); this.counters = counters; counters.put(counter, new ArrayList<Object>(0)); } ArrayList<Object> counterArray = counters.get(counter); while (counterArray.size() <= nesting) { counterArray.add(null); } counterArray.set(nesting, new Integer(value)); } } /* * (non-Javadoc) * * @see * org.lobobrowser.html.renderstate.RenderState#incrementCount(java.lang. * String, int) */ @Override public int incrementCount(String counter, int nesting) { // Expected to be called only in the GUI thread. RenderState prs = this.prevRenderState; if (prs != null) { return prs.incrementCount(counter, nesting); } Map<String, ArrayList<Object>> counters = this.counters; if (counters == null) { counters = new HashMap<String, ArrayList<Object>>(2); this.counters = counters; counters.put(counter, new ArrayList<Object>(0)); } ArrayList<Object> counterArray = counters.get(counter); while (counterArray.size() <= nesting) { counterArray.add(null); } Integer integer = (Integer) counterArray.get(nesting); int prevValue = integer == null ? 0 : integer.intValue(); counterArray.set(nesting, new Integer(prevValue + 1)); return prevValue; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getBackgroundInfo() */ @Override public BackgroundInfo getBackgroundInfo() { BackgroundInfo binfo = this.iBackgroundInfo; if (binfo != INVALID_BACKGROUND_INFO) { return binfo; } if(element != null && !"BODY".equals(element.getNodeName())){ binfo = null; } AbstractCSS2Properties props = this.getCssProperties(); if (props != null) { String backgroundText = props.getBackground(); if (backgroundText != null) { if (binfo == null) { binfo = new BackgroundInfo(); } if((backgroundText.startsWith(ColorFactory.RGB_START) || backgroundText.startsWith(ColorFactory.RGB_START)) && backgroundText.endsWith(")")){ binfo.setBackgroundColor(ColorFactory.getInstance().getColor(backgroundText)); } else { String[] backList = backgroundText.split(" "); for (int i = 0; i < backList.length; i++) { String back = backList[i]; if (back.contains("url")) { String start = "url("; int startIdx = start.length(); int closingIdx = back.lastIndexOf(')'); String quotedUri = back.substring(startIdx, closingIdx); binfo.setBackgroundImage(this.document.getFullURL(quotedUri)); } if (ColorFactory.getInstance().getColor(back) != null) { binfo.setBackgroundColor(ColorFactory.getInstance().getColor(back)); } else if (INHERIT.equalsIgnoreCase(back)) { binfo.setBackgroundColor(this.getPreviousRenderState().getBackgroundColor()); } else if (INITIAL.equalsIgnoreCase(back)) { binfo.setBackgroundColor(Color.WHITE); } this.applyBackgroundPosition(binfo, back); this.applyBackgroundRepeat(binfo, back); } } } else { String background = this.element.getAttribute(HtmlAttributeProperties.BACKGROUND); if ((background != null) && !"".equals(background)) { if (binfo == null) { binfo = new BackgroundInfo(); } binfo.setBackgroundImage(this.document.getFullURL(background)); } String backgroundColorText = props.getBackgroundColor(); if (backgroundColorText != null) { if (binfo == null) { binfo = new BackgroundInfo(); } if (INHERIT.equalsIgnoreCase(backgroundColorText)) { binfo.setBackgroundColor(this.getPreviousRenderState().getBackgroundColor()); } else if (INITIAL.equalsIgnoreCase(backgroundColorText)) { binfo.setBackgroundColor(Color.WHITE); }else { binfo.setBackgroundColor(ColorFactory.getInstance().getColor(backgroundColorText)); } } String backgroundImageText = props.getBackgroundImage(); if ((backgroundImageText != null) && (backgroundImageText.length() > 0)) { URL backgroundImage = HtmlValues.getURIFromStyleValue(backgroundImageText); if (backgroundImage != null) { if (binfo == null) { binfo = new BackgroundInfo(); } binfo.setBackgroundImage(backgroundImage); } } String backgroundRepeatText = props.getBackgroundRepeat(); if (backgroundRepeatText != null) { if (binfo == null) { binfo = new BackgroundInfo(); } this.applyBackgroundRepeat(binfo, backgroundRepeatText); } String backgroundPositionText = props.getBackgroundPosition(); if (backgroundPositionText != null) { if (binfo == null) { binfo = new BackgroundInfo(); } this.applyBackgroundPosition(binfo, backgroundPositionText); } } } this.iBackgroundInfo = binfo; return binfo; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getTextIndentText() */ @Override public String getTextIndentText() { String tiText = this.iTextIndentText; if (tiText != null) { return tiText; } AbstractCSS2Properties props = this.getCssProperties(); tiText = props == null ? null : props.getTextIndent(); if (tiText == null) { RenderState prs = this.prevRenderState; if (prs != null) { String parentText = prs.getTextIndentText(); this.iTextIndentText = parentText; return parentText; } else { tiText = ""; } } return tiText; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getTextIndent(int) */ @Override public int getTextIndent(int availSize) { // No caching for this one. String tiText = this.getTextIndentText(); if (tiText.length() == 0) { return 0; } else { return HtmlValues.getPixelSize(tiText, this, 0, availSize); } } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getWhiteSpace() */ @Override public int getWhiteSpace() { if (RenderThreadState.getState().overrideNoWrap) { return WS_NOWRAP; } Integer ws = this.iWhiteSpace; if (ws != null) { return ws.intValue(); } AbstractCSS2Properties props = this.getCssProperties(); String whiteSpaceText = props == null ? null : props.getWhiteSpace(); int wsValue; if (whiteSpaceText == null) { RenderState prs = this.prevRenderState; if (prs != null) { wsValue = prs.getWhiteSpace(); } else { wsValue = WS_NORMAL; } } else { String whiteSpaceTextTL = whiteSpaceText.toLowerCase(); if (NOWRAP.equals(whiteSpaceTextTL)) { wsValue = WS_NOWRAP; } else if (PRE.equals(whiteSpaceTextTL)) { wsValue = WS_PRE; } else if (INHERIT.equals(whiteSpaceTextTL)) { wsValue = this.getPreviousRenderState().getWhiteSpace(); } else if (INITIAL.equals(whiteSpaceTextTL)) { wsValue = WS_NORMAL; } else { wsValue = WS_NORMAL; } } this.iWhiteSpace = new Integer(wsValue); return wsValue; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getMarginInsets() */ @Override public HtmlInsets getMarginInsets() { HtmlInsets mi = this.marginInsets; if (mi != INVALID_INSETS) { return mi; } AbstractCSS2Properties props = this.getCssProperties(); if (props == null) { mi = null; } else { mi = HtmlValues.getMarginInsets(props, this); } this.marginInsets = mi; return mi; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getPaddingInsets() */ @Override public HtmlInsets getPaddingInsets() { HtmlInsets mi = this.paddingInsets; if (mi != INVALID_INSETS) { return mi; } AbstractCSS2Properties props = this.getCssProperties(); if (props == null) { mi = null; } else { mi = HtmlValues.getPaddingInsets(props, this); this.paddingInsets = mi; } return mi; } /** * Apply background horizontal positon. * * @param binfo * the binfo * @param xposition * the xposition */ private void applyBackgroundHorizontalPositon(BackgroundInfo binfo, String xposition) { if (xposition.endsWith("%")) { binfo.setBackgroundXPositionAbsolute(false); try { binfo.setBackgroundXPosition( (int) Double.parseDouble(xposition.substring(0, xposition.length() - 1).trim())); } catch (NumberFormatException nfe) { binfo.setBackgroundXPosition(0); } } else { switch (xposition) { case CENTER: binfo.setBackgroundXPositionAbsolute(false); binfo.setBackgroundXPosition(50); case RIGHT: binfo.setBackgroundXPositionAbsolute(false); binfo.setBackgroundXPosition(100); case LEFT: binfo.setBackgroundXPositionAbsolute(false); binfo.setBackgroundXPosition(0); case BOTTOM: binfo.setBackgroundYPositionAbsolute(false); binfo.setBackgroundYPosition(100); case TOP: binfo.setBackgroundYPositionAbsolute(false); binfo.setBackgroundYPosition(0); case INHERIT: BackgroundInfo bi = this.getPreviousRenderState().getBackgroundInfo(); if(bi!= null){ binfo.setBackgroundXPositionAbsolute(bi.isBackgroundXPositionAbsolute()); binfo.setBackgroundXPosition(bi.getBackgroundXPosition()); } case INITIAL: binfo.setBackgroundXPositionAbsolute(true); binfo.setBackgroundXPosition(HtmlValues.getPixelSize(xposition, this, 0)); default: binfo.setBackgroundXPositionAbsolute(true); binfo.setBackgroundXPosition(HtmlValues.getPixelSize(xposition, this, 0)); } } } /** * Apply background vertical position. * * @param binfo * the binfo * @param yposition * the yposition */ private void applyBackgroundVerticalPosition(BackgroundInfo binfo, String yposition) { if (yposition.endsWith("%")) { binfo.setBackgroundYPositionAbsolute(false); try { binfo.setBackgroundYPosition( (int) Double.parseDouble(yposition.substring(0, yposition.length() - 1).trim())); } catch (NumberFormatException nfe) { binfo.setBackgroundYPosition(0); } } else { switch (yposition) { case CENTER: binfo.setBackgroundYPositionAbsolute(false); binfo.setBackgroundYPosition(50); case RIGHT: binfo.setBackgroundYPositionAbsolute(false); binfo.setBackgroundYPosition(100); case LEFT: binfo.setBackgroundYPositionAbsolute(false); binfo.setBackgroundYPosition(0); case BOTTOM: binfo.setBackgroundYPositionAbsolute(false); binfo.setBackgroundYPosition(100); case TOP: binfo.setBackgroundYPositionAbsolute(false); binfo.setBackgroundYPosition(0); case INHERIT: BackgroundInfo bi = this.getPreviousRenderState().getBackgroundInfo(); if(bi!= null){ binfo.setBackgroundYPositionAbsolute(bi.isBackgroundYPositionAbsolute()); binfo.setBackgroundYPosition(bi.getBackgroundYPosition()); } case INITIAL: binfo.setBackgroundYPositionAbsolute(true); binfo.setBackgroundYPosition(HtmlValues.getPixelSize(yposition, this, 0)); default: binfo.setBackgroundYPositionAbsolute(true); binfo.setBackgroundYPosition(HtmlValues.getPixelSize(yposition, this, 0)); } } } /** * Apply background position. * * @param binfo * the binfo * @param position * the position */ private void applyBackgroundPosition(BackgroundInfo binfo, String position) { binfo.setBackgroundXPositionAbsolute(false); binfo.setBackgroundYPositionAbsolute(false); binfo.setBackgroundXPosition(50); binfo.setBackgroundYPosition(50); StringTokenizer tok = new StringTokenizer(position, " \t\r\n"); if (tok.hasMoreTokens()) { String xposition = tok.nextToken(); this.applyBackgroundHorizontalPositon(binfo, xposition); if (tok.hasMoreTokens()) { String yposition = tok.nextToken(); this.applyBackgroundVerticalPosition(binfo, yposition); } } } /** * Apply background repeat. * * @param binfo * the binfo * @param backgroundRepeatText * the background repeat text */ private void applyBackgroundRepeat(BackgroundInfo binfo, String backgroundRepeatText) { 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 (REPEAT_NO.equals(brtl)) { binfo.backgroundRepeat = BackgroundInfo.BR_NO_REPEAT; } } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getVisibility() */ @Override public int getVisibility() { Integer v = this.cachedVisibility; if (v != null) { return v.intValue(); } AbstractCSS2Properties props = this.getCssProperties(); int visibility; if (props == null) { visibility = VISIBILITY_VISIBLE; } else { String visibText = props.getVisibility(); if ((visibText == null) || (visibText.length() == 0)) { visibility = VISIBILITY_VISIBLE; } else { String visibTextTL = visibText.toLowerCase(); switch (visibTextTL) { case HIDDEN: visibility = VISIBILITY_HIDDEN; break; case VISIBLE: visibility = VISIBILITY_VISIBLE; break; case COLLAPSE: visibility = VISIBILITY_COLLAPSE; break; case INHERIT: visibility = this.getPreviousRenderState().getVisibility(); break; case INITIAL: visibility = VISIBILITY_VISIBLE; break; default: visibility = VISIBILITY_VISIBLE; break; } } } this.cachedVisibility = new Integer(visibility); return visibility; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getPosition() */ @Override public int getPosition() { Integer p = this.cachedPosition; if (p != null) { return p.intValue(); } AbstractCSS2Properties props = this.getCssProperties(); int position = 0; if (props == null) { position = POSITION_STATIC; } else { String positionText = props.getPosition(); if ((positionText == null) || (positionText.length() == 0)) { position = POSITION_STATIC; } else { String positionTextTL = positionText.toLowerCase(); switch (positionTextTL) { case ABSOLUTE: position = POSITION_ABSOLUTE; break; case STATIC: position = POSITION_STATIC; break; case RELATIVE: position = POSITION_RELATIVE; break; case FIXED: position = POSITION_FIXED; break; case INHERIT: position = this.getPreviousRenderState().getPosition(); break; case INITIAL: position = POSITION_STATIC; break; default: position = POSITION_STATIC; break; } } } this.cachedPosition = new Integer(position); return position; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getFloat() */ @Override public int getFloat() { Integer p = this.cachedFloat; if (p != null) { return p.intValue(); } AbstractCSS2Properties props = this.getCssProperties(); int floatValue = 0; if (props == null) { floatValue = FLOAT_NONE; } else { String floatText = props.getFloat(); if ((floatText == null) || (floatText.length() == 0)) { floatValue = FLOAT_NONE; } else { String floatTextTL = floatText.toLowerCase(); switch (floatTextTL) { case LEFT: floatValue = FLOAT_LEFT; break; case RIGHT: floatValue = FLOAT_RIGHT; break; case NONE: floatValue = FLOAT_NONE; break; case INHERIT: floatValue = this.getPreviousRenderState().getFloat(); break; case INITIAL: floatValue = FLOAT_NONE; break; } } } this.cachedFloat = new Integer(floatValue); return floatValue; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return "StyleSheetRenderState[font=" + this.getFont() + ",textDecoration=" + this.getTextDecorationMask() + "]"; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getOverflowX() */ @Override public int getOverflowX() { int overflow = this.overflowX; if (overflow != -1) { return overflow; } AbstractCSS2Properties props = this.getCssProperties(); if (props == null) { overflow = OVERFLOW_NONE; } else { String overflowText = props.getPropertyValue("overflow-x"); if (overflowText == null) { overflowText = props.getOverflow(); if (overflowText == null) { return OVERFLOW_NONE; } } switch (overflowText) { case SCROLL: overflow = OVERFLOW_SCROLL; break; case AUTO: overflow = OVERFLOW_AUTO; break; case HIDDEN: overflow = OVERFLOW_HIDDEN; break; case VISIBLE: overflow = OVERFLOW_VISIBLE; break; case INHERIT: overflow = this.getPreviousRenderState().getOverflowX(); break; case INITIAL: overflow = OVERFLOW_NONE; break; default: overflow = OVERFLOW_NONE; } } this.overflowX = overflow; return overflow; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getOverflowY() */ @Override public int getOverflowY() { int overflow = this.overflowY; if (overflow != -1) { return overflow; } AbstractCSS2Properties props = this.getCssProperties(); if (props == null) { overflow = OVERFLOW_NONE; } else { String overflowText = props.getPropertyValue("overflow-y"); if (overflowText == null) { overflowText = props.getOverflow(); if (overflowText == null) { return OVERFLOW_NONE; } } switch (overflowText) { case SCROLL: overflow = OVERFLOW_SCROLL; break; case AUTO: overflow = OVERFLOW_AUTO; break; case HIDDEN: overflow = OVERFLOW_HIDDEN; break; case VISIBLE: overflow = OVERFLOW_VISIBLE; break; case INHERIT: overflow = this.getPreviousRenderState().getOverflowY(); break; case INITIAL: overflow = OVERFLOW_NONE; break; default: overflow = OVERFLOW_NONE; } } this.overflowY = overflow; return overflow; } /* * (non-Javadoc) * * @see org.lobobrowser.html.renderstate.RenderState#getBorderInfo() */ @Override public BorderInfo getBorderInfo() { BorderInfo binfo = this.borderInfo; if (binfo != INVALID_BORDER_INFO) { return binfo; } AbstractCSS2Properties props = this.getCssProperties(); if (props != null) { binfo = HtmlValues.getBorderInfo(props, this); } else { binfo = null; } this.borderInfo = binfo; return binfo; } @Override public void setCursor(Optional<Cursor> cursor) { this.cursor = cursor; } @Override public Optional<Cursor> getCursor() { Optional<Cursor> prevCursorOpt = Optional.empty(); AbstractCSS2Properties props = this.getCssProperties(); if (this.cursor != null) { prevCursorOpt = this.cursor; } if (props == null) { return prevCursorOpt; } else { String cursor = props.getPropertyValue("cursor"); if (cursor == null) { return prevCursorOpt; } else { String cursorTL = cursor.toLowerCase(); switch (cursorTL) { case DEFAULT: prevCursorOpt = Optional.of(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); break; case POINTER: prevCursorOpt = Optional.of(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); break; case CROSSHAIR: prevCursorOpt = Optional.of(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); break; case MOVE: prevCursorOpt = Optional.of(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); break; case TEXT: prevCursorOpt = Optional.of(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); break; case WAIT: prevCursorOpt = Optional.of(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); break; case INHERIT: prevCursorOpt = this.getPreviousRenderState().getCursor(); break; case INITIAL: prevCursorOpt = Optional.of(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); break; default: prevCursorOpt = Optional.of(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); break; } } return prevCursorOpt; } } }