001/*
002 * $Id: ChainedProperties.java 4666 2011-01-29 12:53:09Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044package com.itextpdf.text.html.simpleparser;
045
046import java.util.ArrayList;
047import java.util.List;
048import java.util.Map;
049
050import com.itextpdf.text.html.HtmlTags;
051import com.itextpdf.text.html.HtmlUtilities;
052
053/**
054 * Stores the hierarchy of tags along with the attributes of each tag.
055 * @since 5.0.6 renamed from ChainedProperties
056 */
057public class ChainedProperties {
058
059        /**
060         * Class that stores the info about one tag in the chain.
061         */
062        private static final class TagAttributes {
063                /** A possible tag */
064            final String tag;
065            /** The styles corresponding with the tag */
066            final Map<String, String> attrs;
067            /**
068             * Constructs a chained property.
069             * @param   tag             an XML/HTML tag
070             * @param   attrs   the tag's attributes
071             */
072            TagAttributes(String tag, Map<String, String> attrs) {
073                this.tag = tag;
074                this.attrs = attrs;
075            }
076        }
077
078        /** A list of chained properties representing the tag hierarchy. */
079        public List<TagAttributes> chain = new ArrayList<TagAttributes>();
080
081        /** Creates a new instance of ChainedProperties */
082        public ChainedProperties() {
083        }
084
085        /**
086         * Walks through the hierarchy (bottom-up) looking for
087         * a property key. Returns a value as soon as a match
088         * is found or null if the key can't be found.
089         * @param       key     the key of the property
090         * @return      the value of the property
091         */
092        public String getProperty(String key) {
093                for (int k = chain.size() - 1; k >= 0; --k) {
094                        TagAttributes p = chain.get(k);
095                        Map<String, String> attrs = p.attrs;
096                        String ret = attrs.get(key);
097                        if (ret != null)
098                                return ret;
099                }
100                return null;
101        }
102        
103        /**
104         * Walks through the hierarchy (bottom-up) looking for
105         * a property key. Returns true as soon as a match is
106         * found or false if the key can't be found.
107         * @param       key     the key of the property
108         * @return      true if the key is found
109         */
110        public boolean hasProperty(String key) {
111                for (int k = chain.size() - 1; k >= 0; --k) {
112                        TagAttributes p = chain.get(k);
113                        Map<String, String> attrs = p.attrs;
114                        if (attrs.containsKey(key))
115                                return true;
116                }
117                return false;
118        }
119
120        /**
121         * Adds a tag and its corresponding properties to the chain.
122         * @param tag   the tags that needs to be added to the chain
123         * @param props the tag's attributes
124         */
125        public void addToChain(String tag, Map<String, String> props) {
126                this.adjustFontSize(props);
127                chain.add(new TagAttributes(tag, props));
128        }
129
130        /**
131         * Walks through the hierarchy (bottom-up) and removes the
132         * first occurrence of a tag that is encountered.
133         * @param       tag     the tag that needs to be removed
134         */
135        public void removeChain(String tag) {
136                for (int k = chain.size() - 1; k >= 0; --k) {
137                        if (tag.equals(chain.get(k).tag)) {
138                                chain.remove(k);
139                                return;
140                        }
141                }
142        }
143        
144        /**
145         * If the properties contain a font size, the size may need to
146         * be adjusted based on font sizes higher in the hierarchy.
147         * @param       attrs the attributes that may have to be updated
148         * @since 5.0.6 (renamed)
149         */
150        protected void adjustFontSize(Map<String, String> attrs) {
151                // fetch the font size
152                String value = attrs.get(HtmlTags.SIZE);
153                // do nothing if the font size isn't defined
154                if (value == null)
155                        return;
156                // the font is defined as a real size: remove "pt"
157                if (value.endsWith("pt")) {
158                        attrs.put(HtmlTags.SIZE,
159                                value.substring(0, value.length() - 2));
160                        return;
161                }
162                String old = getProperty(HtmlTags.SIZE);
163                attrs.put(HtmlTags.SIZE, Integer.toString(HtmlUtilities.getIndexedFontSize(value, old)));
164        }
165}