001/*
002 * SVG Salamander
003 * Copyright (c) 2004, Mark McKay
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or 
007 * without modification, are permitted provided that the following
008 * conditions are met:
009 *
010 *   - Redistributions of source code must retain the above 
011 *     copyright notice, this list of conditions and the following
012 *     disclaimer.
013 *   - Redistributions in binary form must reproduce the above
014 *     copyright notice, this list of conditions and the following
015 *     disclaimer in the documentation and/or other materials 
016 *     provided with the distribution.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
019 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
020 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
021 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
022 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
023 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
025 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
026 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
029 * OF THE POSSIBILITY OF SUCH DAMAGE. 
030 * 
031 * Mark McKay can be contacted at mark@kitfox.com.  Salamander and other
032 * projects can be found at http://www.kitfox.com
033 *
034 * Created on February 20, 2004, 10:00 PM
035 */
036package com.kitfox.svg;
037
038import com.kitfox.svg.xml.StyleAttribute;
039import java.util.HashMap;
040
041/**
042 * Implements an embedded font.
043 *
044 * SVG specification: http://www.w3.org/TR/SVG/fonts.html
045 *
046 * @author Mark McKay
047 * @author <a href="mailto:mark@kitfox.com">Mark McKay</a>
048 */
049public class Font extends SVGElement
050{
051
052    public static final String TAG_NAME = "font";
053    int horizOriginX = 0;
054    int horizOriginY = 0;
055    int horizAdvX = -1;  //Must be specified
056    int vertOriginX = -1;  //Defaults to horizAdvX / 2
057    int vertOriginY = -1;  //Defaults to font's ascent
058    int vertAdvY = -1;  //Defaults to one 'em'.  See font-face
059    FontFace fontFace = null;
060    MissingGlyph missingGlyph = null;
061    final HashMap<String, SVGElement> glyphs = new HashMap<String, SVGElement>();
062
063    /**
064     * Creates a new instance of Font
065     */
066    public Font()
067    {
068    }
069
070    @Override
071    public String getTagName()
072    {
073        return TAG_NAME;
074    }
075
076    /**
077     * Called after the start element but before the end element to indicate
078     * each child tag that has been processed
079     */
080    @Override
081    public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException
082    {
083        super.loaderAddChild(helper, child);
084
085        if (child instanceof Glyph)
086        {
087            glyphs.put(((Glyph) child).getUnicode(), child);
088        } else if (child instanceof MissingGlyph)
089        {
090            missingGlyph = (MissingGlyph) child;
091        } else if (child instanceof FontFace)
092        {
093            fontFace = (FontFace) child;
094        }
095    }
096
097    @Override
098    public void loaderEndElement(SVGLoaderHelper helper) throws SVGParseException
099    {
100        super.loaderEndElement(helper);
101
102        //build();
103
104        helper.universe.registerFont(this);
105    }
106
107    @Override
108    protected void build() throws SVGException
109    {
110        super.build();
111
112        StyleAttribute sty = new StyleAttribute();
113
114        if (getPres(sty.setName("horiz-origin-x")))
115        {
116            horizOriginX = sty.getIntValue();
117        }
118
119        if (getPres(sty.setName("horiz-origin-y")))
120        {
121            horizOriginY = sty.getIntValue();
122        }
123
124        if (getPres(sty.setName("horiz-adv-x")))
125        {
126            horizAdvX = sty.getIntValue();
127        }
128
129        if (getPres(sty.setName("vert-origin-x")))
130        {
131            vertOriginX = sty.getIntValue();
132        }
133
134        if (getPres(sty.setName("vert-origin-y")))
135        {
136            vertOriginY = sty.getIntValue();
137        }
138
139        if (getPres(sty.setName("vert-adv-y")))
140        {
141            vertAdvY = sty.getIntValue();
142        }
143    }
144
145    public FontFace getFontFace()
146    {
147        return fontFace;
148    }
149
150    public void setFontFace(FontFace face)
151    {
152        fontFace = face;
153    }
154
155    public MissingGlyph getGlyph(String unicode)
156    {
157        Glyph retVal = (Glyph) glyphs.get(unicode);
158        if (retVal == null)
159        {
160            return missingGlyph;
161        }
162        return retVal;
163    }
164
165    public int getHorizOriginX()
166    {
167        return horizOriginX;
168    }
169
170    public int getHorizOriginY()
171    {
172        return horizOriginY;
173    }
174
175    public int getHorizAdvX()
176    {
177        return horizAdvX;
178    }
179
180    public int getVertOriginX()
181    {
182        if (vertOriginX != -1)
183        {
184            return vertOriginX;
185        }
186        vertOriginX = getHorizAdvX() / 2;
187        return vertOriginX;
188    }
189
190    public int getVertOriginY()
191    {
192        if (vertOriginY != -1)
193        {
194            return vertOriginY;
195        }
196        vertOriginY = fontFace.getAscent();
197        return vertOriginY;
198    }
199
200    public int getVertAdvY()
201    {
202        if (vertAdvY != -1)
203        {
204            return vertAdvY;
205        }
206        vertAdvY = fontFace.getUnitsPerEm();
207        return vertAdvY;
208    }
209
210    /**
211     * Updates all attributes in this diagram associated with a time event. Ie,
212     * all attributes with track information.
213     *
214     * @return - true if this node has changed state as a result of the time
215     * update
216     */
217    @Override
218    public boolean updateTime(double curTime) throws SVGException
219    {
220        //Fonts can't change
221        return false;
222        /*
223         if (trackManager.getNumTracks() == 0) return false;
224        
225         //Get current values for parameters
226         StyleAttribute sty = new StyleAttribute();
227         boolean stateChange = false;
228        
229         if (getPres(sty.setName("horiz-origin-x")))
230         {
231         int newVal = sty.getIntValue();
232         if (newVal != horizOriginX)
233         {
234         horizOriginX = newVal;
235         stateChange = true;
236         }
237         }
238        
239         if (getPres(sty.setName("horiz-origin-y")))
240         {
241         int newVal = sty.getIntValue();
242         if (newVal != horizOriginY)
243         {
244         horizOriginY = newVal;
245         stateChange = true;
246         }
247         }
248        
249         if (getPres(sty.setName("horiz-adv-x")))
250         {
251         int newVal = sty.getIntValue();
252         if (newVal != horizAdvX)
253         {
254         horizAdvX = newVal;
255         stateChange = true;
256         }
257         }
258        
259         if (getPres(sty.setName("vert-origin-x")))
260         {
261         int newVal = sty.getIntValue();
262         if (newVal != vertOriginX)
263         {
264         vertOriginX = newVal;
265         stateChange = true;
266         }
267         }
268        
269         if (getPres(sty.setName("vert-origin-y")))
270         {
271         int newVal = sty.getIntValue();
272         if (newVal != vertOriginY)
273         {
274         vertOriginY = newVal;
275         stateChange = true;
276         }
277         }
278        
279         if (getPres(sty.setName("vert-adv-y")))
280         {
281         int newVal = sty.getIntValue();
282         if (newVal != vertAdvY)
283         {
284         vertAdvY = newVal;
285         stateChange = true;
286         }
287         }
288        
289         return shapeChange;
290         */
291    }
292}