Package flex2.compiler.media

Source Code of flex2.compiler.media.FontTranscoder

/*
*
*  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 flex2.compiler.media;

import flash.css.LocalSource;
import flash.css.URLSource;
import flash.fonts.FontDescription;
import flash.fonts.FontFace;
import flash.fonts.FontManager;
import flash.swf.TagValues;
import flash.swf.tags.DefineFont;
import flash.util.Trace;
import flex2.compiler.ILocalizableMessage;
import flex2.compiler.SymbolTable;
import flex2.compiler.Transcoder;
import flex2.compiler.TranscoderException;
import flex2.compiler.common.CompilerConfiguration;
import flex2.compiler.common.Configuration;
import flex2.compiler.common.FontsConfiguration;
import flex2.compiler.common.MxmlConfiguration;
import flex2.compiler.common.PathResolver;
import flex2.compiler.io.FileUtil;
import flex2.compiler.io.LocalFile;
import flex2.compiler.io.VirtualFile;
import flex2.compiler.util.CompilerMessage;
import flex2.compiler.util.MimeMappings;
import flex2.compiler.util.ThreadLocalToolkit;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
* Transcodes fonts into DefineFont SWF tags for embedding.
*
* @author Roger Gonzalez
*/
public class FontTranscoder extends AbstractTranscoder
{
    private FontsConfiguration fontsConfig;
    private int compatibilityVersion;
    private boolean showShadowedDeviceFontWarnings;

    public FontTranscoder( Configuration config )
    {
        super(new String[]{MimeMappings.TTF, MimeMappings.OTF, MimeMappings.FONT, MimeMappings.TTC, MimeMappings.DFONT}, DefineFont.class, true);
        CompilerConfiguration compilerConfig = config.getCompilerConfiguration();
        fontsConfig = compilerConfig.getFontsConfiguration();
        compatibilityVersion = compilerConfig.getCompatibilityVersion();
        showShadowedDeviceFontWarnings = compilerConfig.showShadowedDeviceFontWarnings();
    }

    public static final String UNICODERANGE = "unicodeRange";
    public static final String SYSTEMFONT = "systemFont";
    public static final String SOURCELIST = "sourceList";
  public static final String FLASHTYPE = "flashType";
  public static final String ADVANTIALIASING = "advancedAntiAliasing";
  public static final String EMBEDASCFF = "embedAsCFF";

    public boolean isSupportedAttribute( String attr )
    {
        return FONTNAME.equals( attr )
               || FONTSTYLE.equals( attr )
               || FONTWEIGHT.equals( attr )
               || FONTFAMILY.equals( attr )
               || UNICODERANGE.equals( attr )
           || FLASHTYPE.equals( attr )           
           || ADVANTIALIASING.equals( attr )           
               || SYSTEMFONT.equals( attr )
               || SOURCELIST.equals( attr )
               || EMBEDASCFF.equals( attr );
    }

    public TranscodingResults doTranscode( PathResolver context, SymbolTable symbolTable,
                                           Map<String, Object> args, String className, boolean generateSource )
            throws TranscoderException
    {
        TranscodingResults results = new TranscodingResults();
        String systemFont = null;
        List<Serializable> locations;

        if (args.containsKey( SOURCE ))
        {
            if (args.containsKey( SYSTEMFONT ) || args.containsKey( SOURCELIST ))
                throw new BadParameters();

            results.assetSource = resolveSource( context, args );
            results.modified = results.assetSource.getLastModified();
            locations = new LinkedList<Serializable>();
            locations.add( getURL(results.assetSource) );
        }
        else if (args.containsKey( SYSTEMFONT ))
        {
            if (args.containsKey( SOURCE ) || args.containsKey( SOURCELIST ))
                throw new BadParameters();

            systemFont = (String) args.get( SYSTEMFONT );
            locations = new LinkedList<Serializable>();
            locations.add(systemFont);
        }
        else if (args.containsKey( SOURCELIST ))
        {
            locations = resolveSourceList(context, args);
        }
        else
        {
            throw new BadParameters();
        }

        String family = (String) args.get( FONTFAMILY );
        String alias = (String) args.get( FONTNAME );
        if (alias == null)
        {
            alias = systemFont;
        }
        if (alias == null)
        {
            alias = family;     // FIXME, just either name it name or family, not both!
        }
        if (alias == null)
        {
            throw new BadParameters();
        }

        if (systemFont != null && systemFont.equals(alias) && showShadowedDeviceFontWarnings)
        {
            EmbeddedFontShadowsDeviceFont embeddedFontShadowsDeviceFont = new EmbeddedFontShadowsDeviceFont(alias);
            String path = (String) args.get(Transcoder.FILE);
            String pathSep = (String) args.get(Transcoder.PATHSEP);
            if ("true".equals(pathSep))
            {
                path = path.replace('/', '\\');
            }
            embeddedFontShadowsDeviceFont.path = path;
            if (args.containsKey(Transcoder.LINE))
            {
                int line = Integer.parseInt( (String) args.get(Transcoder.LINE) );
                embeddedFontShadowsDeviceFont.line = line;
            }
            ThreadLocalToolkit.log(embeddedFontShadowsDeviceFont);
        }

        //String newName = (String) args.get( NEWNAME );          // fixme - export name is always font name?

        FontDescription fontDesc = new FontDescription();
        fontDesc.alias = alias;
        fontDesc.style = getFontStyle(args);
        fontDesc.unicodeRanges = (String)args.get(UNICODERANGE);
        fontDesc.advancedAntiAliasing = useAdvancedAntiAliasing(args);
        fontDesc.compactFontFormat = useCompactFontFormat(args, compatibilityVersion);

        DefineFont defineFont = getDefineFont(fontDesc, locations, args);

        try
        {
            results.defineTag = defineFont;
            if (generateSource)
                generateSource(results, className, args);
        }
        catch (TranscoderException te)
        {
          throw te;
        }
        catch (Exception e)
        {
          if (Trace.error)
            e.printStackTrace();

            throw new ExceptionWhileTranscoding( e );
        }
        return results;
    }

    private URL getURL(VirtualFile virtualFile) throws TranscoderException
    {
        URL result;

        if (!(virtualFile instanceof LocalFile))
        {
            InputStream in = null;
           
            try
            {
                String name = virtualFile.getName();
                String path = name.substring(name.indexOf("$") + 1);
                // The path might look like "assets/fonts/Arial.ttf"
                // and slash isn't allowed in temp file names, so
                // convert them to underscore.
                File file = File.createTempFile(path.replace('/', '_'), null);
                in = virtualFile.getInputStream();
                FileUtil.writeBinaryFile(file, in);
                result = file.toURL();
            }
            catch (IOException ioException)
            {
                if (Trace.error)
                {
                    ioException.printStackTrace();
                }

                throw new UnableToExtract( virtualFile.getName() );
            }
            finally
            {
                try
                {
                    if (in != null)
                        in.close();
                }
                catch (Throwable t)
                {
                }
            }
        }
        else
        {
            try
            {
                result = new URL(virtualFile.getURL());
            }
            catch (java.net.MalformedURLException e)
            {
                throw new AbstractTranscoder.UnableToReadSource( virtualFile.getName() );
            }
        }

        return result;
    }

    private DefineFont getDefineFont(FontDescription fontDesc,
            List<Serializable> locations, Map<String, Object> args) throws TranscoderException
    {
        FontManager fontManager = fontsConfig.getTopLevelManager();
        int defineFontTag = TagValues.stagDefineFont3;

        DefineFont defineFont = null;
        for (Iterator<Serializable> it = locations.iterator(); it.hasNext();)
        {
            Object fontSource = it.next();

            try
            {
                // For now, keep the Flex 3 behavior of throwing errors for each
                // location when no FontManager exists.
                if (fontManager == null)
                    throw new NoFontManagerException();

                fontDesc.source = fontSource;
                defineFont = fontManager.createDefineFont(defineFontTag, fontDesc);
            }
            catch (FontManager.InvalidUnicodeRangeException e)
            {
                // For now, keep the Flex 3 error message for invalid unicode
                // ranges...
                throw new InvalidUnicodeRangeException(e.range);
            }
            catch (Exception e)
            {
              if (Trace.error)
              {
                e.printStackTrace();
              }

                ExceptionWhileTranscoding exceptionWhileTranscoding = new ExceptionWhileTranscoding(e);
                String path = (String) args.get(Transcoder.FILE);
                String pathSep = (String) args.get(Transcoder.PATHSEP);
                if ("true".equals(pathSep))
                {
                    path = path.replace('/', '\\');
                }
                exceptionWhileTranscoding.path = path;
                if (args.containsKey(Transcoder.LINE))
                {
                    int line = Integer.parseInt( (String) args.get(Transcoder.LINE) );
                    exceptionWhileTranscoding.line = line;
                }
                ThreadLocalToolkit.log(exceptionWhileTranscoding);
            }

            if (defineFont != null)
            {
                return defineFont;
            }
        }

        throw new UnableToBuildFont(fontDesc.alias);
    }

    private List<Serializable> resolveSourceList(PathResolver context,
            Map<String, Object> args) throws TranscoderException
    {
        List<Serializable> result = new LinkedList<Serializable>();

        Iterator iterator = ((List) args.get( SOURCELIST )).iterator();

        while ( iterator.hasNext() )
        {
            Object source = iterator.next();

            if (source instanceof URLSource)
            {
                URLSource urlSource = (URLSource) source;
                VirtualFile virtualFile = resolve(context, urlSource.getValue());
                result.add( getURL(virtualFile) );
            }
            else // if (source instanceof LocalSource)
            {
                LocalSource localSource = (LocalSource) source;
                result.add( localSource.getValue() );
            }
        }

        return result;
    }

    /**
     * Determines whether advanced anti-aliasing information should be included
     * in the font definition. The term 'Flash Type' is obsolete.
     */
    private boolean useAdvancedAntiAliasing(Map<String, Object> args)
        throws TranscoderException
    {
        boolean useAdvanced = true;
        boolean flashTypeAsName = true;
        String advancedStr = (String)args.get(ADVANTIALIASING);
        if (advancedStr == null)
        {
            advancedStr = (String)args.get(FLASHTYPE);
        }
        else
        {
            flashTypeAsName = false;
        }

        if (advancedStr != null)
        {
            if (advancedStr.equalsIgnoreCase("true"))
            {
                useAdvanced = true;
            }
            else if (advancedStr.equalsIgnoreCase("false"))
            {
                useAdvanced = false;
            }
            else if (flashTypeAsName)
            {
                throw new BadFlashType();
            }
            else
            {
                throw new BadAdvancedAntiAliasing();
            }
        }
        else
        {
            useAdvanced = fontsConfig.getFlashType();
        }

        return useAdvanced;
    }

    /**
     * The CFF flag determines whether font information should be embedded in
     * the Compact Font Format using SWF tag DefineFont4.
     */
    private static boolean useCompactFontFormat(Map<String, Object> args,
        int compatibilityVersion)
    {
        String value = (String)args.get(EMBEDASCFF);
       
        boolean useCFF = true;
        if (compatibilityVersion < MxmlConfiguration.VERSION_4_0)
            useCFF = false;
       
        if (value != null)
        {
            useCFF  = Boolean.parseBoolean(value.trim());
        }

        return useCFF;
    }

    public static int getFontStyle(Map<String, Object> args)
    {
        int s = FontFace.PLAIN;

        String style = (String) args.get( FONTSTYLE );
        if (style == null)
            style = "normal";

        String weight = (String) args.get( FONTWEIGHT );
        if (weight == null)
            weight = "normal";

        if (isBold( weight ))
            s += FontFace.BOLD;

        if (isItalic( style ))
            s += FontFace.ITALIC;

        return s;
    }

    public static boolean isBold(String value)
    {
        boolean bold = false;

        if (value != null)
        {
            String b = value.trim().toLowerCase();
            if (b.startsWith("bold"))
            {
                bold = true;
            }
            else
            {
                try
                {
                    int w = Integer.parseInt(b);
                    if (w >= 700)
                        bold = true;
                }
                catch (Throwable t)
                {
                }
            }
        }

        return bold;
    }

    public static boolean isItalic(String value)
    {
        boolean italic = false;

        if (value != null)
        {
            String ital = value.trim().toLowerCase();
            if (ital.equals("italic") || ital.equals("oblique"))
                italic = true;
        }

        return italic;
    }


    public static final class NoFontManagerException extends RuntimeException
    {
        private static final long serialVersionUID = 755054716704678420L;

        public NoFontManagerException()
        {
            super("No FontManager provided. Cannot build font.");
        }
    }

    public static final class InvalidUnicodeRangeException extends TranscoderException
    {
        private static final long serialVersionUID = 3173208110428813980L;
        public InvalidUnicodeRangeException(String range)
        {
            this.range = range;
        }
        public String range;
    }

    public static final class BadParameters extends TranscoderException
    {
        private static final long serialVersionUID = -2390481014380505531L;
    }

  public static final class BadFlashType extends TranscoderException
  {
        private static final long serialVersionUID = 3971519462447951564L;
  }

  public static final class BadAdvancedAntiAliasing extends TranscoderException
  {
        private static final long serialVersionUID = 8425867739365188050L;
  }

    public static final class UnableToBuildFont extends TranscoderException
    {
        private static final long serialVersionUID = 1520596054636875393L;
        public UnableToBuildFont( String fontName )
        {
            this.fontName = fontName;
        }
        public String fontName;
    }

    public static final class UnableToExtract extends TranscoderException
    {
        private static final long serialVersionUID = -4585845590777360978L;
        public UnableToExtract( String fileName )
        {
            this.fileName = fileName;
        }
        public String fileName;
    }

    public static final class EmbeddedFontShadowsDeviceFont extends CompilerMessage.CompilerWarning implements ILocalizableMessage
    {
        private static final long serialVersionUID = -1125821048682931471L;
        public EmbeddedFontShadowsDeviceFont( String alias )
        {
            this.alias = alias;
        }
        public final String alias;
    }
}

TOP

Related Classes of flex2.compiler.media.FontTranscoder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.