/*
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
*/
package org.lobobrowser.html.style;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lobobrowser.util.Urls;
import org.lobobrowser.util.gui.ColorFactory;
import org.w3c.dom.css.CSS2Properties;
public class HtmlValues {
static final String BORDER_THIN_SIZE = "1px";
static final String BORDER_MEDIUM_SIZE = "3px";
static final String BORDER_THICK_SIZE = "5px";
public static final Map<String, FontInfo> SYSTEM_FONTS = new HashMap<>();
private static final Logger logger = Logger.getLogger(HtmlValues.class.getName());
public static final float DEFAULT_FONT_SIZE = 16.0f;
public static final int DEFAULT_FONT_SIZE_INT = (int) DEFAULT_FONT_SIZE;
// TODO: Make the minimum font size configurable
public static final int MINIMUM_FONT_SIZE_PIXELS = 14;
public static final Float DEFAULT_FONT_SIZE_BOX = new Float(DEFAULT_FONT_SIZE);
public static final int DEFAULT_BORDER_WIDTH = 2;
public static final int BORDER_STYLE_NONE = 0;
public static final int BORDER_STYLE_HIDDEN = 1;
public static final int BORDER_STYLE_DOTTED = 2;
public static final int BORDER_STYLE_DASHED = 3;
public static final int BORDER_STYLE_SOLID = 4;
public static final int BORDER_STYLE_DOUBLE = 5;
public static final int BORDER_STYLE_GROOVE = 6;
public static final int BORDER_STYLE_RIDGE = 7;
public static final int BORDER_STYLE_INSET = 8;
public static final int BORDER_STYLE_OUTSET = 9;
static {
final FontInfo systemFont = new FontInfo();
SYSTEM_FONTS.put("caption", systemFont);
SYSTEM_FONTS.put("icon", systemFont);
SYSTEM_FONTS.put("menu", systemFont);
SYSTEM_FONTS.put("message-box", systemFont);
SYSTEM_FONTS.put("small-caption", systemFont);
SYSTEM_FONTS.put("status-bar", systemFont);
}
private HtmlValues() {
}
public static boolean isBorderStyle(final String token) {
final String tokenTL = token.toLowerCase();
return tokenTL.equals("solid") || tokenTL.equals("dashed") || tokenTL.equals("dotted") || tokenTL.equals("double")
|| tokenTL.equals("none") || tokenTL.equals("hidden") || tokenTL.equals("groove") || tokenTL.equals("ridge")
|| tokenTL.equals("inset") || tokenTL.equals("outset");
}
public static HtmlInsets getMarginInsets(final CSS2Properties cssProperties, final RenderState renderState) {
HtmlInsets insets = null;
final String topText = cssProperties.getMarginTop();
insets = updateInset(insets, topText, renderState, topUpdater);
final String leftText = cssProperties.getMarginLeft();
insets = updateInset(insets, leftText, renderState, leftUpdater);
final String bottomText = cssProperties.getMarginBottom();
insets = updateInset(insets, bottomText, renderState, bottomUpdater);
final String rightText = cssProperties.getMarginRight();
insets = updateInset(insets, rightText, renderState, rightUpdater);
return insets;
}
public static HtmlInsets getPaddingInsets(final CSS2Properties cssProperties, final RenderState renderState) {
HtmlInsets insets = null;
final String topText = cssProperties.getPaddingTop();
insets = updateInset(insets, topText, renderState, topUpdater);
final String leftText = cssProperties.getPaddingLeft();
insets = updateInset(insets, leftText, renderState, leftUpdater);
final String bottomText = cssProperties.getPaddingBottom();
insets = updateInset(insets, bottomText, renderState, bottomUpdater);
final String rightText = cssProperties.getPaddingRight();
insets = updateInset(insets, rightText, renderState, rightUpdater);
return insets;
}
/**
* Populates {@link BorderInfo.insets}.
*
* @param binfo
* A BorderInfo with its styles already populated.
* @param cssProperties
* The CSS properties object.
* @param renderState
* The current render state.
*/
public static void populateBorderInsets(final BorderInfo binfo, final CSS2Properties cssProperties, final RenderState renderState) {
HtmlInsets insets = null;
if (binfo.topStyle != HtmlValues.BORDER_STYLE_NONE && binfo.topStyle != HtmlValues.BORDER_STYLE_HIDDEN) {
final String topText = cssProperties.getBorderTopWidth();
insets = updateBorderInset(insets, topText, renderState, topUpdater, binfo.topStyle);
}
if (binfo.leftStyle != HtmlValues.BORDER_STYLE_NONE && binfo.leftStyle != HtmlValues.BORDER_STYLE_HIDDEN) {
final String leftText = cssProperties.getBorderLeftWidth();
insets = updateBorderInset(insets, leftText, renderState, leftUpdater, binfo.leftStyle);
}
if (binfo.bottomStyle != HtmlValues.BORDER_STYLE_NONE && binfo.bottomStyle != HtmlValues.BORDER_STYLE_HIDDEN) {
final String bottomText = cssProperties.getBorderBottomWidth();
insets = updateBorderInset(insets, bottomText, renderState, bottomUpdater, binfo.bottomStyle);
}
if (binfo.rightStyle != HtmlValues.BORDER_STYLE_NONE && binfo.rightStyle != HtmlValues.BORDER_STYLE_HIDDEN) {
final String rightText = cssProperties.getBorderRightWidth();
insets = updateBorderInset(insets, rightText, renderState, rightUpdater, binfo.rightStyle);
}
binfo.insets = insets;
}
/* Not used by anyone
private static int getBorderWidth(final String sizeText, final int borderStyle, final RenderState renderState) {
if (borderStyle == BORDER_STYLE_NONE) {
return 0;
} else {
if (sizeText == null || sizeText.length() == 0) {
return DEFAULT_BORDER_WIDTH;
}
return HtmlValues.getPixelSize(sizeText, renderState, DEFAULT_BORDER_WIDTH);
}
}*/
private static interface InsetUpdater {
void updateValue(HtmlInsets insets, final int value);
void updateType(HtmlInsets insets, final int type);
}
private static InsetUpdater topUpdater = new InsetUpdater() {
public void updateValue(final HtmlInsets insets, final int value) {
insets.top = value;
}
public void updateType(final HtmlInsets insets, final int type) {
insets.topType = type;
}
};
private static InsetUpdater leftUpdater = new InsetUpdater() {
public void updateValue(final HtmlInsets insets, final int value) {
insets.left = value;
}
public void updateType(final HtmlInsets insets, final int type) {
insets.leftType = type;
}
};
private static InsetUpdater bottomUpdater = new InsetUpdater() {
public void updateValue(final HtmlInsets insets, final int value) {
insets.bottom = value;
}
public void updateType(final HtmlInsets insets, final int type) {
insets.bottomType = type;
}
};
private static InsetUpdater rightUpdater = new InsetUpdater() {
public void updateValue(final HtmlInsets insets, final int value) {
insets.right = value;
}
public void updateType(final HtmlInsets insets, final int type) {
insets.rightType = type;
}
};
private static HtmlInsets updateInset(HtmlInsets insets, String sizeText, final RenderState renderState, final InsetUpdater updater) {
if (sizeText == null) {
return insets;
}
sizeText = sizeText.trim();
if (sizeText.length() == 0) {
return insets;
}
if (insets == null) {
insets = new HtmlInsets();
}
if ("auto".equalsIgnoreCase(sizeText)) {
updater.updateType(insets, HtmlInsets.TYPE_AUTO);
} else if (sizeText.endsWith("%")) {
updater.updateType(insets, HtmlInsets.TYPE_PERCENT);
try {
updater.updateValue(insets, Integer.parseInt(sizeText.substring(0, sizeText.length() - 1)));
} catch (final NumberFormatException nfe) {
updater.updateValue(insets, 0);
}
} else {
updater.updateType(insets, HtmlInsets.TYPE_PIXELS);
updater.updateValue(insets, HtmlValues.getPixelSize(sizeText, renderState, 0));
}
return insets;
}
private static HtmlInsets updateBorderInset(HtmlInsets insets, String sizeText, final RenderState renderState, final InsetUpdater updater, final int borderStyle) {
if (sizeText == null) {
if (borderStyle != BORDER_STYLE_NONE) {
sizeText = BORDER_MEDIUM_SIZE;
}
}
return updateInset(insets, sizeText, renderState, updater);
}
public static Insets getInsets(final String insetsSpec, final RenderState renderState, final boolean negativeOK) {
final int[] insetsArray = new int[4];
int size = 0;
final StringTokenizer tok = new StringTokenizer(insetsSpec);
if (tok.hasMoreTokens()) {
String token = tok.nextToken();
insetsArray[0] = getPixelSize(token, renderState, 0);
if (negativeOK || (insetsArray[0] >= 0)) {
size = 1;
if (tok.hasMoreTokens()) {
token = tok.nextToken();
insetsArray[1] = getPixelSize(token, renderState, 0);
if (negativeOK || (insetsArray[1] >= 0)) {
size = 2;
if (tok.hasMoreTokens()) {
token = tok.nextToken();
insetsArray[2] = getPixelSize(token, renderState, 0);
if (negativeOK || (insetsArray[2] >= 0)) {
size = 3;
if (tok.hasMoreTokens()) {
token = tok.nextToken();
insetsArray[3] = getPixelSize(token, renderState, 0);
size = 4;
if (negativeOK || (insetsArray[3] >= 0)) {
// nop
} else {
insetsArray[3] = 0;
}
}
} else {
size = 4;
insetsArray[2] = 0;
}
}
} else {
size = 4;
insetsArray[1] = 0;
}
}
} else {
size = 1;
insetsArray[0] = 0;
}
}
if (size == 4) {
return new Insets(insetsArray[0], insetsArray[3], insetsArray[2], insetsArray[1]);
} else if (size == 1) {
final int val = insetsArray[0];
return new Insets(val, val, val, val);
} else if (size == 2) {
return new Insets(insetsArray[0], insetsArray[1], insetsArray[0], insetsArray[1]);
} else if (size == 3) {
return new Insets(insetsArray[0], insetsArray[1], insetsArray[2], insetsArray[1]);
} else {
return null;
}
}
/**
* Gets a number for 1 to 7.
*
* @param oldHtmlSpec
* A number from 1 to 7 or +1, etc.
*/
public static final int getFontNumberOldStyle(String oldHtmlSpec, final RenderState renderState) {
oldHtmlSpec = oldHtmlSpec.trim();
int tentative;
try {
if (oldHtmlSpec.startsWith("+")) {
tentative = renderState.getFontBase() + Integer.parseInt(oldHtmlSpec.substring(1));
} else if (oldHtmlSpec.startsWith("-")) {
tentative = renderState.getFontBase() + Integer.parseInt(oldHtmlSpec);
} else {
tentative = Integer.parseInt(oldHtmlSpec);
}
if (tentative < 1) {
tentative = 1;
} else if (tentative > 7) {
tentative = 7;
}
} catch (final NumberFormatException nfe) {
// ignore
tentative = 3;
}
return tentative;
}
public static final float getFontSize(final int fontNumber) {
switch (fontNumber) {
case 1:
return 10.0f;
case 2:
return 11.0f;
case 3:
return 13.0f;
case 4:
return 16.0f;
case 5:
return 21.0f;
case 6:
return 29.0f;
case 7:
return 42.0f;
default:
return 63.0f;
}
}
public static final String getFontSizeSpec(final int fontNumber) {
switch (fontNumber) {
case 1:
return "10px";
case 2:
return "11px";
case 3:
return "13px";
case 4:
return "16px";
case 5:
return "21px";
case 6:
return "29px";
case 7:
return "42px";
default:
return "63px";
}
}
public static final float getFontSize(final String spec, final RenderState parentRenderState) {
final float specifiedFontSize = getFontSizeImpl(spec, parentRenderState);
if (specifiedFontSize == 0f) {
return specifiedFontSize;
}
return Math.max(MINIMUM_FONT_SIZE_PIXELS, specifiedFontSize);
}
private static final float getFontSizeImpl(final String spec, final RenderState parentRenderState) {
final String specTL = spec.toLowerCase();
if (specTL.endsWith("em")) {
if (parentRenderState == null) {
return DEFAULT_FONT_SIZE;
}
final Font font = parentRenderState.getFont();
final String pxText = specTL.substring(0, specTL.length() - 2);
double value;
try {
value = Double.parseDouble(pxText);
} catch (final NumberFormatException nfe) {
return DEFAULT_FONT_SIZE;
}
return (int) Math.round(font.getSize() * value);
} else if (specTL.endsWith("px") || specTL.endsWith("pt") || specTL.endsWith("cm") || specTL.endsWith("pc") || specTL.endsWith("cm")
|| specTL.endsWith("mm") || specTL.endsWith("ex")) {
final int pixelSize = getPixelSize(spec, parentRenderState, DEFAULT_FONT_SIZE_INT);
/* Disabling for GH-185
final int dpi = getDpi();
Normally the factor below should be 72, but the font-size concept in HTML is handled differently.
return (pixelSize * 96f) / dpi;
*/
return pixelSize;
} else if (specTL.endsWith("%")) {
final String value = specTL.substring(0, specTL.length() - 1);
try {
final double valued = Double.parseDouble(value);
final double parentFontSize = parentRenderState == null ? 14.0 : parentRenderState.getFont().getSize();
return (float) ((parentFontSize * valued) / 100.0);
} catch (final NumberFormatException nfe) {
return DEFAULT_FONT_SIZE;
}
} else if ("small".equals(specTL)) {
return 12.0f;
} else if ("medium".equals(specTL)) {
return 14.0f;
} else if ("large".equals(specTL)) {
return 20.0f;
} else if ("x-small".equals(specTL)) {
return 11.0f;
} else if ("xx-small".equals(specTL)) {
return 10.0f;
} else if ("x-large".equals(specTL)) {
return 26.0f;
} else if ("xx-large".equals(specTL)) {
return 40.0f;
} else if ("larger".equals(specTL)) {
final int parentFontSize = parentRenderState == null ? DEFAULT_FONT_SIZE_INT : parentRenderState.getFont().getSize();
return parentFontSize * 1.2f;
} else if ("smaller".equals(specTL)) {
final int parentFontSize = parentRenderState == null ? DEFAULT_FONT_SIZE_INT : parentRenderState.getFont().getSize();
return parentFontSize / 1.2f;
} else {
return getPixelSize(spec, parentRenderState, DEFAULT_FONT_SIZE_INT);
}
}
public static final int getPixelSize(final String spec, final RenderState renderState, final int errorValue, final int availSize) {
if (spec.endsWith("%")) {
final String perText = spec.substring(0, spec.length() - 1);
try {
final double val = Double.parseDouble(perText);
return (int) Math.round((availSize * val) / 100.0);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else {
return getPixelSize(spec, renderState, errorValue);
}
}
public static final int getPixelSize(final String spec, final RenderState renderState, final int errorValue) {
final String lcSpec = spec.toLowerCase();
if (lcSpec.endsWith("px")) {
final String pxText = lcSpec.substring(0, lcSpec.length() - 2);
try {
final double val = Double.parseDouble(pxText);
final int dpi = getDpi();
final double inches = val / 96;
return (int) Math.round(dpi * inches);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else if (lcSpec.endsWith("em") && (renderState != null)) {
final Font f = renderState.getFont();
final String valText = lcSpec.substring(0, lcSpec.length() - 2);
try {
final double val = Double.parseDouble(valText);
// Get fontSize in points (1/72 of an inch).
final float fontSizePt = f.getSize2D();
/* Formula: fontSize in CSS pixels = (fontSizePt / 72.0) * 96.0;
* fontSize in device pixels = (font size in css pixels * dpi) / 96.0
* = (fontSizePt / 72.0) * dpi
*
* Although, we should be using the factor 72 as per above, the actual factor used below is 96.
* This is because the font-height is calculated differently in CSS. TODO: Add a reference for this.
*/
/* Disabling for GH-185
final int dpi = getDpi();
final double fontSizeDevicePixels = (fontSizePt * dpi) / 96;
return (int) Math.round(fontSizeDevicePixels * val);
*/
return (int) Math.round(fontSizePt * val);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else if (lcSpec.endsWith("pt")) {
final String valText = lcSpec.substring(0, lcSpec.length() - 2);
try {
final double val = Double.parseDouble(valText);
final int dpi = getDpi();
final double inches = val / 72;
return (int) Math.round(dpi * inches);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else if (lcSpec.endsWith("in")) {
final String valText = lcSpec.substring(0, lcSpec.length() - 2);
try {
final double inches = Double.parseDouble(valText);
final int dpi = getDpi();
return (int) Math.round(dpi * inches);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else if (lcSpec.endsWith("pc")) {
final String valText = lcSpec.substring(0, lcSpec.length() - 2);
try {
final double val = Double.parseDouble(valText);
final int dpi = getDpi();
final double inches = val / 6;
return (int) Math.round(dpi * inches);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else if (lcSpec.endsWith("cm")) {
final String valText = lcSpec.substring(0, lcSpec.length() - 2);
try {
final double val = Double.parseDouble(valText);
final int dpi = getDpi();
final double inches = val / 2.54;
return (int) Math.round(dpi * inches);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else if (lcSpec.endsWith("mm")) {
final String valText = lcSpec.substring(0, lcSpec.length() - 2);
try {
final double val = Double.parseDouble(valText);
final int dpi = getDpi();
final double inches = val / 25.4;
return (int) Math.round(dpi * inches);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else if (lcSpec.endsWith("ex") && (renderState != null)) {
final double xHeight = renderState.getFontXHeight();
final String valText = lcSpec.substring(0, lcSpec.length() - 2);
try {
final double val = Double.parseDouble(valText);
return (int) Math.round(xHeight * val);
} catch (final NumberFormatException nfe) {
return errorValue;
}
} else {
final String pxText = lcSpec;
try {
return (int) Math.round(Double.parseDouble(pxText));
} catch (final NumberFormatException nfe) {
return errorValue;
}
}
}
private static int getDpi() {
if (GraphicsEnvironment.isHeadless()) {
// TODO: Why is this 72? The CSS native resolution seems to be 96, so we could use that instead.
return 72;
} else {
final int screenResolution = Toolkit.getDefaultToolkit().getScreenResolution();
// TODO: Hack: converting to a multiple of 16. See GH-185
return (screenResolution + 15) & 0xfffffff0;
}
}
public static int scaleToDevicePixels(final double cssPixels) {
return (int) Math.round(cssPixels * getDpi() / 96.0);
}
// TODO: move this functionality to the attribute -> CSS style functionality
public static int getOldSyntaxPixelSize(String spec, final int availSize, final int errorValue) {
if (spec == null) {
return errorValue;
}
spec = spec.trim();
try {
if (spec.endsWith("%")) {
return (availSize * Integer.parseInt(spec.substring(0, spec.length() - 1))) / 100;
}
if (spec.endsWith("px")){
final double val = Double.parseDouble(spec.substring(0, spec.length() - 2));
return scaleToDevicePixels(val);
} else {
return scaleToDevicePixels(Integer.parseInt(spec));
}
} catch (final NumberFormatException nfe) {
return errorValue;
}
}
/* This was called from BodyRenderState.getMarginInsets() which has now been commented out
public static int getOldSyntaxPixelSizeSimple(String spec, final int errorValue) {
if (spec == null) {
return errorValue;
}
spec = spec.trim();
try {
return Integer.parseInt(spec);
} catch (final NumberFormatException nfe) {
return errorValue;
}
}*/
public static java.net.URL getURIFromStyleValue(final String fullURLStyleValue) {
final String start = "url(";
if (!fullURLStyleValue.toLowerCase().startsWith(start)) {
return null;
}
final int startIdx = start.length();
final int closingIdx = fullURLStyleValue.lastIndexOf(')');
if (closingIdx == -1) {
return null;
}
final String quotedUri = fullURLStyleValue.substring(startIdx, closingIdx);
final String tentativeUri = unquoteAndUnescape(quotedUri);
try {
return Urls.createURL(null, tentativeUri);
} catch (final java.net.MalformedURLException mfu) {
logger.log(Level.WARNING, "Unable to create URL for URI=[" + tentativeUri + "].", mfu);
return null;
}
}
public static String unquoteAndUnescape(final String text) {
final StringBuffer result = new StringBuffer();
int index = 0;
final int length = text.length();
boolean escape = false;
boolean single = false;
if (index < length) {
final char ch = text.charAt(index);
switch (ch) {
case '\'':
single = true;
break;
case '"':
break;
case '\\':
escape = true;
break;
default:
result.append(ch);
}
index++;
}
OUTER: for (; index < length; index++) {
final char ch = text.charAt(index);
switch (ch) {
case '\'':
if (escape || !single) {
escape = false;
result.append(ch);
} else {
break OUTER;
}
break;
case '"':
if (escape || single) {
escape = false;
result.append(ch);
} else {
break OUTER;
}
break;
case '\\':
if (escape) {
escape = false;
result.append(ch);
} else {
escape = true;
}
break;
default:
if (escape) {
escape = false;
result.append('\\');
}
result.append(ch);
}
}
return result.toString();
}
public static String quoteAndEscape(final String text) {
final StringBuffer result = new StringBuffer();
result.append("'");
int index = 0;
final int length = text.length();
while (index < length) {
final char ch = text.charAt(index);
switch (ch) {
case '\'':
result.append("\\'");
break;
case '\\':
result.append("\\\\");
break;
default:
result.append(ch);
}
index++;
}
result.append("'");
return result.toString();
}
/*
public static String getColorFromBackground(final String background) {
final String[] backgroundParts = HtmlValues.splitCssValue(background);
for (final String token : backgroundParts) {
if (ColorFactory.getInstance().isColor(token)) {
return token;
}
}
return null;
}
*/
public static boolean isLength(final String token) {
if (token.endsWith("px") || token.endsWith("pt") || token.endsWith("pc") || token.endsWith("cm") || token.endsWith("mm")
|| token.endsWith("ex") || token.endsWith("em")) {
return true;
}
try {
Double.parseDouble(token);
return true;
} catch (final NumberFormatException nfe) {
return false;
}
}
public static String[] splitCssValue(final String cssValue) {
final ArrayList<String> tokens = new ArrayList<>(4);
final int len = cssValue.length();
int parenCount = 0;
StringBuffer currentWord = null;
for (int i = 0; i < len; i++) {
final char ch = cssValue.charAt(i);
switch (ch) {
case '(':
parenCount++;
if (currentWord == null) {
currentWord = new StringBuffer();
}
currentWord.append(ch);
break;
case ')':
parenCount--;
if (currentWord == null) {
currentWord = new StringBuffer();
}
currentWord.append(ch);
break;
case ' ':
case '\t':
case '\n':
case '\r':
if (parenCount == 0) {
tokens.add(currentWord.toString());
currentWord = null;
break;
} else {
// Fall through - no break
}
default:
if (currentWord == null) {
currentWord = new StringBuffer();
}
currentWord.append(ch);
break;
}
}
if (currentWord != null) {
tokens.add(currentWord.toString());
}
return tokens.toArray(new String[tokens.size()]);
}
public static boolean isUrl(final String token) {
return token.toLowerCase().startsWith("url(");
}
public static int getListStyleType(final String token) {
final String tokenTL = token.toLowerCase();
if ("none".equals(tokenTL)) {
return ListStyle.TYPE_NONE;
} else if ("disc".equals(tokenTL)) {
return ListStyle.TYPE_DISC;
} else if ("circle".equals(tokenTL)) {
return ListStyle.TYPE_CIRCLE;
} else if ("square".equals(tokenTL)) {
return ListStyle.TYPE_SQUARE;
} else if ("decimal".equals(tokenTL)) {
return ListStyle.TYPE_DECIMAL;
} else if ("lower-alpha".equals(tokenTL) || "lower-latin".equals(tokenTL)) {
return ListStyle.TYPE_LOWER_ALPHA;
} else if ("upper-alpha".equals(tokenTL) || "upper-latin".equals(tokenTL)) {
return ListStyle.TYPE_UPPER_ALPHA;
} else {
// TODO: Many types missing here
return ListStyle.TYPE_UNSET;
}
}
public static int getListStyleTypeDeprecated(final String token) {
final String tokenTL = token.toLowerCase();
if ("disc".equals(tokenTL)) {
return ListStyle.TYPE_DISC;
} else if ("circle".equals(tokenTL)) {
return ListStyle.TYPE_CIRCLE;
} else if ("square".equals(tokenTL)) {
return ListStyle.TYPE_SQUARE;
} else if ("1".equals(tokenTL)) {
return ListStyle.TYPE_DECIMAL;
} else if ("a".equals(tokenTL)) {
return ListStyle.TYPE_LOWER_ALPHA;
} else if ("A".equals(tokenTL)) {
return ListStyle.TYPE_UPPER_ALPHA;
} else {
// TODO: Missing i, I.
return ListStyle.TYPE_UNSET;
}
}
public static int getListStylePosition(final String token) {
final String tokenTL = token.toLowerCase();
if ("inside".equals(tokenTL)) {
return ListStyle.POSITION_INSIDE;
} else if ("outside".equals(tokenTL)) {
return ListStyle.POSITION_OUTSIDE;
} else {
return ListStyle.POSITION_UNSET;
}
}
public static ListStyle getListStyle(final String listStyleText) {
final ListStyle listStyle = new ListStyle();
final String[] tokens = HtmlValues.splitCssValue(listStyleText);
for (final String token : tokens) {
final int listStyleType = HtmlValues.getListStyleType(token);
if (listStyleType != ListStyle.TYPE_UNSET) {
listStyle.type = listStyleType;
} else if (HtmlValues.isUrl(token)) {
// TODO: listStyle.image
} else {
final int listStylePosition = HtmlValues.getListStylePosition(token);
if (listStylePosition != ListStyle.POSITION_UNSET) {
listStyle.position = listStylePosition;
}
}
}
return listStyle;
}
public static boolean isFontStyle(final String token) {
return "italic".equals(token) || "normal".equals(token) || "oblique".equals(token);
}
public static boolean isFontVariant(final String token) {
return "small-caps".equals(token) || "normal".equals(token);
}
public static boolean isFontWeight(final String token) {
if ("bold".equals(token) || "bolder".equals(token) || "lighter".equals(token)) {
return true;
}
try {
final int value = Integer.parseInt(token);
return ((value % 100) == 0) && (value >= 100) && (value <= 900);
} catch (final NumberFormatException nfe) {
return false;
}
}
public static BorderInfo getBorderInfo(final CSS2Properties properties, final RenderState renderState) {
final BorderInfo binfo = new BorderInfo();
binfo.topStyle = getBorderStyle(properties.getBorderTopStyle());
binfo.rightStyle = getBorderStyle(properties.getBorderRightStyle());
binfo.bottomStyle = getBorderStyle(properties.getBorderBottomStyle());
binfo.leftStyle = getBorderStyle(properties.getBorderLeftStyle());
final ColorFactory cf = ColorFactory.getInstance();
binfo.topColor = getBorderColor(cf, properties.getBorderTopColor(), renderState);
binfo.rightColor = getBorderColor(cf, properties.getBorderRightColor(), renderState);
binfo.bottomColor = getBorderColor(cf, properties.getBorderBottomColor(), renderState);
binfo.leftColor = getBorderColor(cf, properties.getBorderLeftColor(), renderState);
HtmlValues.populateBorderInsets(binfo, properties, renderState);
return binfo;
}
private static java.awt.Color getBorderColor(final ColorFactory cf, final String colorSpec, final RenderState renderState) {
if (colorSpec != null && (colorSpec.trim().length() != 0)) {
return cf.getColor(colorSpec);
} else {
return renderState.getColor();
}
}
public static Insets getBorderStyles(final CSS2Properties properties) {
final int topStyle = getBorderStyle(properties.getBorderTopStyle());
final int rightStyle = getBorderStyle(properties.getBorderRightStyle());
final int bottomStyle = getBorderStyle(properties.getBorderBottomStyle());
final int leftStyle = getBorderStyle(properties.getBorderLeftStyle());
return new Insets(topStyle, leftStyle, bottomStyle, rightStyle);
}
private static int getBorderStyle(final String styleText) {
if ((styleText == null) || (styleText.length() == 0)) {
return HtmlValues.BORDER_STYLE_NONE;
}
final String stl = styleText.toLowerCase();
if ("solid".equals(stl)) {
return BORDER_STYLE_SOLID;
} else if ("dashed".equals(stl)) {
return BORDER_STYLE_DASHED;
} else if ("dotted".equals(stl)) {
return BORDER_STYLE_DOTTED;
} else if ("none".equals(stl)) {
return BORDER_STYLE_NONE;
} else if ("hidden".equals(stl)) {
return BORDER_STYLE_HIDDEN;
} else if ("double".equals(stl)) {
return BORDER_STYLE_DOUBLE;
} else if ("groove".equals(stl)) {
return BORDER_STYLE_GROOVE;
} else if ("ridge".equals(stl)) {
return BORDER_STYLE_RIDGE;
} else if ("inset".equals(stl)) {
return BORDER_STYLE_INSET;
} else if ("outset".equals(stl)) {
return BORDER_STYLE_OUTSET;
} else {
return BORDER_STYLE_NONE;
}
}
public static boolean isBackgroundRepeat(final String repeat) {
final String repeatTL = repeat.toLowerCase();
return repeatTL.indexOf("repeat") != -1;
}
public static boolean isBackgroundPosition(final String token) {
return isLength(token) || token.endsWith("%") || token.equalsIgnoreCase("top") || token.equalsIgnoreCase("center")
|| token.equalsIgnoreCase("bottom") || token.equalsIgnoreCase("left") || token.equalsIgnoreCase("right");
}
}