Package org.joget.itextrenderer

Source Code of org.joget.itextrenderer.ITextCustomFontResolver$FontFamily

package org.joget.itextrenderer;

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import java.io.*;
import java.util.*;
import org.xhtmlrenderer.css.constants.IdentValue;
import org.xhtmlrenderer.css.value.FontSpecification;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.pdf.ITextFSFont;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.TrueTypeUtil;
import org.xhtmlrenderer.render.FSFont;
import org.xhtmlrenderer.util.XRRuntimeException;

public class ITextCustomFontResolver extends ITextFontResolver {
    protected Map _fontFamilies = createInitialFontMap();
    protected Map _fontCache = new HashMap();
   
    public ITextCustomFontResolver(SharedContext sharedContext) {
        super(sharedContext);
    }
   
    @Override
    public FSFont resolveFont(SharedContext renderingContext, FontSpecification spec) {
        return resolveFont(renderingContext, spec.families, spec.size, spec.fontWeight, spec.fontStyle, spec.variant);
    }
   
    @Override
    public void flushCache() {
        _fontFamilies = createInitialFontMap();
        _fontCache = new HashMap();
    }
   
    @Override
    public void flushFontFaceFonts() {
        _fontCache = new HashMap();
       
        for (Iterator i = _fontFamilies.values().iterator(); i.hasNext(); ) {
            FontFamily family = (FontFamily)i.next();
            for (Iterator j = family.getFontDescriptions().iterator(); j.hasNext(); ) {
                FontDescription d = (FontDescription)j.next();
                if (d.isFromFontFace()) {
                    j.remove();
                }
            }
            if (family.getFontDescriptions().size() == 0) {
                i.remove();
            }
        }
    }
   
    protected byte[] readFile(String path) throws IOException {
        File f = new File(path);
        if (f.exists()) {
            ByteArrayOutputStream result = new ByteArrayOutputStream((int)f.length());
            InputStream is = null;
            try {
                is = new FileInputStream(path);
                byte[] buf = new byte[10240];
                int i;
                while ( (i = is.read(buf)) != -1) {
                    result.write(buf, 0, i);
                }
                is.close();
                is = null;
               
                return result.toByteArray();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        // ignore
                    }
                }
            }
        } else {
            throw new IOException("File " + path + " does not exist or is not accessible");
        }
    }
   
    @Override
    public void addFont(String path, String encoding, boolean embedded, String pathToPFB) throws DocumentException, IOException {
        try {
            String lower = path.toLowerCase();
            if (lower.endsWith(".otf") || lower.endsWith(".ttf") || lower.indexOf(".ttc,") != -1) {
                BaseFont font = BaseFont.createFont(path, encoding, embedded);

                String fontFamilyName = TrueTypeUtil.getFamilyName(font);
                FontFamily fontFamily = getCustomFontFamily(fontFamilyName);

                FontDescription descr = new FontDescription(font);
                try {
                    TrueTypeUtil.populateDescription(path, font, descr);
                } catch (Exception e) {
                    throw new XRRuntimeException(e.getMessage(), e);
                }

                fontFamily.addFontDescription(descr);
            } else if (lower.endsWith(".ttc")) {
                String[] names = BaseFont.enumerateTTCNames(path);
                for (int i = 0; i < names.length; i++) {
                    addFont(path + "," + i, encoding, embedded);
                }
            } else if (lower.endsWith(".afm") || lower.endsWith(".pfm")) {
                if (embedded && pathToPFB == null) {
                    throw new IOException("When embedding a font, path to PFB/PFA file must be specified");
                }

                BaseFont font = BaseFont.createFont(
                        path, encoding, embedded, false, null, readFile(pathToPFB));

                String fontFamilyName = font.getFamilyFontName()[0][3];
                FontFamily fontFamily = getCustomFontFamily(fontFamilyName);

                FontDescription descr = new FontDescription(font);
                // XXX Need to set weight, underline position, etc.  This information
                // is contained in the AFM file (and even parsed by Type1Font), but
                // unfortunately it isn't exposed to the caller.
                fontFamily.addFontDescription(descr);           
            } else {
                BaseFont font = BaseFont.createFont(path, encoding, embedded);
           
                String fontFamilyName = font.getFamilyFontName()[0][3];
                FontFamily fontFamily = getCustomFontFamily(fontFamilyName);

                FontDescription descr = new FontDescription(font);
                fontFamily.addFontDescription(descr);   
            }
        } catch (Exception ex) {
            throw new IOException("Unsupported font type");
        }
    }
   
    protected void addFontFaceFont(
            String uri, String encoding, boolean embedded, byte[] afmttf, byte[] pfb)
            throws DocumentException, IOException {
        String lower = uri.toLowerCase();
        if (lower.endsWith(".otf") || lower.endsWith(".ttf") || lower.indexOf(".ttc,") != -1) {
            BaseFont font = BaseFont.createFont(uri, encoding, embedded, false, afmttf, pfb);
           
            String fontFamilyName = TrueTypeUtil.getFamilyName(font);
            FontFamily fontFamily = getCustomFontFamily(fontFamilyName);
           
            FontDescription descr = new FontDescription(font);
            try {
                TrueTypeUtil.populateDescription(uri, afmttf, font, descr);
            } catch (Exception e) {
                throw new XRRuntimeException(e.getMessage(), e);
            }
           
            descr.setFromFontFace(true);
           
            fontFamily.addFontDescription(descr);
        } else if (lower.endsWith(".afm") || lower.endsWith(".pfm") || lower.endsWith(".pfb") || lower.endsWith(".pfa")) {
            if (embedded && pfb == null) {
                throw new IOException("When embedding a font, path to PFB/PFA file must be specified");
            }
           
            String name = uri.substring(0, uri.length()-4) + ".afm";
            BaseFont font = BaseFont.createFont(
                    name, encoding, embedded, false, afmttf, pfb);
           
            String fontFamilyName = font.getFamilyFontName()[0][3];
            FontFamily fontFamily = getCustomFontFamily(fontFamilyName);
           
            FontDescription descr = new FontDescription(font);
            descr.setFromFontFace(true);
            // XXX Need to set weight, underline position, etc.  This information
            // is contained in the AFM file (and even parsed by Type1Font), but
            // unfortunately it isn't exposed to the caller.
            fontFamily.addFontDescription(descr);           
        } else {
            throw new IOException("Unsupported font type");
        }
    }   
   
    protected FontFamily getCustomFontFamily(String fontFamilyName) {
        FontFamily fontFamily = (FontFamily)_fontFamilies.get(fontFamilyName);
        if (fontFamily == null) {
            fontFamily = new FontFamily();
            fontFamily.setName(fontFamilyName);
            _fontFamilies.put(fontFamilyName, fontFamily);
        }
        return fontFamily;
    }
   
    protected String normalizeFontFamily(String fontFamily) {
        String result = fontFamily;
        // strip off the "s if they are there
        if (result.startsWith("\"")) {
            result = result.substring(1);
        }
        if (result.endsWith("\"")) {
            result = result.substring(0, result.length() - 1);
        }

        // normalize the font name
        if (result.equalsIgnoreCase("serif")) {
            result = "Serif";
        }
        else if (result.equalsIgnoreCase("sans-serif")) {
            result = "SansSerif";
        }
        else if (result.equalsIgnoreCase("monospace")) {
            result = "Monospaced";
        }
       
        return result;
    }
   
    protected FSFont resolveFont(SharedContext ctx, String[] families, float size, IdentValue weight, IdentValue style, IdentValue variant) {
        if (! (style == IdentValue.NORMAL || style == IdentValue.OBLIQUE
                || style == IdentValue.ITALIC)) {
            style = IdentValue.NORMAL;
        }
        if (families != null) {
            for (int i = 0; i < families.length; i++) {
                FSFont font = resolveFont(ctx, families[i], size, weight, style, variant);
                if (font != null) {
                    return font;
                }
            }
        }
       
        return resolveFont(ctx, "Serif", size, weight, style, variant);
    }
   
    protected FSFont resolveFont(SharedContext ctx, String fontFamily, float size, IdentValue weight, IdentValue style, IdentValue variant) {
        String normalizedFontFamily = normalizeFontFamily(fontFamily);

        String cacheKey = getHashName(normalizedFontFamily, weight, style);
        FontDescription result = (FontDescription)_fontCache.get(cacheKey);
        if (result != null) {
            return new ITextFSFont(result, size);
        }
       
        FontFamily family = (FontFamily)_fontFamilies.get(normalizedFontFamily);
        if (family != null) {
            result = family.match(convertWeightToInt(weight), style);
            if (result != null) {
                _fontCache.put(cacheKey, result);
                return new ITextFSFont(result, size);
            }
        }
       
        return null;
    }
   
    protected static Map createInitialFontMap() {
        HashMap result = new HashMap();
       
        try {
            addCourier(result);
            addTimes(result);
            addHelvetica(result);
            addUnicodeFont(result);
        } catch (DocumentException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);           
        }

        return result;
    }
   
    protected static BaseFont createFont(String name) throws DocumentException, IOException {
        return BaseFont.createFont(name, "winansi", true);
    }
   
    protected int convertWeightToInt(IdentValue weight) {
        if (weight == IdentValue.NORMAL) {
            return 400;
        } else if (weight == IdentValue.BOLD) {
            return 700;
        } else if (weight == IdentValue.FONT_WEIGHT_100) {
            return 100;
        } else if (weight == IdentValue.FONT_WEIGHT_200) {
            return 200;
        } else if (weight == IdentValue.FONT_WEIGHT_300) {
            return 300;
        } else if (weight == IdentValue.FONT_WEIGHT_400) {
            return 400;
        } else if (weight == IdentValue.FONT_WEIGHT_500) {
            return 500;
        } else if (weight == IdentValue.FONT_WEIGHT_600) {
            return 600;
        } else if (weight == IdentValue.FONT_WEIGHT_700) {
            return 700;
        } else if (weight == IdentValue.FONT_WEIGHT_800) {
            return 800;
        } else if (weight == IdentValue.FONT_WEIGHT_900) {
            return 900;
        } else if (weight == IdentValue.LIGHTER) {
            // FIXME
            return 400;
        } else if (weight == IdentValue.BOLDER) {
            // FIXME
            return 700;
        }
        throw new IllegalArgumentException();
    }
   
    protected static void addCourier(HashMap result) throws DocumentException, IOException {
        FontFamily courier = new FontFamily();
        courier.setName("Courier");
       
        courier.addFontDescription(new FontDescription(
                createFont(BaseFont.COURIER_BOLDOBLIQUE), IdentValue.OBLIQUE, 700));
        courier.addFontDescription(new FontDescription(
                createFont(BaseFont.COURIER_OBLIQUE), IdentValue.OBLIQUE, 400));
        courier.addFontDescription(new FontDescription(
                createFont(BaseFont.COURIER_BOLD), IdentValue.NORMAL, 700));
        courier.addFontDescription(new FontDescription(
                createFont(BaseFont.COURIER), IdentValue.NORMAL, 400));       
       
        result.put("DialogInput", courier);
        result.put("Monospaced", courier);
        result.put("Courier", courier);
    }
   
    protected static void addTimes(HashMap result) throws DocumentException, IOException {
        FontFamily times = new FontFamily();
        times.setName("Times");
       
        times.addFontDescription(new FontDescription(
                createFont(BaseFont.TIMES_BOLDITALIC), IdentValue.ITALIC, 700));
        times.addFontDescription(new FontDescription(
                createFont(BaseFont.TIMES_ITALIC), IdentValue.ITALIC, 400));
        times.addFontDescription(new FontDescription(
                createFont(BaseFont.TIMES_BOLD), IdentValue.NORMAL, 700));
        times.addFontDescription(new FontDescription(
                createFont(BaseFont.TIMES_ROMAN), IdentValue.NORMAL, 400))
       
        result.put("Serif", times);
        result.put("TimesRoman", times);
    }
   
    protected static void addHelvetica(HashMap result) throws DocumentException, IOException {
        FontFamily helvetica = new FontFamily();
        helvetica.setName("Helvetica");
       
        helvetica.addFontDescription(new FontDescription(
                createFont(BaseFont.HELVETICA_BOLDOBLIQUE), IdentValue.OBLIQUE, 700));
        helvetica.addFontDescription(new FontDescription(
                createFont(BaseFont.HELVETICA_OBLIQUE), IdentValue.OBLIQUE, 400));
        helvetica.addFontDescription(new FontDescription(
                createFont(BaseFont.HELVETICA_BOLD), IdentValue.NORMAL, 700));
        helvetica.addFontDescription(new FontDescription(
                createFont(BaseFont.HELVETICA), IdentValue.NORMAL, 400))
       
        result.put("Dialog", helvetica);
        result.put("SansSerif", helvetica);
    }
   
    protected static void addUnicodeFont(HashMap result) throws DocumentException, IOException {
        FontFamily stsong = new FontFamily();
        stsong.setName("STSong-Light");
        BaseFont stsongFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        stsong.addFontDescription(new FontDescription(stsongFont, IdentValue.NORMAL, 400));
        result.put("STSong-Light", stsong);
       
        FontFamily msung = new FontFamily();
        msung.setName("MSung-Light");
        BaseFont msungFont = BaseFont.createFont("MSung-Light", "UniCNS-UCS2-H", BaseFont.NOT_EMBEDDED);
        msung.addFontDescription(new FontDescription(msungFont, IdentValue.NORMAL, 400));
        result.put("MSung-Light", msung);
       
        FontFamily heiseimin = new FontFamily();
        heiseimin.setName("HeiseiMin-W3");
        BaseFont heiseiminFont = BaseFont.createFont("HeiseiMin-W3", "UniJIS-UCS2-H", BaseFont.NOT_EMBEDDED);
        heiseimin.addFontDescription(new FontDescription(heiseiminFont, IdentValue.NORMAL, 400));
        result.put("HeiseiMin-W3", heiseimin);
       
        FontFamily hygothic = new FontFamily();
        hygothic.setName("HYGoThic-Medium");
        BaseFont hygothicFont = BaseFont.createFont("HYGoThic-Medium", "UniKS-UCS2-H", BaseFont.NOT_EMBEDDED);
        hygothic.addFontDescription(new FontDescription(hygothicFont, IdentValue.NORMAL, 400));
        result.put("HYGoThic-Medium", hygothic);
       
        FontFamily droidsan = new FontFamily();
        String path = "fonts/Droid-Sans/DroidSans.ttf";
        BaseFont font = BaseFont.createFont(path, BaseFont.IDENTITY_H, true);
        String fontFamilyName = TrueTypeUtil.getFamilyName(font);
        droidsan.setName(fontFamilyName);
        FontDescription descr = new FontDescription(font);
        try {
            TrueTypeUtil.populateDescription(path, font, descr);
        } catch (Exception e) {
            throw new XRRuntimeException(e.getMessage(), e);
        }
        droidsan.addFontDescription(descr);
        result.put(fontFamilyName, droidsan);
    }
   
    protected static class FontFamily {

        protected String _name;
        protected List _fontDescriptions;

        public FontFamily() {
        }

        public List getFontDescriptions() {
            return _fontDescriptions;
        }

        public void addFontDescription(FontDescription descr) {
            if (_fontDescriptions == null) {
                _fontDescriptions = new ArrayList();
            }
            _fontDescriptions.add(descr);
            Collections.sort(_fontDescriptions,
                    new Comparator() {

                        public int compare(Object o1, Object o2) {
                            FontDescription f1 = (FontDescription) o1;
                            FontDescription f2 = (FontDescription) o2;
                            return f1.getWeight() - f2.getWeight();
                        }
                    });
        }

        public String getName() {
            return _name;
        }

        public void setName(String name) {
            _name = name;
        }

        public FontDescription match(int desiredWeight, IdentValue style) {
            if (_fontDescriptions == null) {
                throw new RuntimeException("fontDescriptions is null");
            }

            List candidates = new ArrayList();

            for (Iterator i = _fontDescriptions.iterator(); i.hasNext();) {
                FontDescription description = (FontDescription) i.next();

                if (description.getStyle() == style) {
                    candidates.add(description);
                }
            }

            if (candidates.size() == 0) {
                if (style == IdentValue.ITALIC) {
                    return match(desiredWeight, IdentValue.OBLIQUE);
                } else if (style == IdentValue.OBLIQUE) {
                    return match(desiredWeight, IdentValue.NORMAL);
                } else {
                    return null;
                }
            }

            FontDescription[] matches = (FontDescription[]) candidates.toArray(new FontDescription[candidates.size()]);
            FontDescription result;

            result = findByWeight(matches, desiredWeight, SM_EXACT);

            if (result != null) {
                return result;
            } else {
                if (desiredWeight <= 500) {
                    return findByWeight(matches, desiredWeight, SM_LIGHTER_OR_DARKER);
                } else {
                    return findByWeight(matches, desiredWeight, SM_DARKER_OR_LIGHTER);
                }
            }
        }
        protected static final int SM_EXACT = 1;
        protected static final int SM_LIGHTER_OR_DARKER = 2;
        protected static final int SM_DARKER_OR_LIGHTER = 3;

        protected FontDescription findByWeight(FontDescription[] matches,
                int desiredWeight, int searchMode) {
            if (searchMode == SM_EXACT) {
                for (int i = 0; i < matches.length; i++) {
                    FontDescription descr = matches[i];
                    if (descr.getWeight() == desiredWeight) {
                        return descr;
                    }
                }
                return null;
            } else if (searchMode == SM_LIGHTER_OR_DARKER) {
                int offset = 0;
                FontDescription descr = null;
                for (offset = 0; offset < matches.length; offset++) {
                    descr = matches[offset];
                    if (descr.getWeight() > desiredWeight) {
                        break;
                    }
                }

                if (offset > 0 && descr.getWeight() > desiredWeight) {
                    return matches[offset - 1];
                } else {
                    return descr;
                }

            } else if (searchMode == SM_DARKER_OR_LIGHTER) {
                int offset = 0;
                FontDescription descr = null;
                for (offset = matches.length - 1; offset >= 0; offset--) {
                    descr = matches[offset];
                    if (descr.getWeight() < desiredWeight) {
                        break;
                    }
                }

                if (offset != matches.length - 1 && descr.getWeight() < desiredWeight) {
                    return matches[offset + 1];
                } else {
                    return descr;
                }
            }

            return null;
        }
    }
}
TOP

Related Classes of org.joget.itextrenderer.ITextCustomFontResolver$FontFamily

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.