* @throws PropertyException For an invalid property value.
*/
private PropertyValue createPropertyValue(final FObj fobj,
final String propertyFullName, final String value)
throws PropertyException {
final PropertyCollection collection = new PropertyCollection();
final PropertyValue pv = checkKeywords(this.getValidKeywords(), value);
if (pv != null) {
collection.addItem(new PdFontStyle(pv));
collection.addItem(new PdFontVariant(pv));
collection.addItem(new PdFontWeight(pv));
collection.addItem(new PdFontSize(pv));
collection.addItem(new PdLineHeight(pv));
collection.addItem(new PdFontFamily(pv));
/*
* In addition to the properties explicitly set, font-stretch and
* font-size-adjust are set to their initial values by the "font"
* shorthand. They do *not* pick up the "inherit" from the "font"
* shorthand.
*/
return collection;
}
// There are 6 properties which can be explicitly set
final byte maxTokens = 6;
// Tokenize the input & put the tokens into an ArrayList
final StringTokenizer st = new StringTokenizer(value);
final List<String> tokenList = new ArrayList<String>(st.countTokens());
while (st.hasMoreTokens()) {
final String token = st.nextToken();
final int slashIndex = token.indexOf("/");
/*
* If the slash is the first character, it is just a normal token.
* If it is past the first character, we want to split the token
* into two pieces.
* TODO: This needs to be enhanced to see if the the slash is quoted
* or escaped, in which case, the token should not be split.
*/
if (slashIndex > 0) {
tokenList.add(token.substring(0, slashIndex));
tokenList.add(token.substring(slashIndex));
} else {
tokenList.add(token);
}
tokenList.add(token);
}
if (tokenList.size() < 1 || tokenList.size() > maxTokens) {
throw unexpectedValue(value, fobj);
}
// Create an array indicating which property is in each position
final FoProperty[] positionArray = new FoProperty[tokenList.size()];
for (int i = 0; i < tokenList.size(); i++) {
final FoProperty contentType = getContentType(tokenList.get(i));
if (contentType == null) {
throw unexpectedValue(value, fobj);
}
positionArray[i] = contentType;
}
boolean styleFound = false;
boolean variantFound = false;
boolean weightFound = false;
boolean sizeFound = false;
boolean lineHeightFound = false;
boolean familyFound = false;
for (int i = 0; i < positionArray.length; i++) {
switch (positionArray[i]) {
case FONT_STYLE: {
if (styleFound || sizeFound || lineHeightFound || familyFound) {
throw unexpectedValue(value, fobj);
}
collection.addItem(new PdFontStyle(fobj,
propertyFullName, tokenList.get(i)));
styleFound = true;
break;
}
case FONT_VARIANT: {
if (variantFound || sizeFound || lineHeightFound
|| familyFound) {
throw unexpectedValue(value, fobj);
}
collection.addItem(new PdFontVariant(fobj,
propertyFullName, tokenList.get(i)));
variantFound = true;
break;
}
case FONT_WEIGHT: {
if (weightFound || sizeFound || lineHeightFound
|| familyFound) {
throw unexpectedValue(value, fobj);
}
collection.addItem(new PdFontWeight(fobj,
propertyFullName, tokenList.get(i)));
weightFound = true;
break;
}
case FONT_SIZE: {
if (sizeFound || lineHeightFound || familyFound) {
throw unexpectedValue(value, fobj);
}
collection.addItem(new PdFontSize(fobj,
propertyFullName, tokenList.get(i)));
sizeFound = true;
break;
}
case LINE_HEIGHT: {
if (lineHeightFound || familyFound || ! sizeFound) {
throw unexpectedValue(value, fobj);
}
// Strip the leading "/" character.
final String adjustedToken
= tokenList.get(i).substring(1);
collection.addItem(new PdLineHeight(fobj,
propertyFullName, adjustedToken));
lineHeightFound = true;
break;
}
case FONT_FAMILY: {
if (familyFound || ! sizeFound) {
throw unexpectedValue(value, fobj);
}
collection.addItem(new PdFontFamily(fobj,
propertyFullName, tokenList.get(i)));
familyFound = true;
break;
}
}