/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.flex.compiler.internal.fxg.dom; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.apache.flex.compiler.fxg.FXGConstants.*; import org.apache.flex.compiler.fxg.dom.IFXGNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.AbstractRichTextNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.BRNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.DivNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.ImgNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.LinkNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.ParagraphNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.SpanNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.TCYNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.TabNode; import org.apache.flex.compiler.internal.fxg.dom.richtext.TextHelper; import org.apache.flex.compiler.internal.fxg.dom.richtext.TextLayoutFormatNode; import org.apache.flex.compiler.internal.fxg.dom.types.AlignmentBaseline; import org.apache.flex.compiler.internal.fxg.dom.types.BaselineOffset; import org.apache.flex.compiler.internal.fxg.dom.types.BaselineShift; import org.apache.flex.compiler.internal.fxg.dom.types.BlockProgression; import org.apache.flex.compiler.internal.fxg.dom.types.BreakOpportunity; import org.apache.flex.compiler.internal.fxg.dom.types.ColorWithEnum; import org.apache.flex.compiler.internal.fxg.dom.types.DigitCase; import org.apache.flex.compiler.internal.fxg.dom.types.DigitWidth; import org.apache.flex.compiler.internal.fxg.dom.types.Direction; import org.apache.flex.compiler.internal.fxg.dom.types.DominantBaseline; import org.apache.flex.compiler.internal.fxg.dom.types.FontStyle; import org.apache.flex.compiler.internal.fxg.dom.types.FontWeight; import org.apache.flex.compiler.internal.fxg.dom.types.JustificationRule; import org.apache.flex.compiler.internal.fxg.dom.types.JustificationStyle; import org.apache.flex.compiler.internal.fxg.dom.types.Kerning; import org.apache.flex.compiler.internal.fxg.dom.types.LeadingModel; import org.apache.flex.compiler.internal.fxg.dom.types.LigatureLevel; import org.apache.flex.compiler.internal.fxg.dom.types.LineBreak; import org.apache.flex.compiler.internal.fxg.dom.types.NumberAuto; import org.apache.flex.compiler.internal.fxg.dom.types.NumberInherit; import org.apache.flex.compiler.internal.fxg.dom.types.TextAlign; import org.apache.flex.compiler.internal.fxg.dom.types.TextDecoration; import org.apache.flex.compiler.internal.fxg.dom.types.TextJustify; import org.apache.flex.compiler.internal.fxg.dom.types.TextRotation; import org.apache.flex.compiler.internal.fxg.dom.types.TypographicCase; import org.apache.flex.compiler.internal.fxg.dom.types.VerticalAlign; import org.apache.flex.compiler.internal.fxg.dom.types.WhiteSpaceCollapse; import org.apache.flex.compiler.internal.fxg.dom.types.BaselineOffset.BaselineOffsetAsEnum; import org.apache.flex.compiler.internal.fxg.dom.types.BaselineShift.BaselineShiftAsEnum; import org.apache.flex.compiler.internal.fxg.dom.types.ColorWithEnum.ColorEnum; import org.apache.flex.compiler.internal.fxg.dom.types.NumberAuto.NumberAutoAsEnum; import org.apache.flex.compiler.internal.fxg.dom.types.NumberInherit.NumberInheritAsEnum; import org.apache.flex.compiler.problems.FXGContentNotContiguousProblem; import org.apache.flex.compiler.problems.FXGInvalidChildNodeProblem; import org.apache.flex.compiler.problems.FXGMissingAttributeProblem; import org.apache.flex.compiler.problems.FXGMultipleElementProblem; import org.apache.flex.compiler.problems.FXGUnknownAttributeValueProblem; import org.apache.flex.compiler.problems.ICompilerProblem; /** * Represents a <RichText> element of an FXG Document. */ public class RichTextNode extends GraphicContentNode implements ITextNode { protected static final double FONTSIZE_MIN_INCLUSIVE = 1.0; protected static final double FONTSIZE_MAX_INCLUSIVE = 720.0; protected static final double PADDING_MIN_INCLUSIVE = 0.0; protected static final double PADDING_MAX_INCLUSIVE = 1000.0; protected static final double BASELINEOFFSET_MIN_INCLUSIVE = 0.0; protected static final double BASELINEOFFSET_MAX_INCLUSIVE = 1000.0; protected static final double BASELINESHIFT_MIN_INCLUSIVE = -1000.0; protected static final double BASELINESHIFT_MAX_INCLUSIVE = 1000.0; protected static final int COLUMNCOUNT_MIN_INCLUSIVE = 0; protected static final int COLUMNCOUNT_MAX_INCLUSIVE = 50; protected static final double COLUMNGAP_MIN_INCLUSIVE = 0.0; protected static final double COLUMNGAP_MAX_INCLUSIVE = 1000.0; protected static final double COLUMNWIDTH_MIN_INCLUSIVE = 0.0; protected static final double COLUMNWIDTH_MAX_INCLUSIVE = 8000.0; protected static final double LINEHEIGHT_PERCENT_MIN_INCLUSIVE = -1000.0; protected static final double LINEHEIGHT_PERCENT_MAX_INCLUSIVE = 1000.0; protected static final double LINEHEIGHT_PIXEL_MIN_INCLUSIVE = -720.0; protected static final double LINEHEIGHT_PIXEL_MAX_INCLUSIVE = 720.0; protected static final double PARAGRAPH_INDENT_MIN_INCLUSIVE = 0.0; protected static final double PARAGRAPH_INDENT_MAX_INCLUSIVE = 1000.00; protected static final double PARAGRAPH_SPACE_MIN_INCLUSIVE = 0.0; protected static final double PARAGRAPH_SPACE_MAX_INCLUSIVE = 1000.00; protected static final double TEXTINDENT_MIN_INCLUSIVE = -1000.0; protected static final double TEXTINDENT_MAX_INCLUSIVE = 1000.0; protected static final double TRACKING_MIN_INCLUSIVE = -1000.0; protected static final double TRACKING_MAX_INCLUSIVE = 1000.0; //-------------------------------------------------------------------------- // // Attributes // //-------------------------------------------------------------------------- public double width = 0.0; public double height = 0.0; // Text Flow Attributes public BlockProgression blockProgression = BlockProgression.TB; public NumberInherit paddingLeft = NumberInherit.newInstance(0.0); public NumberInherit paddingRight = NumberInherit.newInstance(0.0); public NumberInherit paddingTop = NumberInherit.newInstance(0.0); public NumberInherit paddingBottom = NumberInherit.newInstance(0.0); public LineBreak lineBreak = LineBreak.TOFIT; public NumberInherit columnGap = NumberInherit.newInstance(20.0); public NumberAuto columnCount = NumberAuto.newInstance(NumberAutoAsEnum.AUTO); public NumberAuto columnWidth = NumberAuto.newInstance(NumberAutoAsEnum.AUTO); public BaselineOffset firstBaselineOffset = BaselineOffset.newInstance(BaselineOffsetAsEnum.AUTO); public VerticalAlign verticalAlign = VerticalAlign.TOP; // Paragraph Attributes public TextAlign textAlign = TextAlign.START; public TextAlign textAlignLast = TextAlign.START; public double textIndent = 0.0; public double paragraphStartIndent = 0.0; public double paragraphEndIndent = 0.0; public double paragraphSpaceBefore = 0.0; public double paragraphSpaceAfter = 0.0; public Direction direction = Direction.LTR; public JustificationRule justificationRule = JustificationRule.AUTO; public JustificationStyle justificationStyle = JustificationStyle.PRIORITIZELEASTADJUSTMENT; public TextJustify textJustify = TextJustify.INTERWORD; public LeadingModel leadingModel = LeadingModel.AUTO; public String tabStops = ""; // Text Leaf Attributes public String fontFamily = "Arial"; public double fontSize = 12.0; public FontStyle fontStyle = FontStyle.NORMAL; public FontWeight fontWeight = FontWeight.NORMAL; public Kerning kerning = Kerning.AUTO; public double lineHeight = 120.0; public TextDecoration textDecoration = TextDecoration.NONE; public boolean lineThrough = false; public int color = AbstractFXGNode.COLOR_BLACK; public double textAlpha = 1.0; public WhiteSpaceCollapse whiteSpaceCollapse = WhiteSpaceCollapse.COLLAPSE; public NumberInherit backgroundAlpha = NumberInherit.newInstance(1.0);; public ColorWithEnum backgroundColor = ColorWithEnum.newInstance(ColorEnum.TRANSPARENT); public BaselineShift baselineShift = BaselineShift.newInstance(0.0); public BreakOpportunity breakOpportunity = BreakOpportunity.AUTO; public DigitCase digitCase = DigitCase.DEFAULT; public DigitWidth digitWidth = DigitWidth.DEFAULT; public DominantBaseline dominantBaseline = DominantBaseline.AUTO; public AlignmentBaseline alignmentBaseline = AlignmentBaseline.USEDOMINANTBASELINE; public LigatureLevel ligatureLevel = LigatureLevel.COMMON; public String locale = "en"; public TypographicCase typographicCase = TypographicCase.DEFAULT; public double trackingLeft = 0.0; public double trackingRight = 0.0; public TextRotation textRotation = TextRotation.AUTO; // Link format properties public TextLayoutFormatNode linkNormalFormat = null; public TextLayoutFormatNode linkHoverFormat = null; public TextLayoutFormatNode linkActiveFormat = null; private boolean contiguous = false; //-------------------------------------------------------------------------- // // ITextNode Helpers // //-------------------------------------------------------------------------- /** * The attributes set on this node. */ protected Map<String, String> textAttributes; /** * @return A Map recording the attribute names and values set on this * text node. */ @Override public Map<String, String> getTextAttributes() { return textAttributes; } /** * This node's child text nodes. */ protected List<ITextNode> content; /** * @return The List of child nodes of this text node. */ @Override public List<ITextNode> getTextChildren() { return content; } /** * This node's child property nodes. */ protected Map<String, ITextNode> properties; /** * @return The List of child property nodes of this text node. */ @Override public Map<String, ITextNode> getTextProperties() { return properties; } /** * A RichText node can also have special child property nodes that represent * complex property values that cannot be set via a simple attribute. */ @Override public void addTextProperty(String propertyName, ITextNode node, Collection<ICompilerProblem> problems) { if (node instanceof TextLayoutFormatNode) { if (FXG_LINKACTIVEFORMAT_PROPERTY_ELEMENT.equals(propertyName)) { if (linkActiveFormat == null) { linkActiveFormat = (TextLayoutFormatNode)node; linkActiveFormat.setParent(this); if (properties == null) properties = new HashMap<String, ITextNode>(3); properties.put(propertyName, linkActiveFormat); } else { // Multiple LinkFormat elements are not allowed. problems.add(new FXGMultipleElementProblem(getDocumentPath(), getStartLine(), getStartColumn(), propertyName)); } } else if (FXG_LINKHOVERFORMAT_PROPERTY_ELEMENT.equals(propertyName)) { if (linkHoverFormat == null) { linkHoverFormat = (TextLayoutFormatNode)node; linkHoverFormat.setParent(this); if (properties == null) properties = new HashMap<String, ITextNode>(3); properties.put(propertyName, linkHoverFormat); } else { // Multiple LinkFormat elements are not allowed. problems.add(new FXGMultipleElementProblem(getDocumentPath(), getStartLine(), getStartColumn(), propertyName)); } } else if (FXG_LINKNORMALFORMAT_PROPERTY_ELEMENT.equals(propertyName)) { if (linkNormalFormat == null) { linkNormalFormat = (TextLayoutFormatNode)node; linkNormalFormat.setParent(this); if (properties == null) properties = new HashMap<String, ITextNode>(3); properties.put(propertyName, linkNormalFormat); } else { // Multiple LinkFormat elements are not allowed. problems.add(new FXGMultipleElementProblem(getDocumentPath(), getStartLine(), getStartColumn(), propertyName)); } } else { // Unknown LinkFormat element. problems.add(new FXGUnknownAttributeValueProblem(getDocumentPath(), node.getStartLine(), node.getStartColumn(), node.getNodeName(), propertyName)); } } else { addChild(node, problems); } } /** * <RichText> content allows child <p>, <span> and * <br /> tags, as well as character data (text content). * * @param child - a child FXG node to be added to this node. * @param problems problem collection used to collect problems occurred within this method */ public void addContentChild(IFXGNode child, Collection<ICompilerProblem> problems) { if (child instanceof ParagraphNode || child instanceof DivNode || child instanceof SpanNode || child instanceof BRNode || child instanceof TabNode || child instanceof TCYNode || child instanceof LinkNode || child instanceof ImgNode || child instanceof CDATANode) { if (child instanceof LinkNode && (((LinkNode)child).href == null)) { //Missing href attribute in <a> element. problems.add(new FXGMissingAttributeProblem(getDocumentPath(), getStartLine(), getStartColumn(), FXG_HREF_ATTRIBUTE, child.getNodeName())); return; } if (content == null) { content = new ArrayList<ITextNode>(); contiguous = true; } if (!contiguous) { problems.add(new FXGContentNotContiguousProblem(child.getDocumentPath(), child.getStartLine(), child.getStartColumn(), getNodeName())); return; } content.add((ITextNode)child); } else { problems.add(new FXGInvalidChildNodeProblem(child.getDocumentPath(), child.getStartLine(), child.getStartColumn(), child.getNodeName(), getNodeName())); return; } if (child instanceof AbstractRichTextNode) ((AbstractRichTextNode)child).setParent(this); } /** * Remember that an attribute was set on this node. * * @param name - the unqualified attribute name. * @param value - the attribute value. */ protected void rememberAttribute(String name, String value) { if (textAttributes == null) textAttributes = new HashMap<String, String>(4); textAttributes.put(name, value); } //-------------------------------------------------------------------------- // // IFXGNode Implementation // //-------------------------------------------------------------------------- /** * This method is invoked for only non-content children. * * @param child - a child FXG node to be added to this node. * @param problems problem collection used to collect problems occurred within this method */ @Override public void addChild(IFXGNode child, Collection<ICompilerProblem> problems) { if (child instanceof CDATANode) { if (TextHelper.ignorableWhitespace(((CDATANode)child).content)) { /** * Ignorable white spaces don't break content contiguous * rule and should be ignored. */ return; } else { problems.add(new FXGContentNotContiguousProblem(child.getDocumentPath(), child.getStartLine(), child.getStartColumn(), getNodeName())); return; } } else { super.addChild(child, problems); contiguous = false; return; } } @Override public List<IFXGNode> getChildren() { List<IFXGNode> children = new ArrayList<IFXGNode>(); children.addAll(super.getChildren()); if(content != null) children.addAll(content); if(getTextProperties() != null) { children.addAll(getTextProperties().values()); } return children; } /** * @return The unqualified name of a RichText node, without tag markup. */ @Override public String getNodeName() { return FXG_RICHTEXT_ELEMENT; } /** * Sets an FXG attribute on this RichText node. * * In addition to the attributes supported by all graphic content nodes, * RichText supports the following attributes. * * <p> * <ul> * <li><b>width</b> (Number): The width of the text box to render text * in.</li> * <li><b>height</b> (Number): The height of the text box to render text * in.</li> * <li><b>paddingLeft</b> (Number): Inset from left edge to content area. * Units in pixels, defaults to 0.</li> * <li><b>paddingRight</b> (Number): Inset from right edge to content area. * Units in pixels, defaults to 0.</li> * <li><b>paddingTop</b> (Number): Inset from top edge to content area. * Units in pixels, defaults to 0.</li> * <li><b>paddingBottom</b> (Number): Inset from bottom edge to content * area. Units in pixels, defaults to 0.</li> * </ul> * </p> * @param name - the unqualified attribute name. * @param value - the attribute value. */ @Override public void setAttribute(String name, String value, Collection<ICompilerProblem> problems) { if (FXG_WIDTH_ATTRIBUTE.equals(name)) { width = DOMParserHelper.parseDouble(this, value, name, width, problems); } else if (FXG_HEIGHT_ATTRIBUTE.equals(name)) { height = DOMParserHelper.parseDouble(this, value, name, height, problems); } else if (FXG_BLOCKPROGRESSION_ATTRIBUTE.equals(name)) { blockProgression = TextHelper.getBlockProgression(this, value, blockProgression, problems); } else if (FXG_PADDINGLEFT_ATTRIBUTE.equals(name)) { paddingLeft = getNumberInherit(this, name, value, PADDING_MIN_INCLUSIVE, PADDING_MAX_INCLUSIVE, paddingLeft.getNumberInheritAsDbl(), problems); } else if (FXG_PADDINGRIGHT_ATTRIBUTE.equals(name)) { paddingRight = getNumberInherit(this, name, value, PADDING_MIN_INCLUSIVE, PADDING_MAX_INCLUSIVE, paddingRight.getNumberInheritAsDbl(), problems); } else if (FXG_PADDINGTOP_ATTRIBUTE.equals(name)) { paddingTop = getNumberInherit(this, name, value, PADDING_MIN_INCLUSIVE, PADDING_MAX_INCLUSIVE, paddingTop.getNumberInheritAsDbl(), problems); } else if (FXG_PADDINGBOTTOM_ATTRIBUTE.equals(name)) { paddingBottom = getNumberInherit(this, name, value, PADDING_MIN_INCLUSIVE, PADDING_MAX_INCLUSIVE, paddingBottom.getNumberInheritAsDbl(), problems); } else if (FXG_LINEBREAK_ATTRIBUTE.equals(name)) { lineBreak = TextHelper.getLineBreak(this, value, lineBreak, problems); } else if (FXG_COLUMNGAP_ATTRIBUTE.equals(name)) { columnGap = getNumberInherit(this, name, value, COLUMNGAP_MIN_INCLUSIVE, COLUMNGAP_MAX_INCLUSIVE, columnGap.getNumberInheritAsDbl(), problems); } else if (FXG_COLUMNCOUNT_ATTRIBUTE.equals(name)) { columnCount = getNumberAutoInt(this, name, value, COLUMNCOUNT_MIN_INCLUSIVE, COLUMNCOUNT_MAX_INCLUSIVE, columnCount.getNumberAutoAsInt(), problems); } else if (FXG_COLUMNWIDTH_ATTRIBUTE.equals(name)) { columnWidth = getNumberAutoDbl(this, name, value, COLUMNWIDTH_MIN_INCLUSIVE, COLUMNWIDTH_MAX_INCLUSIVE, columnWidth.getNumberAutoAsDbl(), problems); } else if (FXG_FIRSTBASELINEOFFSET_ATTRIBUTE.equals(name)) { firstBaselineOffset = getFirstBaselineOffset(this, name, value, BASELINEOFFSET_MIN_INCLUSIVE, BASELINEOFFSET_MAX_INCLUSIVE, firstBaselineOffset.getBaselineOffsetAsDbl(), problems); } else if (FXG_VERTICALALIGN_ATTRIBUTE.equals(name)) { verticalAlign = TextHelper.getVerticalAlign(this, value, verticalAlign, problems); } else if (FXG_TEXTALIGN_ATTRIBUTE.equals(name)) { textAlign = TextHelper.getTextAlign(this, value, textAlign, problems); } else if (FXG_TEXTALIGNLAST_ATTRIBUTE.equals(name)) { textAlignLast = TextHelper.getTextAlign(this, value, textAlignLast, problems); } else if (FXG_TEXTINDENT_ATTRIBUTE.equals(name)) { textIndent = DOMParserHelper.parseDouble(this, value, name, TEXTINDENT_MIN_INCLUSIVE, TEXTINDENT_MAX_INCLUSIVE, textIndent, problems); } else if (FXG_PARAGRAPHSTARTINDENT_ATTRIBUTE.equals(name)) { paragraphStartIndent = DOMParserHelper.parseDouble(this, value, name, PARAGRAPH_INDENT_MIN_INCLUSIVE, PARAGRAPH_INDENT_MAX_INCLUSIVE, paragraphStartIndent, problems); } else if (FXG_PARAGRAPHENDINDENT_ATTRIBUTE.equals(name)) { paragraphEndIndent = DOMParserHelper.parseDouble(this, value, name, PARAGRAPH_INDENT_MIN_INCLUSIVE, PARAGRAPH_INDENT_MAX_INCLUSIVE, paragraphEndIndent, problems); } else if (FXG_PARAGRAPHSPACEBEFORE_ATTRIBUTE.equals(name)) { paragraphSpaceBefore = DOMParserHelper.parseDouble(this, value, name, PARAGRAPH_SPACE_MIN_INCLUSIVE, PARAGRAPH_SPACE_MAX_INCLUSIVE, paragraphSpaceBefore, problems); } else if (FXG_PARAGRAPHSPACEAFTER_ATTRIBUTE.equals(name)) { paragraphSpaceAfter = DOMParserHelper.parseDouble(this, value, name, PARAGRAPH_SPACE_MIN_INCLUSIVE, PARAGRAPH_SPACE_MAX_INCLUSIVE, paragraphSpaceAfter, problems); } else if (FXG_DIRECTION_ATTRIBUTE.equals(name)) { direction = TextHelper.getDirection(this, value, direction, problems); } else if (FXG_JUSTIFICATIONRULE_ATTRIBUTE.equals(name)) { justificationRule = TextHelper.getJustificationRule(this, value, justificationRule, problems); } else if (FXG_JUSTIFICATIONSTYLE_ATTRIBUTE.equals(name)) { justificationStyle = TextHelper.getJustificationStyle(this, value, justificationStyle, problems); } else if (FXG_TEXTJUSTIFY_ATTRIBUTE.equals(name)) { textJustify = TextHelper.getTextJustify(this, value, textJustify, problems); } else if (FXG_LEADINGMODEL_ATTRIBUTE.equals(name)) { leadingModel = TextHelper.getLeadingModel(this, value, leadingModel, problems); } else if (FXG_TABSTOPS_ATTRIBUTE.equals(name)) { tabStops = TextHelper.parseTabStops(this, value, tabStops, problems); } else if (FXG_FONTFAMILY_ATTRIBUTE.equals(name)) { fontFamily = value; } else if (FXG_FONTSIZE_ATTRIBUTE.equals(name)) { fontSize = DOMParserHelper.parseDouble(this, value, name, FONTSIZE_MIN_INCLUSIVE, FONTSIZE_MAX_INCLUSIVE, fontSize, problems); } else if (FXG_FONTSTYLE_ATTRIBUTE.equals(name)) { fontStyle = TextHelper.getFontStyle(this, value, fontStyle, problems); } else if (FXG_FONTWEIGHT_ATTRIBUTE.equals(name)) { fontWeight = TextHelper.getFontWeight(this, value, fontWeight, problems); } else if (FXG_KERNING_ATTRIBUTE.equals(name)) { kerning = TextHelper.getKerning(this, value, kerning, problems); } else if (FXG_LINEHEIGHT_ATTRIBUTE.equals(name)) { lineHeight = DOMParserHelper.parseNumberPercentWithSeparateRange(this, value, name, LINEHEIGHT_PIXEL_MIN_INCLUSIVE, LINEHEIGHT_PIXEL_MAX_INCLUSIVE, LINEHEIGHT_PERCENT_MIN_INCLUSIVE, LINEHEIGHT_PERCENT_MAX_INCLUSIVE, lineHeight, problems); } else if (FXG_TEXTDECORATION_ATTRIBUTE.equals(name)) { textDecoration = TextHelper.getTextDecoration(this, value, textDecoration, problems); } else if ( FXG_LINETHROUGH_ATTRIBUTE.equals(name)) { lineThrough = DOMParserHelper.parseBoolean(this, value, name, lineThrough, problems); } else if (FXG_COLOR_ATTRIBUTE.equals(name)) { color = DOMParserHelper.parseRGB(this, value, name, color, problems); } else if (FXG_TEXTALPHA_ATTRIBUTE.equals(name)) { textAlpha = DOMParserHelper.parseDouble(this, value, name, ALPHA_MIN_INCLUSIVE, ALPHA_MAX_INCLUSIVE, textAlpha, problems); } else if (FXG_WHITESPACECOLLAPSE_ATTRIBUTE.equals(name)) { whiteSpaceCollapse = TextHelper.getWhiteSpaceCollapse(this, value, whiteSpaceCollapse, problems); } else if (FXG_BACKGROUNDALPHA_ATTRIBUTE.equals(name)) { backgroundAlpha = getAlphaInherit(this, name, value, ALPHA_MIN_INCLUSIVE, ALPHA_MAX_INCLUSIVE, backgroundAlpha.getNumberInheritAsDbl(), problems); } else if (FXG_BACKGROUNDCOLOR_ATTRIBUTE.equals(name)) { backgroundColor = getColorWithEnum(this, name, value, backgroundColor.getColorWithEnumAsString(), problems); } else if (FXG_BASELINESHIFT_ATTRIBUTE.equals(name)) { baselineShift = getBaselineShift(this, name, value, BASELINESHIFT_MIN_INCLUSIVE, BASELINESHIFT_MAX_INCLUSIVE, baselineShift.getBaselineShiftAsDbl(), problems); } else if (FXG_BREAKOPPORTUNITY_ATTRIBUTE.equals(name)) { breakOpportunity = TextHelper.getBreakOpportunity(this, value, breakOpportunity, problems); } else if (FXG_DIGITCASE_ATTRIBUTE.equals(name)) { digitCase = TextHelper.getDigitCase(this, value, digitCase, problems); } else if (FXG_DIGITWIDTH_ATTRIBUTE.equals(name)) { digitWidth = TextHelper.getDigitWidth(this, value, digitWidth, problems); } else if (FXG_DOMINANTBASELINE_ATTRIBUTE.equals(name)) { dominantBaseline = TextHelper.getDominantBaseline(this, value, dominantBaseline, problems); } else if (FXG_ALIGNMENTBASELINE_ATTRIBUTE.equals(name)) { alignmentBaseline = TextHelper.getAlignmentBaseline(this, value, alignmentBaseline, problems); } else if (FXG_LIGATURELEVEL_ATTRIBUTE.equals(name)) { ligatureLevel = TextHelper.getLigatureLevel(this, value, ligatureLevel, problems); } else if (FXG_LOCALE_ATTRIBUTE.equals(name)) { locale = value; } else if (FXG_TYPOGRAPHICCASE_ATTRIBUTE.equals(name)) { typographicCase = TextHelper.getTypographicCase(this, value, typographicCase, problems); } else if (FXG_TRACKINGLEFT_ATTRIBUTE.equals(name)) { trackingLeft = DOMParserHelper.parseNumberPercent(this, value, name, TRACKING_MIN_INCLUSIVE, TRACKING_MAX_INCLUSIVE, trackingLeft, problems); } else if (FXG_TRACKINGRIGHT_ATTRIBUTE.equals(name)) { trackingRight = DOMParserHelper.parseNumberPercent(this, value, name, TRACKING_MIN_INCLUSIVE, TRACKING_MAX_INCLUSIVE, trackingRight, problems); } else if (FXG_TEXTROTATION_ATTRIBUTE.equals(name)) { textRotation = TextHelper.getTextRotation(this, value, textRotation, problems); } else if (FXG_ID_ATTRIBUTE.equals(name)) { //id = value; } else { super.setAttribute(name, value, problems); } // Remember that this attribute was set on this node. rememberAttribute(name, value); } //-------------------------------------------------------------------------- // // Helper Methods // //-------------------------------------------------------------------------- /** * Convert an FXG String value to a BaselineOffset object. * * @param value - the FXG String value. * @param name - the FXG attribute name. * @param min - the smallest double value that the result must be greater * or equal to. * @param max - the largest double value that the result must be smaller * than or equal to. * @param defaultValue - the default double value; if the encountered minor * version is later than the supported minor version and the attribute value * is out-of-range, the default value is returned. * @param problems problem collection used to collect problems occurred within this method * @return the matching BaselineOffset rule. */ private BaselineOffset getFirstBaselineOffset(IFXGNode node, String name, String value, double min, double max, double defaultValue, Collection<ICompilerProblem> problems) { if (FXG_BASELINEOFFSET_AUTO_VALUE.equals(value)) { return BaselineOffset.newInstance(BaselineOffsetAsEnum.AUTO); } else if (FXG_BASELINEOFFSET_ASCENT_VALUE.equals(value)) { return BaselineOffset.newInstance(BaselineOffsetAsEnum.ASCENT); } else if (FXG_BASELINEOFFSET_LINEHEIGHT_VALUE.equals(value)) { return BaselineOffset.newInstance(BaselineOffsetAsEnum.LINEHEIGHT); } else { try { return BaselineOffset.newInstance(DOMParserHelper.parseDouble(this, value, min, max)); } catch(Exception e) { //Exception: Unknown first baseline offset: {0} problems.add(new FXGUnknownAttributeValueProblem(node.getDocumentPath(), node.getStartLine(), node.getStartColumn(), name, value)); return BaselineOffset.newInstance(defaultValue); } } } /** * Convert an FXG String value to a NumberAuto object. * * @param value - the FXG String value. * @param name - the FXG attribute name. * @param min - the smallest double value that the result must be greater * or equal to. * @param max - the largest double value that the result must be smaller * than or equal to. * @param defaultValue - the default double value; if the encountered minor * version is later than the supported minor version and the attribute value * is out-of-range, the default value is returned. * @param problems problem collection used to collect problems occurred within this method * @return the matching NumberAuto rule. */ private NumberAuto getNumberAutoDbl(IFXGNode node, String name, String value, double min, double max, double defaultValue, Collection<ICompilerProblem> problems) { try { return NumberAuto.newInstance(DOMParserHelper.parseDouble(this, value, min, max)); } catch(Exception e) { if (FXG_NUMBERAUTO_AUTO_VALUE.equals(value)) return NumberAuto.newInstance(NumberAutoAsEnum.AUTO); else if (FXG_INHERIT_VALUE.equals(value)) return NumberAuto.newInstance(NumberAutoAsEnum.INHERIT); //Exception: Unknown number auto: {0} problems.add(new FXGUnknownAttributeValueProblem(node.getDocumentPath(), node.getStartLine(), node.getStartColumn(), name, value)); return NumberAuto.newInstance(defaultValue); } } /** * Convert an FXG String value to a NumberAuto object. * * @param value - the FXG String value. * @param name - the FXG attribute name. * @param min - the smallest int value that the result must be greater * or equal to. * @param max - the largest int value that the result must be smaller * than or equal to. * @param defaultValue - the default int value; if the encountered minor * version is later than the supported minor version and the attribute value * is out-of-range, the default value is returned. * @param problems problem collection used to collect problems occurred within this method * @return the matching NumberAuto rule. */ private NumberAuto getNumberAutoInt(IFXGNode node, String name, String value, int min, int max, int defaultValue, Collection<ICompilerProblem> problems) { try { return NumberAuto.newInstance(DOMParserHelper.parseInt(this, value, min, max)); } catch(Exception e) { if (FXG_NUMBERAUTO_AUTO_VALUE.equals(value)) return NumberAuto.newInstance(NumberAutoAsEnum.AUTO); else if (FXG_INHERIT_VALUE.equals(value)) return NumberAuto.newInstance(NumberAutoAsEnum.INHERIT); //Exception: Unknown number auto: {0} problems.add(new FXGUnknownAttributeValueProblem(node.getDocumentPath(), node.getStartLine(), node.getStartColumn(), name, value)); return NumberAuto.newInstance(defaultValue); } } /** * Convert an FXG String value to a NumberInherit enumeration. * * @param value - the FXG String value. * @param name - the FXG attribute name. * @param min - the smallest double value that the result must be greater * or equal to. * @param max - the largest double value that the result must be smaller * than or equal to. * @param defaultValue - the default double value; if the encountered minor * version is later than the supported minor version and the attribute value * is out-of-range, the default value is returned. * @param problems problem collection used to collect problems occurred within this method * @return the matching NumberInherit rule. */ private NumberInherit getNumberInherit(IFXGNode node, String name, String value, double min, double max, double defaultValue, Collection<ICompilerProblem> problems) { try { return NumberInherit.newInstance(DOMParserHelper.parseDouble(this, value, min, max)); } catch(Exception e) { if (FXG_INHERIT_VALUE.equals(value)) return NumberInherit.newInstance(NumberInheritAsEnum.INHERIT); //Exception: Unknown number inherit: {0} problems.add(new FXGUnknownAttributeValueProblem(node.getDocumentPath(), node.getStartLine(), node.getStartColumn(), name, value)); return NumberInherit.newInstance(defaultValue); } } /** * Convert an FXG String value to a BaselineShift enumeration. * * @param value - the FXG String value. * @param name - the FXG attribute name. * @param min - the smallest double value that the result must be greater * or equal to. * @param max - the largest double value that the result must be smaller * than or equal to. * @param defaultValue - the default double value; if the encountered minor * version is later than the supported minor version and the attribute value * is out-of-range, the default value is returned. * @param problems problem collection used to collect problems occurred within this method * @return the matching BaselineShift rule. */ private BaselineShift getBaselineShift(IFXGNode node, String name, String value, double min, double max, double defaultValue, Collection<ICompilerProblem> problems) { try { return BaselineShift.newInstance(DOMParserHelper.parseNumberPercent(this, value, min, max)); } catch(Exception e) { if (FXG_BASELINESHIFT_SUPERSCRIPT_VALUE.equals(value)) { return BaselineShift.newInstance(BaselineShiftAsEnum.SUPERSCRIPT); } else if (FXG_BASELINESHIFT_SUBSCRIPT_VALUE.equals(value)) { return BaselineShift.newInstance(BaselineShiftAsEnum.SUBSCRIPT); } //Exception: Unknown baseline shift: {0} problems.add(new FXGUnknownAttributeValueProblem(node.getDocumentPath(), node.getStartLine(), node.getStartColumn(), name, value)); return BaselineShift.newInstance(defaultValue); } } /** * Convert an FXG String value to a NumberInherit object. * * @param value - the FXG String value. * @param name - the FXG attribute name. * @param min - the smallest double value that the result must be greater * or equal to. * @param max - the largest double value that the result must be smaller * than or equal to. * @param defaultValue - the default double value; if the encountered minor * version is later than the supported minor version and the attribute value * is out-of-range, the default value is returned. * @param problems problem collection used to collect problems occurred within this method * @return the matching NumberInherit rule. */ private NumberInherit getAlphaInherit(IFXGNode node, String name, String value, double min, double max, double defaultValue, Collection<ICompilerProblem> problems) { try { return NumberInherit.newInstance(DOMParserHelper.parseDouble(this, value, ALPHA_MIN_INCLUSIVE, ALPHA_MAX_INCLUSIVE)); } catch(Exception e) { if (FXG_INHERIT_VALUE.equals(value)) { return NumberInherit.newInstance(NumberInheritAsEnum.INHERIT); } //Exception: Unknown number inherit: {0} problems.add(new FXGUnknownAttributeValueProblem(node.getDocumentPath(), node.getStartLine(), node.getStartColumn(), name, value)); return NumberInherit.newInstance(defaultValue); } } /** * Convert an FXG String value to a NumberInherit object. * * @param node - the FXG node. * @param attribute - the FXG attribute name. * @param value - the FXG String value. * @param defaultValue - default color value * @param problems problem collection used to collect problems occurred within this method * @return the matching NumberInherit rule. */ private ColorWithEnum getColorWithEnum(IFXGNode node, String attribute, String value, int defaultValue, Collection<ICompilerProblem> problems) { if (FXG_COLORWITHENUM_TRANSPARENT_VALUE.equals(value)) { return ColorWithEnum.newInstance(ColorEnum.TRANSPARENT); } else if (FXG_INHERIT_VALUE.equals(value)) { return ColorWithEnum.newInstance(ColorEnum.INHERIT); } else { return ColorWithEnum.newInstance(DOMParserHelper.parseRGB(this, value, attribute, defaultValue, problems)); } } }