/******************************************************************************* * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.wst.css.core.internal.util.declaration; import org.eclipse.wst.css.core.internal.contentmodel.IValID; import org.eclipse.wst.css.core.internal.contentmodel.PropCMProperty; import org.eclipse.wst.css.core.internal.parserz.CSSRegionContexts; import org.eclipse.wst.css.core.internal.parserz.CSSTextParser; import org.eclipse.wst.css.core.internal.parserz.CSSTextToken; /** * For 'font' property 'font' will be expanded to 'font-family', 'font-size', * 'font-style', 'font-variant', 'font-weight', 'line-height', */ public class FontShorthandAdapter implements IShorthandAdapter { /** * */ public FontShorthandAdapter() { super(); } /** * */ public boolean expand(String source, CSSPropertyContext dest) { CSSTextParser parser = new CSSTextParser(CSSTextParser.MODE_DECLARATION_VALUE, source); CSSTextToken[] tokens = parser.getTokens(); if (tokens.length <= 0) { return false; } String style = null, variant = null, weight = null, size = null, height = null, family = null; PropCMProperty propFont = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT); PropCMProperty propStyle = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_STYLE); PropCMProperty propVariant = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_VARIANT); PropCMProperty propWeight = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_WEIGHT); PropCMProperty propSize = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_SIZE); boolean bNormalSpecified = false; int i = 0; for (; i < tokens.length; i++) { if (tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_IDENT) { // first of all, check font idents if (i == 0) { for (int j = 0; j < propFont.getNumChild(); j++) { Object obj = propFont.getChildAt(i); if (obj instanceof String && tokens[i].image.compareToIgnoreCase(obj.toString()) == 0) return false; } } // value "normal" is shared !! if (tokens[i].image.equalsIgnoreCase(IValID.V_NORMAL)) { bNormalSpecified = true; } else { if (propStyle.canHave(tokens[i].image)) style = tokens[i].image; else if (propVariant.canHave(tokens[i].image)) variant = tokens[i].image; else if (propWeight.canHave(tokens[i].image)) weight = tokens[i].image; else if (propSize.canHave(tokens[i].image)) { size = tokens[i].image; break; // if size found, break loop } } } else if (tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_NUMBER && weight == null && propWeight.canHave(tokens[i].image)) { weight = tokens[i].image; } else if (org.eclipse.wst.css.core.internal.util.CSSUtil.isLength(tokens[i]) || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_NUMBER || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_PERCENTAGE) { size = tokens[i].image; break; // if size found, break loop } } if (bNormalSpecified) { if (style == null) style = IValID.V_NORMAL; if (variant == null) variant = IValID.V_NORMAL; if (weight == null) weight = IValID.V_NORMAL; } // skip whitespace for (i++; i < tokens.length; i++) { if (tokens[i].kind != CSSRegionContexts.CSS_S || tokens[i].kind != CSSRegionContexts.CSS_DECLARATION_VALUE_S) break; } // line-height ? if (i < tokens.length && tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_OPERATOR && tokens[i].image.equals("/")) { //$NON-NLS-1$ for (i++; i < tokens.length; i++) { if (org.eclipse.wst.css.core.internal.util.CSSUtil.isLength(tokens[i]) || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_PERCENTAGE || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_NUMBER || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_IDENT) { height = tokens[i++].image; break; } } } // font-family StringBuffer buf = new StringBuffer(); for (; i < tokens.length; i++) { if (tokens[i].kind == CSSRegionContexts.CSS_COMMENT) buf.append(" ");//$NON-NLS-1$ else buf.append(tokens[i].image); } family = buf.toString().trim(); dest.set(PropCMProperty.P_FONT_STYLE, style); dest.set(PropCMProperty.P_FONT_VARIANT, variant); dest.set(PropCMProperty.P_FONT_WEIGHT, weight); dest.set(PropCMProperty.P_FONT_SIZE, size); dest.set(PropCMProperty.P_LINE_HEIGHT, height); dest.set(PropCMProperty.P_FONT_FAMILY, family); return true; } /** * */ public String extract(String source, PropCMProperty propDest) { CSSTextParser parser = new CSSTextParser(CSSTextParser.MODE_DECLARATION_VALUE, source); CSSTextToken[] tokens = parser.getTokens(); if (tokens.length <= 0) { return null; } String style = null, variant = null, weight = null, size = null, height = null, family = null; PropCMProperty propFont = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT); PropCMProperty propStyle = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_STYLE); PropCMProperty propVariant = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_VARIANT); PropCMProperty propWeight = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_WEIGHT); PropCMProperty propSize = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_SIZE); PropCMProperty propHeight = PropCMProperty.getInstanceOf(PropCMProperty.P_LINE_HEIGHT); PropCMProperty propFamily = PropCMProperty.getInstanceOf(PropCMProperty.P_FONT_FAMILY); boolean bNormalSpecified = false; int i = 0; for (; i < tokens.length; i++) { if (tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_IDENT) { // first of all, check font idents if (i == 0) { for (int j = 0; j < propFont.getNumChild(); j++) { Object obj = propFont.getChildAt(i); if (obj instanceof String && tokens[i].image.compareToIgnoreCase(obj.toString()) == 0) return null; } } // value "normal" is shared !! if (tokens[i].image.equalsIgnoreCase(IValID.V_NORMAL)) { bNormalSpecified = true; } else { if (propStyle.canHave(tokens[i].image)) style = tokens[i].image; else if (propVariant.canHave(tokens[i].image)) variant = tokens[i].image; else if (propWeight.canHave(tokens[i].image)) weight = tokens[i].image; else if (propSize.canHave(tokens[i].image)) { size = tokens[i].image; break; // if size found, break loop } } } else if (tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_NUMBER && weight == null && propWeight.canHave(tokens[i].image)) { weight = tokens[i].image; } else if (org.eclipse.wst.css.core.internal.util.CSSUtil.isLength(tokens[i]) || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_NUMBER || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_PERCENTAGE) { size = tokens[i].image; break; // if size found, break loop } } if (bNormalSpecified) { if (style == null) style = IValID.V_NORMAL; if (variant == null) variant = IValID.V_NORMAL; if (weight == null) weight = IValID.V_NORMAL; } // skip whitespace for (i++; i < tokens.length; i++) { if (tokens[i].kind != CSSRegionContexts.CSS_S || tokens[i].kind != CSSRegionContexts.CSS_DECLARATION_VALUE_S) break; } // line-height ? if (i < tokens.length && tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_OPERATOR && tokens[i].image.equals("/")) { //$NON-NLS-1$ for (i++; i < tokens.length; i++) { if (org.eclipse.wst.css.core.internal.util.CSSUtil.isLength(tokens[i]) || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_PERCENTAGE || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_NUMBER || tokens[i].kind == CSSRegionContexts.CSS_DECLARATION_VALUE_IDENT) { height = tokens[i++].image; break; } } } // font-family StringBuffer buf = new StringBuffer(); for (; i < tokens.length; i++) { if (tokens[i].kind == CSSRegionContexts.CSS_COMMENT) buf.append(" ");//$NON-NLS-1$ else buf.append(tokens[i].image); } family = buf.toString().trim(); if (propStyle == propDest) return style; else if (propVariant == propDest) return variant; else if (propWeight == propDest) return weight; else if (propSize == propDest) return size; else if (propHeight == propDest) return height; else if (propFamily == propDest) return family; else return null; } }