diff --git a/lib/ttf.jar b/lib/ttf.jar index 70bde0bb7..4cae30b29 100644 Binary files a/lib/ttf.jar and b/lib/ttf.jar differ diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java index 5be9e3e76..37bc23c6d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java @@ -263,6 +263,7 @@ public class FontExporter { WritableFontData woffData = w.convert(font); woffData.copyTo(fos); } + ttfFile.delete(); } } diff --git a/libsrc/ttf/src/fontastic/Fontastic.java b/libsrc/ttf/src/fontastic/Fontastic.java index 7dcbc7c11..bf07e4c77 100644 --- a/libsrc/ttf/src/fontastic/Fontastic.java +++ b/libsrc/ttf/src/fontastic/Fontastic.java @@ -165,6 +165,7 @@ public class Fontastic { //m_engine.fireAction(); //m_engine.addDefaultGlyphs(); + List glyphFiles = new ArrayList<>(glyphs.size()); for (FGlyph glyph : glyphs) { m_engine.checkUnicodeBlock(glyph.getGlyphChar()); @@ -199,8 +200,10 @@ public class Fontastic { glyphFile.addContour(econtour); } - glyphFile.saveGlyphFile(); + + glyphFiles.add(glyphFile); } + m_engine.getTypeface().addRequiredGlyphs(); m_engine.buildTrueType(false); diff --git a/libsrc/ttf/src/org/doubletype/ossa/Engine.java b/libsrc/ttf/src/org/doubletype/ossa/Engine.java index 94c92bd19..16e459f68 100644 --- a/libsrc/ttf/src/org/doubletype/ossa/Engine.java +++ b/libsrc/ttf/src/org/doubletype/ossa/Engine.java @@ -1,762 +1,697 @@ -/* - * $Id: Engine.java,v 1.84 2004/12/27 04:56:03 eed3si9n Exp $ - * - * $Copyright: copyright (c) 2003, e.e d3si9n $ - * $License: - * This source code is part of DoubleType. - * DoubleType is a graphical typeface designer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * In addition, as a special exception, e.e d3si9n gives permission to - * link the code of this program with any Java Platform that is available - * to public with free of charge, including but not limited to - * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), - * and distribute linked combinations including the two. - * You must obey the GNU General Public License in all respects for all - * of the code used other than Java Platform. If you modify this file, - * you may extend this exception to your version of the file, but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. - * $ - */ - -package org.doubletype.ossa; - -import java.awt.*; -import java.awt.datatransfer.*; -import java.awt.event.*; -import java.awt.geom.*; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.io.*; -import java.net.MalformedURLException; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.swing.*; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.*; -import javax.swing.event.*; - -import org.doubletype.ossa.adapter.*; -import org.doubletype.ossa.module.*; -import org.doubletype.ossa.truetype.*; - -/** - * @author e.e - */ -public class Engine { - // -------------------------------------------------------------- - - // used by findFile - public static final int USER_CANCELLED = -1; - public static final int FILE_NOT_FOUND = 0; - public static final int FILE_FOUND = 1; - - // used by Find - public static final int SEARCH_BY_EXAMPLE = 0; - public static final int SEARCH_UNICODE = 1; - public static final int SEARCH_JIS_CODE = 2; - - // public static final double k_fontSizes [] = {9, 10, 11, 12, 14, 18, 24, 36, 72}; - public static final int k_defaultPixelSize = 16; - public static final int k_resolutions [] = {96, 72, 75, 100}; - public static final int k_defaultResolution = 96; - public static final int k_zooms [] = {25, 50, 100}; - public static final int k_defaultZoom = 100; - - // -------------------------------------------------------------- - - private static int s_em = 1024; - private static Engine s_singleton = null; - - public static Engine getSingletonInstance() { - if (s_singleton == null) - s_singleton = new Engine(); - return s_singleton; - } - - public static int getEm() { - return TTPixelSize.getEm(); - } - - // -------------------------------------------------------------- - - private UiBridge m_ui; - - private TypefaceFile m_typeface; - private GlyphFile m_root; - private ActiveList m_actives; - private ArrayList m_listeners = new ArrayList<>(); - - private String m_foundFileName; - private Clipboard m_clipboard; - private JFileChooser m_gifChooser; - private JFileChooser m_chooser; - - private Action m_deleteAction; - private Action m_addPointAction; - private Action m_toggleAction; - private Action m_hintAction; - private Action m_contourAction; - private Action m_moduleAction; - private Action m_includeAction; - private Action m_selectNextAction; - private Action m_roundAction; - private Action m_propertyAction; - private Action m_convertControlPointAction; - private Action m_convertContourAction; - - private String m_msgAlreadyExists = " already exists!"; - private String m_msgNoTypeface = "no typeface"; - private String m_msgEmptyGlyphTitle = "glyph title is empty"; - private String m_msgGlyphName = "glyph name?"; - private String m_msgCircular = "circular include!"; - private String m_msgNoJis = "Charset ISO-2022-JP is not supported.\n" - + "Please include charsets.jar in classpath."; - - // -------------------------------------------------------------- - - private Engine() { - //GlyphFactory.setFactory(new EGlyphFactory()); - - - - m_typeface = null; - m_root = null; - - m_clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - m_actives = ActiveList.getSingletonInstance(); - - initActions(); - } - - private void initActions() { - - } - - public Action [] buildCommands() { - ArrayList actions = buildCommandsArrayList(); - Action [] retval = new Action[actions.size()]; - int i; - for (i = 0; i < actions.size(); i++) { - retval[i] = (Action) actions.get(i); - } // for i - - return retval; - } - - private ArrayList buildCommandsArrayList() { - ArrayList retval = new ArrayList<>(); - - if (m_root == null) { - return retval; - } // if - - if (m_actives.hasActiveContour()) { - retval.add(m_convertContourAction); - } - - if (m_actives.hasActiveControlPoint()) { - EControlPoint controlPoint = m_actives.getActiveControlPoint(); - retval.add(m_convertControlPointAction); - } - - if (m_actives.hasActivePoint()) { - EContourPoint point = m_actives.getActivePoint(); - - retval.add(m_toggleAction); - - if (!point.isRounded()) { - retval.add(m_hintAction); - } // if - - if (!point.hasHintForCurrentPpem()) { - retval.add(m_roundAction); - } // if - } // if - - if (m_actives.size() > 0) { - // retval.add(m_propertyAction); - retval.add(m_deleteAction); - } // if - - if (m_actives.hasActivePoint()) { - retval.add(m_addPointAction); - } // if - - /*if (!GlyphAction.isPointVisible()) { - retval.add(m_moduleAction); - retval.add(m_contourAction); - retval.add(m_includeAction); - } // if*/ - - return retval; - } - - public void localize(ResourceBundle a_bundle) { - m_msgAlreadyExists = a_bundle.getString("msgAlreadyExists"); - m_msgNoTypeface = a_bundle.getString("msgNoTypeface"); - m_msgEmptyGlyphTitle = a_bundle.getString("msgEmptyGlyphTitle"); - m_msgGlyphName = a_bundle.getString("msgGlyphName"); - m_msgCircular = a_bundle.getString("msgCircular"); - } - - private void showPropertyDialog() { - if (m_actives.size() != 1) { - return; - } // if - - m_ui.showPropertyDialog(m_actives.get(0)); - fireAction(); - } - - public void setUi(UiBridge a_ui) { - m_ui = a_ui; - } - - - - public void selectNext() { - if (m_root == null) { - return; - } // if - - m_root.selectNext(); - fireAction(); - } - - public void delete() { - if (m_root == null) - return; - if (!m_actives.hasSelected()) { - return; - } // if - - m_root.remove(); - - fireAction(); - } - - public void cutToClipboard() { - if (m_root == null) - return; - if (!m_actives.hasSelected()) { - return; - } // if - - copyToClipboard(); - delete(); - - fireAction(); - } - - public void copyToClipboard() { - if (m_root == null) - return; - if (!m_actives.hasSelected()) { - return; - } // if - - String s = m_actives.getSelectedAsString(); - if (s.equals("")) { - return; - } // if - - StringSelection selection = new StringSelection(s); - - try { - m_clipboard.setContents(selection, selection); - } catch (Exception e) { - e.printStackTrace(); - } // try-catch - - fireAction(); - } - - public void pasteFromClipboard() { - if (m_root == null) - return; - Transferable content = null; - String s = ""; - - try { - content = m_clipboard.getContents(this); - if (content == null) - return; - s = (String) content.getTransferData(DataFlavor.stringFlavor); - if (s.equals("")) { - return; - } // if - } catch (Exception e) { - e.printStackTrace(); - return; - } // try-catch - - try { - m_root.addObjectFromClipboard(s); - } catch (GlyphFile.CircularIncludeException e) { - Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, m_msgCircular, e); - } - - fireAction(); - } - - public void undo() { - if (m_root == null) - return; - - m_root.undo(); - fireAction(); - } - - public void redo() { - if (m_root == null) - return; - - m_root.redo(); - fireAction(); - } - - public void setAdvanceWidth(int a_value) { - if (m_root == null) - return; - - m_root.setAdvanceWidth(a_value); - fireAction(); - } - - public void moveLeft() { - move(new Point2D.Double(-1, 0)); - } - - public void moveUp() { - move(new Point2D.Double(0, 1)); - } - - public void moveDown() { - move(new Point2D.Double(0, -1)); - } - - public void moveRight() { - move(new Point2D.Double(1, 0)); - } - - private void move(Point2D a_delta) { - if (m_root == null) { - return; - } // if - - m_root.move(a_delta); - } - - public void buildNewTypeface(String a_name, File a_dir) throws FileNotFoundException { - if (a_name == null || a_name.equals("")) { - return; - } // if - - TypefaceFile typeface = new TypefaceFile(a_name, a_dir); - typeface.setAuthor("no body"); - DateFormat format = new SimpleDateFormat("yyyy"); - typeface.setCopyrightYear(format.format(new Date())); - typeface.setFontFamilyName(a_name); - typeface.setSubFamily("Regular"); - typeface.addCodePage(TTCodePage.US_ASCII.toString()); - typeface.addCodePage(TTCodePage.Latin_1.toString()); - - setTypeface(typeface); - } - - public void addDefaultGlyphs() throws FileNotFoundException { - m_typeface.addRequiredGlyphs(); - m_typeface.addBasicLatinGlyphs(); - - fireAction(); - } - - public void openTypeface() throws FileNotFoundException { - if (m_chooser == null) { - m_chooser = new JFileChooser(new File(AppSettings.getLastTypefaceDir())); - } // if - - m_chooser.setFileFilter(new TypefaceFileFilter()); - int returnVal = m_chooser.showOpenDialog(null); - - if (returnVal != JFileChooser.APPROVE_OPTION) { - return; - } // if - - AppSettings.setLastTypefaceDir(m_chooser.getSelectedFile().toString()); - openTypeface(m_chooser.getSelectedFile()); - } - - private void openTypeface(File a_file) throws FileNotFoundException { - setTypeface(new TypefaceFile(a_file)); - - if (m_typeface.addRequiredGlyphs()) { - fireAction(); - } // if - } - - public void setTypeface(TypefaceFile a_typeface) { - m_typeface = a_typeface; - fireAction(); - } - - public void changeUnicode(long a_unicode) throws FileNotFoundException { - if (m_typeface == null || m_root == null) { - return; - } // if - - m_typeface.setGlyphUnicode(m_root, a_unicode); - fireAction(); - } - - public int findFile(long a_unicode) { - if (m_typeface == null) - return USER_CANCELLED; - - m_foundFileName = m_typeface.unicodeToFileName(a_unicode); - if (m_foundFileName != null) { - return FILE_FOUND; - } // if - - return FILE_NOT_FOUND; - } - - public String getFoundFileName() { - return m_foundFileName; - } - - - /** - * Create glyph out of given unicode, and add it to the typeface. - * @param a_unicode - */ - public GlyphFile addNewGlyph(long a_unicode) throws FileNotFoundException { - GlyphFile retval; - - retval = m_typeface.createGlyph(a_unicode); - addGlyphToTypeface(retval); - - return retval; - } - - public void checkUnicodeBlock(long a_unicode) throws FileNotFoundException { - TTUnicodeRange range = TTUnicodeRange.of(a_unicode); - if (range == null){ - return; - } - - if (m_typeface.containsUnicodeRange(range.toString())){ - return; - } - m_typeface.addUnicodeRange(range.toString()); - } - - private void addGlyphToTypeface(GlyphFile a_file) throws FileNotFoundException { - m_typeface.addGlyph(a_file); - m_typeface.saveGlyphFile(); - - setRoot(a_file); - } - - public GlyphFile openGlyphFile(String a_fileName) { - ModuleManager manager = ModuleManager.getSingletonInstance(); - GlyphFile retval = manager.getReloadedGlyphFile(a_fileName); - setRoot(retval); - - return retval; - } - - public void removeGlyphFromTypeface(String a_fileName) { - if (m_typeface == null) - return; - - m_typeface.removeGlyph(a_fileName); - fireAction(); - } - - public Font buildTrueType(boolean a_isDebug) { - Font retval = null; - - if (m_typeface == null) - return retval; - - - - try { - m_typeface.buildTTF(a_isDebug); - retval = m_typeface.getFont(); - } catch (Exception e) { - Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, null,e); - } // try-catch - - return retval; - } - - public void saveGlyph() throws FileNotFoundException { - if (m_root == null) - return; - - if (m_root.getGlyphTitle().equals("")) { - Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, m_msgEmptyGlyphTitle); - return; - } // if - - m_root.saveGlyphFile(); - fireAction(); - } - - public TypefaceFile getTypeface() { - return m_typeface; - } - - public File getGlyphPath() { - return m_typeface.getGlyphPath(); - } - - - public GlyphFile getRoot() { - return m_root; - } - - public void setRoot(GlyphFile a_file) { - m_root = a_file; - fireAction(); - } - - public void addActionListener(ActionListener a_listener) { - m_listeners.add(a_listener); - } - - public void fireAction() { - ActionEvent e = new ActionEvent(this, Event.ACTION_EVENT, "foo"); - - for (ActionListener listener: m_listeners) { - listener.actionPerformed(e); - } // for listener - } - - public String includeFileName() { - String retval = ""; - - JFileChooser chooser = new JFileChooser(getGlyphPath()); - chooser.setFileFilter(new GlyphFileFilter()); - - int returnVal = chooser.showOpenDialog(null); - - if (returnVal == JFileChooser.APPROVE_OPTION) { - retval = chooser.getSelectedFile().getName().toString(); - } // if - - return retval; - } - - public void addCodePage(String a_codePage) throws FileNotFoundException { - if (m_typeface == null) { - return; - } // if - - m_typeface.addCodePage(a_codePage); - fireAction(); - } - - public void removeCodePage(String a_codePage) throws FileNotFoundException { - if (m_typeface == null) { - return; - } // if - - m_typeface.removeCodePage(a_codePage); - fireAction(); - } - - public void setAuthor(String a_value) throws FileNotFoundException { - if (m_typeface == null) { - return; - } // if - - m_typeface.setAuthor(a_value); - m_typeface.saveGlyphFile(); - fireAction(); - } - - public void setCopyrightYear(String a_value) throws FileNotFoundException { - if (m_typeface == null) { - return; - } // if - - m_typeface.setCopyrightYear(a_value); - m_typeface.saveGlyphFile(); - fireAction(); - } - - public void setFontFamilyName(String a_value) throws FileNotFoundException { - if (m_typeface == null) { - return; - } // if - - m_typeface.setFontFamilyName(a_value); - fireAction(); - } - - public void setTypefaceLicense(String a_value) throws FileNotFoundException { - if (m_typeface == null) { - return; - } // if - - m_typeface.setLicense(a_value); - m_typeface.saveGlyphFile(); - fireAction(); - } - - public void setBaseline(double a_value) throws FileNotFoundException { - if (m_typeface == null) { - return; - } // if - - double min = m_typeface.getBottomSideBearing(); - double max = m_typeface.getMeanline(); - - if (a_value < min) { - a_value = min; - } // if - - if (a_value > max) { - a_value = max; - } // if - - try { - m_typeface.setDescender(a_value - min); - m_typeface.setAscender(m_typeface.getEm() - - m_typeface.getTopSideBearing() - a_value); - m_typeface.setXHeight(max - a_value); - } - catch (OutOfRangeException e) { - e.printStackTrace(); - } // try-catch - - fireAction(); - } - - public void setMeanline(double a_value) throws FileNotFoundException { - if (m_typeface == null) { - return; - } // if - - double min = m_typeface.getBaseline(); - double max = m_typeface.getEm() - - m_typeface.getTopSideBearing(); - - if (a_value < min) { - a_value = min; - } // if - - if (a_value > max) { - a_value = max; - } // if - - try { - m_typeface.setXHeight(a_value - min); - } - catch (OutOfRangeException e) { - e.printStackTrace(); - } // try-catch - - fireAction(); - } - - public void mousePressed(MouseEvent a_event) { - - } - - - public void mouseDragged(MouseEvent a_event) { - - } - - public void mouseReleased(MouseEvent a_event) { - - } - - public void setAction(String a_key) { - - } - - public void keyPressed(KeyEvent a_event) { - if (a_event.getModifiers() == 0) { - if (a_event.getKeyCode() == KeyEvent.VK_TAB) { - - m_selectNextAction.actionPerformed(null); - } // if - } else if (a_event.getModifiers() == KeyEvent.SHIFT_MASK) { - - } // if - - fireAction(); - } - - private JFileChooser createImageChooser() { - JFileChooser retval; - - retval = new JFileChooser(new File(AppSettings.getLastTypefaceDir())); - retval.setFileFilter(new javax.swing.filechooser.FileFilter() { - public boolean accept(File a_file) { - if (a_file.isDirectory()) - return true; - - String s = a_file.toString().toLowerCase(); - if (s.endsWith(".gif") - || s.endsWith(".jpg") - || s.endsWith(".jpeg") - || s.endsWith(".png")) - return true; - - return false; - } - - //The description of this filter - public String getDescription() { - return "Image Files"; - } - }); - - return retval; - } - - - - - public ArrayList getPixelSizes() { - return TTPixelSize.getList(); - } - - class MyTreeListener implements TreeSelectionListener { - public void valueChanged(TreeSelectionEvent a_event) { - TreePath path = a_event.getPath(); - Object obj = path.getLastPathComponent(); - String s = obj.toString(); - - TreePath parent = path.getParentPath(); - if (parent != null) { - obj = parent.getLastPathComponent(); - s = obj.toString() + "->" + s; - } // if - - } - } - -} +/* + * $Id: Engine.java,v 1.84 2004/12/27 04:56:03 eed3si9n Exp $ + * + * $Copyright: copyright (c) 2003, e.e d3si9n $ + * $License: + * This source code is part of DoubleType. + * DoubleType is a graphical typeface designer. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * In addition, as a special exception, e.e d3si9n gives permission to + * link the code of this program with any Java Platform that is available + * to public with free of charge, including but not limited to + * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), + * and distribute linked combinations including the two. + * You must obey the GNU General Public License in all respects for all + * of the code used other than Java Platform. If you modify this file, + * you may extend this exception to your version of the file, but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. + * $ + */ + +package org.doubletype.ossa; + +import java.awt.*; +import java.awt.datatransfer.*; +import java.awt.event.*; +import java.awt.geom.*; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.io.*; +import java.net.MalformedURLException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.*; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.*; +import javax.swing.event.*; + +import org.doubletype.ossa.adapter.*; +import org.doubletype.ossa.module.*; +import org.doubletype.ossa.truetype.*; + +/** + * @author e.e + */ +public class Engine { + // -------------------------------------------------------------- + + // used by findFile + public static final int USER_CANCELLED = -1; + public static final int FILE_NOT_FOUND = 0; + public static final int FILE_FOUND = 1; + + // used by Find + public static final int SEARCH_BY_EXAMPLE = 0; + public static final int SEARCH_UNICODE = 1; + public static final int SEARCH_JIS_CODE = 2; + + // public static final double k_fontSizes [] = {9, 10, 11, 12, 14, 18, 24, 36, 72}; + public static final int k_defaultPixelSize = 16; + public static final int k_resolutions [] = {96, 72, 75, 100}; + public static final int k_defaultResolution = 96; + public static final int k_zooms [] = {25, 50, 100}; + public static final int k_defaultZoom = 100; + + // -------------------------------------------------------------- + + private static int s_em = 1024; + private static Engine s_singleton = null; + + public static Engine getSingletonInstance() { + if (s_singleton == null) + s_singleton = new Engine(); + return s_singleton; + } + + public static int getEm() { + return TTPixelSize.getEm(); + } + + // -------------------------------------------------------------- + + private UiBridge m_ui; + + private TypefaceFile m_typeface; + private GlyphFile m_root; + private ActiveList m_actives; + private ArrayList m_listeners = new ArrayList<>(); + + private String m_foundFileName; + private Clipboard m_clipboard; + private JFileChooser m_gifChooser; + private JFileChooser m_chooser; + + private Action m_deleteAction; + private Action m_addPointAction; + private Action m_toggleAction; + private Action m_hintAction; + private Action m_contourAction; + private Action m_moduleAction; + private Action m_includeAction; + private Action m_selectNextAction; + private Action m_roundAction; + private Action m_propertyAction; + private Action m_convertControlPointAction; + private Action m_convertContourAction; + + private String m_msgAlreadyExists = " already exists!"; + private String m_msgNoTypeface = "no typeface"; + private String m_msgEmptyGlyphTitle = "glyph title is empty"; + private String m_msgGlyphName = "glyph name?"; + private String m_msgCircular = "circular include!"; + private String m_msgNoJis = "Charset ISO-2022-JP is not supported.\n" + + "Please include charsets.jar in classpath."; + + // -------------------------------------------------------------- + + private Engine() { + //GlyphFactory.setFactory(new EGlyphFactory()); + + + + m_typeface = null; + m_root = null; + + m_clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + m_actives = ActiveList.getSingletonInstance(); + + initActions(); + } + + private void initActions() { + + } + + public Action [] buildCommands() { + ArrayList actions = buildCommandsArrayList(); + Action [] retval = new Action[actions.size()]; + int i; + for (i = 0; i < actions.size(); i++) { + retval[i] = (Action) actions.get(i); + } // for i + + return retval; + } + + private ArrayList buildCommandsArrayList() { + ArrayList retval = new ArrayList<>(); + + if (m_root == null) { + return retval; + } // if + + if (m_actives.hasActiveContour()) { + retval.add(m_convertContourAction); + } + + if (m_actives.hasActiveControlPoint()) { + EControlPoint controlPoint = m_actives.getActiveControlPoint(); + retval.add(m_convertControlPointAction); + } + + if (m_actives.hasActivePoint()) { + EContourPoint point = m_actives.getActivePoint(); + + retval.add(m_toggleAction); + + if (!point.isRounded()) { + retval.add(m_hintAction); + } // if + + if (!point.hasHintForCurrentPpem()) { + retval.add(m_roundAction); + } // if + } // if + + if (m_actives.size() > 0) { + // retval.add(m_propertyAction); + retval.add(m_deleteAction); + } // if + + if (m_actives.hasActivePoint()) { + retval.add(m_addPointAction); + } // if + + /*if (!GlyphAction.isPointVisible()) { + retval.add(m_moduleAction); + retval.add(m_contourAction); + retval.add(m_includeAction); + } // if*/ + + return retval; + } + + public void localize(ResourceBundle a_bundle) { + m_msgAlreadyExists = a_bundle.getString("msgAlreadyExists"); + m_msgNoTypeface = a_bundle.getString("msgNoTypeface"); + m_msgEmptyGlyphTitle = a_bundle.getString("msgEmptyGlyphTitle"); + m_msgGlyphName = a_bundle.getString("msgGlyphName"); + m_msgCircular = a_bundle.getString("msgCircular"); + } + + private void showPropertyDialog() { + if (m_actives.size() != 1) { + return; + } // if + + m_ui.showPropertyDialog(m_actives.get(0)); + } + + public void setUi(UiBridge a_ui) { + m_ui = a_ui; + } + + + + public void selectNext() { + if (m_root == null) { + return; + } // if + + m_root.selectNext(); + } + + public void delete() { + if (m_root == null) + return; + if (!m_actives.hasSelected()) { + return; + } // if + + m_root.remove(); + } + + public void cutToClipboard() { + if (m_root == null) + return; + if (!m_actives.hasSelected()) { + return; + } // if + + copyToClipboard(); + delete(); + } + + public void copyToClipboard() { + if (m_root == null) + return; + if (!m_actives.hasSelected()) { + return; + } // if + + String s = m_actives.getSelectedAsString(); + if (s.equals("")) { + return; + } // if + + StringSelection selection = new StringSelection(s); + + try { + m_clipboard.setContents(selection, selection); + } catch (Exception e) { + e.printStackTrace(); + } // try-catch + } + + public void pasteFromClipboard() { + if (m_root == null) + return; + Transferable content = null; + String s = ""; + + try { + content = m_clipboard.getContents(this); + if (content == null) + return; + s = (String) content.getTransferData(DataFlavor.stringFlavor); + if (s.equals("")) { + return; + } // if + } catch (Exception e) { + e.printStackTrace(); + return; + } // try-catch + + try { + m_root.addObjectFromClipboard(s); + } catch (GlyphFile.CircularIncludeException e) { + Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, m_msgCircular, e); + } + } + + public void setAdvanceWidth(int a_value) { + if (m_root == null) + return; + + m_root.setAdvanceWidth(a_value); + } + + public void moveLeft() { + move(new Point2D.Double(-1, 0)); + } + + public void moveUp() { + move(new Point2D.Double(0, 1)); + } + + public void moveDown() { + move(new Point2D.Double(0, -1)); + } + + public void moveRight() { + move(new Point2D.Double(1, 0)); + } + + private void move(Point2D a_delta) { + if (m_root == null) { + return; + } // if + + m_root.move(a_delta); + } + + public void buildNewTypeface(String a_name, File a_dir) throws FileNotFoundException { + if (a_name == null || a_name.equals("")) { + return; + } // if + + TypefaceFile typeface = new TypefaceFile(a_name, a_dir); + typeface.setAuthor("no body"); + DateFormat format = new SimpleDateFormat("yyyy"); + typeface.setCopyrightYear(format.format(new Date())); + typeface.setFontFamilyName(a_name); + typeface.setSubFamily("Regular"); + typeface.addCodePage(TTCodePage.US_ASCII.toString()); + typeface.addCodePage(TTCodePage.Latin_1.toString()); + + setTypeface(typeface); + } + + public void addDefaultGlyphs() throws FileNotFoundException { + m_typeface.addRequiredGlyphs(); + m_typeface.addBasicLatinGlyphs(); + } + + public void openTypeface() throws FileNotFoundException { + if (m_chooser == null) { + m_chooser = new JFileChooser(new File(AppSettings.getLastTypefaceDir())); + } // if + + m_chooser.setFileFilter(new TypefaceFileFilter()); + int returnVal = m_chooser.showOpenDialog(null); + + if (returnVal != JFileChooser.APPROVE_OPTION) { + return; + } // if + + AppSettings.setLastTypefaceDir(m_chooser.getSelectedFile().toString()); + openTypeface(m_chooser.getSelectedFile()); + } + + private void openTypeface(File a_file) throws FileNotFoundException { + setTypeface(new TypefaceFile(a_file)); + + if (m_typeface.addRequiredGlyphs()) { + } // if + } + + public void setTypeface(TypefaceFile a_typeface) { + m_typeface = a_typeface; + } + + public void changeUnicode(long a_unicode) throws FileNotFoundException { + if (m_typeface == null || m_root == null) { + return; + } // if + + m_typeface.setGlyphUnicode(m_root, a_unicode); + } + + public int findFile(long a_unicode) { + if (m_typeface == null) + return USER_CANCELLED; + + m_foundFileName = m_typeface.unicodeToFileName(a_unicode); + if (m_foundFileName != null) { + return FILE_FOUND; + } // if + + return FILE_NOT_FOUND; + } + + public String getFoundFileName() { + return m_foundFileName; + } + + + /** + * Create glyph out of given unicode, and add it to the typeface. + * @param a_unicode + */ + public GlyphFile addNewGlyph(long a_unicode) throws FileNotFoundException { + GlyphFile retval; + + retval = m_typeface.createGlyph(a_unicode); + addGlyphToTypeface(retval); + + return retval; + } + + public void checkUnicodeBlock(long a_unicode) throws FileNotFoundException { + TTUnicodeRange range = TTUnicodeRange.of(a_unicode); + if (range == null){ + return; + } + + if (m_typeface.containsUnicodeRange(range.toString())){ + return; + } + m_typeface.addUnicodeRange(range.toString()); + } + + private void addGlyphToTypeface(GlyphFile a_file) throws FileNotFoundException { + m_typeface.addGlyph(a_file); + + setRoot(a_file); + } + + public GlyphFile openGlyphFile(String a_fileName) { + ModuleManager manager = ModuleManager.getSingletonInstance(); + GlyphFile retval = manager.getReloadedGlyphFile(a_fileName); + setRoot(retval); + + return retval; + } + + public void removeGlyphFromTypeface(String a_fileName) { + if (m_typeface == null) + return; + + m_typeface.removeGlyph(a_fileName); + } + + public Font buildTrueType(boolean a_isDebug) { + Font retval = null; + + if (m_typeface == null) + return retval; + + + + try { + m_typeface.buildTTF(a_isDebug); + retval = m_typeface.getFont(); + } catch (Exception e) { + Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, null,e); + } // try-catch + + return retval; + } + + public void saveGlyph() throws FileNotFoundException { + if (m_root == null) + return; + + if (m_root.getGlyphTitle().equals("")) { + Logger.getLogger(Engine.class.getName()).log(Level.SEVERE, m_msgEmptyGlyphTitle); + return; + } // if + } + + public TypefaceFile getTypeface() { + return m_typeface; + } + + public File getGlyphPath() { + return m_typeface.getGlyphPath(); + } + + + public GlyphFile getRoot() { + return m_root; + } + + public void setRoot(GlyphFile a_file) { + m_root = a_file; + } + + public String includeFileName() { + String retval = ""; + + JFileChooser chooser = new JFileChooser(getGlyphPath()); + chooser.setFileFilter(new GlyphFileFilter()); + + int returnVal = chooser.showOpenDialog(null); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + retval = chooser.getSelectedFile().getName().toString(); + } // if + + return retval; + } + + public void addCodePage(String a_codePage) throws FileNotFoundException { + if (m_typeface == null) { + return; + } // if + + m_typeface.addCodePage(a_codePage); + } + + public void removeCodePage(String a_codePage) throws FileNotFoundException { + if (m_typeface == null) { + return; + } // if + + m_typeface.removeCodePage(a_codePage); + } + + public void setAuthor(String a_value) throws FileNotFoundException { + if (m_typeface == null) { + return; + } // if + + m_typeface.setAuthor(a_value); + } + + public void setCopyrightYear(String a_value) throws FileNotFoundException { + if (m_typeface == null) { + return; + } // if + + m_typeface.setCopyrightYear(a_value); + } + + public void setFontFamilyName(String a_value) throws FileNotFoundException { + if (m_typeface == null) { + return; + } // if + + m_typeface.setFontFamilyName(a_value); + } + + public void setTypefaceLicense(String a_value) throws FileNotFoundException { + if (m_typeface == null) { + return; + } // if + + m_typeface.setLicense(a_value); + } + + public void setBaseline(double a_value) throws FileNotFoundException { + if (m_typeface == null) { + return; + } // if + + double min = m_typeface.getBottomSideBearing(); + double max = m_typeface.getMeanline(); + + if (a_value < min) { + a_value = min; + } // if + + if (a_value > max) { + a_value = max; + } // if + + try { + m_typeface.setDescender(a_value - min); + m_typeface.setAscender(m_typeface.getEm() + - m_typeface.getTopSideBearing() - a_value); + m_typeface.setXHeight(max - a_value); + } + catch (OutOfRangeException e) { + e.printStackTrace(); + } // try-catch + } + + public void setMeanline(double a_value) throws FileNotFoundException { + if (m_typeface == null) { + return; + } // if + + double min = m_typeface.getBaseline(); + double max = m_typeface.getEm() + - m_typeface.getTopSideBearing(); + + if (a_value < min) { + a_value = min; + } // if + + if (a_value > max) { + a_value = max; + } // if + + try { + m_typeface.setXHeight(a_value - min); + } + catch (OutOfRangeException e) { + e.printStackTrace(); + } // try-catch + } + + public void mousePressed(MouseEvent a_event) { + + } + + + public void mouseDragged(MouseEvent a_event) { + + } + + public void mouseReleased(MouseEvent a_event) { + + } + + public void setAction(String a_key) { + + } + + public void keyPressed(KeyEvent a_event) { + if (a_event.getModifiers() == 0) { + if (a_event.getKeyCode() == KeyEvent.VK_TAB) { + + m_selectNextAction.actionPerformed(null); + } // if + } else if (a_event.getModifiers() == KeyEvent.SHIFT_MASK) { + + } // if + } + + private JFileChooser createImageChooser() { + JFileChooser retval; + + retval = new JFileChooser(new File(AppSettings.getLastTypefaceDir())); + retval.setFileFilter(new javax.swing.filechooser.FileFilter() { + public boolean accept(File a_file) { + if (a_file.isDirectory()) + return true; + + String s = a_file.toString().toLowerCase(); + if (s.endsWith(".gif") + || s.endsWith(".jpg") + || s.endsWith(".jpeg") + || s.endsWith(".png")) + return true; + + return false; + } + + //The description of this filter + public String getDescription() { + return "Image Files"; + } + }); + + return retval; + } + + + + + public ArrayList getPixelSizes() { + return TTPixelSize.getList(); + } + + class MyTreeListener implements TreeSelectionListener { + public void valueChanged(TreeSelectionEvent a_event) { + TreePath path = a_event.getPath(); + Object obj = path.getLastPathComponent(); + String s = obj.toString(); + + TreePath parent = path.getParentPath(); + if (parent != null) { + obj = parent.getLastPathComponent(); + s = obj.toString() + "->" + s; + } // if + + } + } + +} diff --git a/libsrc/ttf/src/org/doubletype/ossa/HistoryList.java b/libsrc/ttf/src/org/doubletype/ossa/HistoryList.java deleted file mode 100644 index 53fe5e867..000000000 --- a/libsrc/ttf/src/org/doubletype/ossa/HistoryList.java +++ /dev/null @@ -1,104 +0,0 @@ - /* - * $Id: HistoryList.java,v 1.1 2004/09/05 17:08:03 eed3si9n Exp $ - * - * $Copyright: copyright (c) 2004, e.e d3si9n $ - * $License: - * This source code is part of DoubleType. - * DoubleType is a graphical typeface designer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * In addition, as a special exception, e.e d3si9n gives permission to - * link the code of this program with any Java Platform that is available - * to public with free of charge, including but not limited to - * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), - * and distribute linked combinations including the two. - * You must obey the GNU General Public License in all respects for all - * of the code used other than Java Platform. If you modify this file, - * you may extend this exception to your version of the file, but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. - * $ - */ - -package org.doubletype.ossa; - -import java.util.*; -import org.doubletype.ossa.module.GlyphFile; - -/** Caretaker of MementoPattern. - * @author e.e - */ -public class HistoryList { - private GlyphFile m_file; - private ArrayList m_list = new ArrayList<>(); - private int m_index = -1; - - - public HistoryList(GlyphFile a_file) { - m_file = a_file; - } - - private void printHistoryArray() { - int i; - for (i = 0; i <= m_index; i++) { - Memento memento = m_list.get(i); - System.out.println(memento.toString()); - } // for i - } - - /** - * Records snapshot into history queue. - * Takes place after each action. - * Updates modified time with the current system time. - * @param a_description - */ - public void record(String a_description) { - add(m_file.createMemento(a_description)); - } - - private void add(Memento a_memento) { - while (m_list.size() - 1 > m_index) { - m_list.remove(m_list.size() - 1); - } // if - - m_list.add(a_memento); - m_index = m_list.size() - 1; - } - - public void undo() { - if (m_list.size() == 0 - || m_index <= 0) { - return; - } // if - - m_index--; - m_file.restore(get(m_index)); - } - - public void redo() { - if (m_list.size() == 0 - || m_index >= m_list.size() - 1) { - return; - } // if - - m_index++; - m_file.restore(get(m_index)); - } - - private Memento get(int a_index) { - return m_list.get(a_index); - } -} diff --git a/libsrc/ttf/src/org/doubletype/ossa/module/GlyphFile.java b/libsrc/ttf/src/org/doubletype/ossa/module/GlyphFile.java index fd57a24d3..bdd5d618b 100644 --- a/libsrc/ttf/src/org/doubletype/ossa/module/GlyphFile.java +++ b/libsrc/ttf/src/org/doubletype/ossa/module/GlyphFile.java @@ -1,1141 +1,1079 @@ - /* - * $Copyright: copyright (c) 2003-2008, e.e d3si9n $ - * $License: - * This source code is part of DoubleType. - * DoubleType is a graphical typeface designer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * In addition, as a special exception, e.e d3si9n gives permission to - * link the code of this program with any Java Platform that is available - * to public with free of charge, including but not limited to - * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), - * and distribute linked combinations including the two. - * You must obey the GNU General Public License in all respects for all - * of the code used other than Java Platform. If you modify this file, - * you may extend this exception to your version of the file, but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. - * $ - */ - -package org.doubletype.ossa.module; - -import org.doubletype.ossa.*; -import org.doubletype.ossa.xml.*; -import org.doubletype.ossa.adapter.*; -import org.doubletype.ossa.truetype.*; - -import java.io.*; -import java.awt.*; -import java.awt.geom.*; - -import javax.xml.transform.*; -import javax.xml.transform.stream.*; -import javax.xml.transform.dom.*; -import java.net.*; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.w3c.dom.*; -import javax.xml.parsers.*; -import org.xml.sax.*; - -/** - * @author e.e - */ -public class GlyphFile extends GlyphModule { - protected static String s_emptyFileName = "empty.glyph"; - private static final String k_dotGlyph = ".glyph"; - private static Transformer s_transformer = null; - - static { - GlyphFactory.setFactory(EGlyphFactory.getFactory()); - } - - public static File createFileName(File a_dir, String a_name) { - return new File(a_dir, a_name + k_dotGlyph); - } - - /** - * http://www.atmarkit.co.jp/fxml/rensai2/xmltool04/02.html - * @return - */ - private static Transformer getTransformer() { - if (s_transformer == null) { - TransformerFactory transFactory - = TransformerFactory.newInstance(); - try { - s_transformer = transFactory.newTransformer(); - } - catch (TransformerConfigurationException e) { - } - - s_transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - s_transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - } // if - - return s_transformer; - } - - private static XStartGlyphElement loadGlyphElement(URL a_url) { - IGlyphFactory factory = GlyphFactory.getFactory(); - - XStartGlyphElement retval = null; - - try { - retval = factory.createXStartGlyphElement(a_url); - } catch( SAXException | ParserConfigurationException | IOException e) { - e.printStackTrace(); - } - - return retval; - } - - private static XStartGlyphElement loadGlyphElement(InputStream a_in) { - IGlyphFactory factory = GlyphFactory.getFactory(); - XStartGlyphElement retval = null; - - try { - retval = factory.createXStartGlyphElement(a_in); - } catch( SAXException | ParserConfigurationException | IOException e) { - e.printStackTrace(); - } - - return retval; - } - // -------------------------------------------------------------- - - protected XStartGlyphElement m_glyph; - protected File m_fileName; - protected long m_modifiedTime = 0; - protected long m_savedTime = 0; - protected HistoryList m_history; - - private final int k_halfWidth = 512; - private final int k_fullWidth = 1024; - private String m_selectedNodeName = ""; - private boolean m_isMoving = false; - private PointAggregate m_pointHost; - - - // -------------------------------------------------------------- - - /** - * creates new file - */ - public GlyphFile(File a_dir, String a_name, long a_unicode) throws FileNotFoundException { - super(); - - m_fileName = createFileName(a_dir, a_name); - - init(getClass().getResource(s_emptyFileName)); - setGlyphTitle(a_name); - setUnicode(Long.toHexString(a_unicode)); - - /*int eastAsianWidth = UCharacter.getIntPropertyValue( - (int) a_unicode, - 0x1004); //UProperty.EAST_ASIAN_WIDTH); - */ - int eastAsianWidth = 5; //?? - if (eastAsianWidth == 5 || eastAsianWidth == 1) { - setAdvanceWidth(k_fullWidth); - } // if - - saveGlyphFile(); - } - - /** - * creates new file - * @param a_dir parent dir - * @param a_name glyph name - */ - public GlyphFile(File a_dir, String a_name) throws FileNotFoundException { - super(); - init(getClass().getResource(s_emptyFileName)); - setGlyphTitle(a_name); - m_fileName = createFileName(a_dir, a_name); - saveGlyphFile(); - } - - /** - * opens existing file - * @param a_file - */ - public GlyphFile(File a_file) { - super(); - - m_fileName = a_file; - - URL url = null; - - try { - url = a_file.toURI().toURL(); - } catch(MalformedURLException e) { - e.printStackTrace(); - } - - init(url); - } - - protected GlyphFile(URL a_url) { - super(); - init(a_url); - } - - private void init(URL a_url) { - m_glyph = loadGlyphElement(a_url); - ModuleManager.getSingletonInstance().clear(); - - //m_display = Engine.getSingletonInstance().getDisplay(); - m_history = new HistoryList(this); - - m_history.record("loadFile"); - m_savedTime = m_modifiedTime; - } - - /** - * initialize .notdef - */ - public void initNotDef(int a_advanceWidth) throws FileNotFoundException { - setAdvanceWidth(a_advanceWidth); - - EContour contour = new EContour(); - contour.setType(EContour.k_cubic); - contour.addContourPoint(new EContourPoint(0.0, 0.0, true)); - contour.addContourPoint(new EContourPoint(438.0, 0.0, true)); - contour.addContourPoint(new EContourPoint(438.0, 683.0, true)); - contour.addContourPoint(new EContourPoint(0.0, 683.0, true)); - addContour(contour); - - contour = new EContour(); - contour.setType(EContour.k_cubic); - contour.addContourPoint(new EContourPoint(365.0, 73.0, true)); - contour.addContourPoint(new EContourPoint(73.0, 73.0, true)); - contour.addContourPoint(new EContourPoint(73.0, 610.0, true)); - contour.addContourPoint(new EContourPoint(365.0, 610.0, true)); - addContour(contour); - - saveGlyphFile(); - } - - public void initNullGlyph() throws FileNotFoundException { - setAdvanceWidth(0); - saveGlyphFile(); - } - - public void initSpace(int a_advanceWidth) throws FileNotFoundException { - setAdvanceWidth(a_advanceWidth); - saveGlyphFile(); - } - - public void beforePush() { - loadVar(); - } - - public void undo() { - m_history.undo(); - } - - public void redo() { - m_history.redo(); - } - - public void restore(Memento a_memento) { - m_glyph = loadGlyphElement(a_memento.getData()); - ModuleManager.getSingletonInstance().clear(); - } - - // -------------------------------------------------------------- - - public XStartGlyphElement getGlyph() { - return m_glyph; - } - - // -------------------------------------------------------------- - - public void saveGlyphFile() throws FileNotFoundException { - saveGlyphFile(m_fileName); - } - - protected void saveGlyphFile(File a_file) throws FileNotFoundException { - FileOutputStream output = new FileOutputStream(a_file); - saveGlyphFile(output); - try { - output.close(); //JPEXS - } catch (IOException ex) { - Logger.getLogger(GlyphFile.class.getName()).log(Level.SEVERE, null, ex); - } - } - - public void saveGlyphFile(OutputStream a_output) { - try { - Transformer transformer = getTransformer(); - Document document = m_glyph.makeDocument(); - DOMSource source = new DOMSource(document); - StreamResult result = new StreamResult(a_output); - transformer.transform(source, result); - } catch (ParserConfigurationException | TransformerException e) { - e.printStackTrace(); - } - - m_savedTime = System.currentTimeMillis(); - m_modifiedTime = m_savedTime; - } - - public Memento createMemento(String a_description) { - m_modifiedTime = System.currentTimeMillis(); - byte [] bytes = m_glyph.makeTextDocument().getBytes(); - return new Memento(a_description, bytes); - } - - public boolean hasUnsavedChange() { - return (m_savedTime != m_modifiedTime); - } - - public void setAuthor(String a_value) { - m_glyph.getHead().setAuthor(a_value); - m_history.record("setAuthor"); - } - - public String getAuthor() { - return m_glyph.getHead().getAuthor(); - } - - public void setCopyrightYear(String a_value) { - m_glyph.getHead().setCopyright(a_value); - m_history.record("setCopyrightYear"); - } - - public String getCopyrightYear() { - return m_glyph.getHead().getCopyright(); - } - - public void setAdvanceWidth(int a_width) { - m_glyph.getHead().setAdvanceWidth(a_width); - m_history.record("setAdvanceWidth"); - } - - public int getAdvanceWidth() { - if (!m_glyph.getHead().checkAdvanceWidth()) { - setAdvanceWidth(k_halfWidth); - } // if - - return (int) m_glyph.getHead().getAdvanceWidth(); - } - - public Iterator createIterator() { - return new GlyphIterator(this); - } - - - // -------------------------------------------------------------- - - public void display(Graphics2D g, AffineTransform a_trans) - { - Iterator i = createIterator(); - while (i.hasNext()) { - GlyphObject object = (GlyphObject) i.next(); - object.display(g, a_trans); - } // while - } - - // -------------------------------------------------------------- - - public static final int k_defaultPixelSize = 16; //PPM - - /** converts this glyph into Shape. - * It could be called for root's preview mode or by include invoke. - * Pushing either this GlyphFile or DIncludeInvoke should be - * handled before this. - */ - public Shape toShape(AffineTransform a_trans) { - - - int ppem = k_defaultPixelSize; - - GeneralPath retval = new GeneralPath(); - Iterator i = createIterator(); - while (i.hasNext()) { - GlyphObject object = (GlyphObject) i.next(); - - if (object instanceof EContourPoint - || object instanceof EHint) { - continue; - } // if - - retval.append(object.toShape(a_trans, ppem), false); - } // if - - return retval; - } - - // -------------------------------------------------------------- - - /** - * Generates array of XContour from local contours and modules. - * Used for TTF building. - */ - private XContour [] toContours() { - XContour [] retval; - ArrayList list = new ArrayList<>(); - XContour [] contours = m_glyph.getBody().getContour(); - for (int i = 0; i < contours.length; i++) { - EContour contour = (EContour) contours[i]; - list.add(contour.toQuadratic()); - } // for i - - XModule [] modules = m_glyph.getBody().getModule(); - for (int i = 0; i < modules.length; i++) { - EModuleInvoke module = (EModuleInvoke) modules[i]; - - // push and pop happens inside toContour - list.add(module.toContour(new AffineTransform())); - } // for i - - if (list.size() == 0) - return null; - - retval = new XContour[list.size()]; - for (int i = 0; i < list.size(); i++) { - retval[i] = list.get(i); - } // for i - - return retval; - } - - // -------------------------------------------------------------- - - public boolean isMoving() { - return m_isMoving; - } - - // -------------------------------------------------------------- - - public void beginMove() { - m_isMoving = true; - } - - // -------------------------------------------------------------- - - public void endMove() { - if (!m_isMoving) { - return; - } // if - - m_isMoving = false; - - m_history.record("move"); - } - - // -------------------------------------------------------------- - - public void move(Point2D a_delta) { - int i; - for (i = 0; i < m_actives.size(); i++) { - GlyphObject active = m_actives.get(i); - active.move(a_delta); - } // for i - } - - - // -------------------------------------------------------------- - - public void fitMove() { - if (m_actives.hasActiveControlPoint()) { - EControlPoint controlPoint = m_actives.getActiveControlPoint(); - controlPoint.rotateTo45(); - } // if - } - - // -------------------------------------------------------------- - - public boolean isHittingSelected(Point2D a_point) { - ActiveList oldActiveObjects = new ActiveList(); - oldActiveObjects.setActives(m_actives); - - m_actives.unselectAll(); - hit(a_point, false, false); - - int i, j; - for (i = 0; i < m_actives.size(); i++) { - GlyphObject selected = m_actives.get(i); - for (j = 0; j < oldActiveObjects.size(); j++) { - GlyphObject old = oldActiveObjects.get(j); - - if (selected == old) { - m_actives.setActives(oldActiveObjects); - return true; - } // if - } // for j - } // for i - - m_actives.setActives(oldActiveObjects); - - return false; - } - - // -------------------------------------------------------------- - - /** hits a point to add them in active object queue. - * @param a_single when it is true, the method returns after - * finding the first hit. - */ - public boolean hit(Point2D a_point, - boolean a_isAppend, - boolean a_isSelectOnlyOne) { - if (a_point == null) { - return false; - } // if - - Rectangle2D rect = new Rectangle2D.Double( - a_point.getX(), a_point.getY(), - 1.0, 1.0); - return hit(rect, a_isAppend, a_isSelectOnlyOne); - } - - public void selectNext() { - Iterator i = new SelectionIterator(this); - - if (m_actives.size() == 1) { - boolean isFound = false; - - // loop the iterator in reverse order of drawing - while (i.hasNext()) { - GlyphObject object = (GlyphObject) i.next(); - - if (m_actives.isSelected(object)) { - isFound = true; - continue; - } // if - - if (!isFound) { - continue; - } // if - - m_actives.unselectAll(); - m_actives.addActive(object); - return; - } // while i - } // if - - i = new SelectionIterator(this); - if (i.hasNext()) { - GlyphObject object = (GlyphObject) i.next(); - m_actives.unselectAll(); - m_actives.addActive(object); - return; - } // if - } - - // -------------------------------------------------------------- - - public boolean hit(Rectangle2D a_rect, - boolean a_isAppend, - boolean a_single) { - - - if (!a_isAppend) { - m_actives.unselectAll(); - } // if - - return hitObjects(a_rect, a_single); - } - - // -------------------------------------------------------------- - - private boolean hitObjects(Rectangle2D a_rect, boolean a_isSelectOnlyOne) { - boolean retval = false; - - Iterator i = new SelectionIterator(this); - - // loop the iterator in reverse order of drawing - while (i.hasNext()) { - GlyphObject object = (GlyphObject) i.next(); - - if (!object.hit(a_rect, new AffineTransform())) { - continue; - } // if - - retval = true; - - if (a_isSelectOnlyOne) { - return true; - } // if - } // while i - - return retval; - } - - // -------------------------------------------------------------- - - /** used for cut and paste. - */ - public void addObjectFromClipboard(String a_value) throws CircularIncludeException { - Reader reader = new StringReader(a_value); - Document document = null; - try { - document = UJAXP.getDocument(reader); - } catch (Exception e) { - e.printStackTrace(); - return; - } // try-catch - - Element root = document.getDocumentElement(); - if (!root.getNodeName().equals("clipboard")) { - return; - } // if - - Node child; - for (child = root.getFirstChild(); child != null; - child = child.getNextSibling()) { - if (!(child instanceof Element)) { - continue; - } // if - Element element = (Element) child; - - IGlyphFactory factory = GlyphFactory.getFactory(); - - - if (XModule.isMatch(element)) { - EModuleInvoke module = (EModuleInvoke) factory.createXModule(element); - addModule(module); - continue; - } // if - - if (XContour.isMatch(element)) { - EContour contour = (EContour) factory.createXContour(element); - addContour(contour); - continue; - } // if - - if (XInclude.isMatch(element)) { - EIncludeInvoke include = (EIncludeInvoke) factory.createXInclude(element); - addInclude(include); - continue; - } // if - } // while - } - - // -------------------------------------------------------------- - - private boolean isCircularInclude(String a_href) { - if (getShortFileName().equals(a_href)) { - return true; - } // if - - ModuleManager manager = ModuleManager.getSingletonInstance(); - XInclude [] includes = m_glyph.getBody().getInclude(); - int i; - for (i = 0; i < includes.length; i++) { - XInclude include = includes[i]; - GlyphFile child = manager.getGlyphFile(include.getHref()); - - if (child.isCircularInclude(a_href)) { - return true; - } // if - } // for i - - return false; - } - - // -------------------------------------------------------------- - - public void addInclude(String a_fileName) throws CircularIncludeException { - addInclude(EIncludeInvoke.create(a_fileName)); - } - - public void addInclude(XInclude a_include) throws CircularIncludeException { - if (isCircularInclude(a_include.getHref())) { - throw new CircularIncludeException(); - } // if - - m_actives.unselectAll(); - m_actives.addActive((GlyphObject) a_include); - m_glyph.getBody().addInclude(a_include); - m_history.record("addInclude"); - } - - // -------------------------------------------------------------- - - /** - * pasted module from clipboard or ModuleInvokeAction - * @param a_module - */ - public XModule addModule(EModuleInvoke a_module) { - m_actives.unselectAll(); - m_actives.addActive(a_module); - m_glyph.getBody().addModule(a_module); - m_history.record("addModule"); - - return a_module; - } - - // -------------------------------------------------------------- - - /** add contour from clipboard or ContourAction - * @param a_contour - */ - public void addContour(EContour a_contour) { - m_actives.unselectAll(); - m_actives.addActive(a_contour); - m_glyph.getBody().addContour(a_contour); - m_history.record("addContour"); - } - - - // -------------------------------------------------------------- - - - public void addPoint() { - if (!m_actives.hasActivePoint()) { - return; - } // if - - EContourPoint contourPoint = m_actives.getActivePoint(); - m_actives.unselectAll(); - m_actives.addActive(contourPoint.add()); - - m_history.record("addPoint"); - } - - // -------------------------------------------------------------- - - public void addHint(int a_ppem) { - if (!m_actives.hasActivePoint()) - return; - - EContourPoint contourPoint = m_actives.getActivePoint(); - m_actives.unselectAll(); - m_actives.addActive(contourPoint.addHint(a_ppem)); - - if (contourPoint.hasControlPoint1()) { - EContourPoint p = (EContourPoint) contourPoint.getControlPoint1().getContourPoint(); - m_actives.addActive(p.addHint(a_ppem)); - } // if - - if (contourPoint.hasControlPoint2()) { - EContourPoint p = (EContourPoint) contourPoint.getControlPoint2().getContourPoint(); - m_actives.addActive(p.addHint(a_ppem)); - } // if - - - m_history.record("addHint"); - } - - public void toggleRounded() { - if (!m_actives.hasActivePoint()) - return; - - EContourPoint contourPoint = m_actives.getActivePoint(); - contourPoint.toggleRounded(); - - m_history.record("toggleGridfit"); - } - - public void convertControlPoint() { - if (!m_actives.hasActiveControlPoint()) { - return; - } // if - - EControlPoint controlPoint = m_actives.getActiveControlPoint(); - controlPoint.convert(); - - m_history.record("convertControlPoint"); - } - - public void convertContour() { - if (!m_actives.hasActiveContour()) { - return; - } // if - - EContour contour = m_actives.getActiveContour(); - contour.convert(); - - m_history.record("convertContour"); - } - - // -------------------------------------------------------------- - - public void remove() { - if (!m_actives.hasSelected()) - return; - - int i; - for (i = 0; i < m_actives.size(); i++) { - GlyphObject active = m_actives.get(i); - active.remove(); - } // for i - - m_history.record("remove"); - - m_actives.unselectAll(); - } - - // -------------------------------------------------------------- - - public void toggleOnOff() { - if (!m_actives.hasSelected()) - return; - - int i; - for (i = 0; i < m_actives.size(); i++) { - GlyphObject active = m_actives.get(i); - if (!(active instanceof EContourPoint)) { - continue; - } // if - - EContourPoint point = (EContourPoint) active; - point.toggleOnCurve(); - } // for i - - m_history.record("toggleOnOff"); - } - - private void loadVar() { - XParamListParam [] params = m_glyph.getHead().getHeadGlobal().getParamListParam(); - int i; - for (i = 0; i < params.length; i++) { - XParamListParam param = params[i]; - addVar(param.getName(), param.getContent()); - } // for i - } - - public String getSelectedNodeName() { - return m_selectedNodeName; - } - - public void addFileVar() { - XParamListParam param = new XParamListParam(); - param.setName("New parameter"); - param.setContent(0.0); - m_history.record("addFileVar"); - - m_glyph.getHead().getHeadGlobal().addParamListParam(param); - } - - public void removeFileVar(int a_index) { - m_history.record("removeFileVar"); - - m_glyph.getHead().getHeadGlobal().removeParamListParam(a_index); - } - - - public void addInvokeArg(int a_type) { - - } - - public void removeInvokeArg(int a_type, int a_index) { - - } - - public String getIncludeName() { - String retval = ""; - - if (!m_actives.hasActiveInclude()) - return retval; - retval = m_actives.getActiveInclude().getHref(); - - return retval; - } - - public void setIncludeName(String a_name) { - if (!m_actives.hasActiveInclude()) - return; - - m_actives.getActiveInclude().setHref(a_name); - m_history.record("setIncludeName"); - } - - public void setGlyphTitle(String a_title) { - m_glyph.getHead().setTitle(a_title); - m_history.record("setGlyphTitle"); - } - - public String getGlyphTitle() { - String retval = ""; - - retval = m_glyph.getHead().getTitle(); - - if (retval.equals("empty")) { - retval = ""; - } // if - - return retval; - } - - public String getModuleName() { - String retval = ""; - - if (!m_actives.hasActiveModule()) - return retval; - retval = m_actives.getActiveModule().getName(); - - return retval; - } - - public String getUnicode() { - return getUnicodeAsString(); - } - - public String getUnicodeAsString() { - return m_glyph.getHead().getUnicode(); - } - - public long getUnicodeAsLong() { - long retval = -1; - - String s = getUnicodeAsString(); - if (s.equals("")) { - return retval; - } // if - - try { - retval = Long.parseLong(s, 16); - } catch (NumberFormatException e) { - retval = -1; - } // try-catch - - return retval; - } - - protected void setUnicode(String a_unicode) { - m_glyph.getHead().setUnicode(a_unicode); - m_history.record("setUnicode"); - } - - public boolean isSimple() { - return (m_glyph.getBody().getInclude().length == 0); - } - - public boolean isWhiteSpace() { - long unicode = getUnicodeAsLong(); - - if (unicode == 0x0020 - || unicode == 0x00a0 - || unicode == 0x200b - || unicode == 0x2060 - || unicode == 0x3000 - || unicode == 0xfeff) - { - return true; - } // if - - return false; - } - - public String getShortFileName() { - return m_fileName.getName(); - } - - public void setLicense(String a_value) { - m_glyph.getHead().setLicense(a_value); - m_history.record("setLicense"); - } - - public String getLicense() { - return m_glyph.getHead().getLicense(); - } - - public PointAggregate getPointHost() { - return m_pointHost; - } - - public void buildPointHost() { - m_pointHost = null; - - /*if (!GlyphAction.isPointVisible()) { - return; - } // if*/ - - int i; - for (i = 0; i < m_actives.size(); i++) { - GlyphObject object = (GlyphObject) m_actives.get(i); - PointAggregate host = null; - - if (object instanceof EContourPoint) { - EContourPoint point = (EContourPoint) object; - host = point.getParent(); - - if (host instanceof EContourPoint) { - EContourPoint hostPoint = (EContourPoint) host; - host = hostPoint.getParent(); - } // if - } else if (object instanceof EHint) { - EHint hint = (EHint) object; - host = hint.getPointHost(); - } // if-else - - if (host == null) { - continue; - } // if - - if (m_pointHost == null) { - m_pointHost = host; - } else { - if (m_pointHost != host) { - m_pointHost = null; - return; - } // if - } // if - } // while - } - - public boolean isRequiredGlyph() { - long unicode = getUnicodeAsLong(); - - return (unicode == TTUnicodeRange.k_notDef - || unicode == TTUnicodeRange.k_null - || unicode == TTUnicodeRange.k_cr - || unicode == TTUnicodeRange.k_space); - } - - public TTGlyph toSimpleGlyph() { - // convert the file into array of contours - XContour [] contours = toContours(); - if ((contours == null) && (!isRequiredGlyph())) { - return null; - } // if - - TTGlyph retval = new TTGlyph(); - retval.setSimple(true); - retval.setAdvanceWidth(getAdvanceWidth()); - - if (contours == null) { - return retval; - } // if - - ArrayList points = new ArrayList<>(); - for (int i = 0; i < contours.length; i++) { - XContour contour = contours[i]; - XContourPoint [] contourPoints = contour.getContourPoint(); - for (int j = 0; j < contourPoints.length; j++) { - points.add((EContourPoint) contourPoints[j]); - } // for j - retval.addEndPoint(points.size() - 1); - } // for i - - for (EContourPoint point: points) { - loadContourPoint(retval, point); - } // for point - - boolean hasGridfit = false; - // I need int i here. - for (int i = 0; i < points.size(); i++) { - EContourPoint point = points.get(i); - - if (!point.isRounded()) { - continue; - } // if - - hasGridfit = true; - loadGridfit(retval, point, i); - } // for i - - if (hasGridfit) { - retval.addInstruction(TTGlyph.IUP1); - retval.addInstruction(TTGlyph.IUP0); - } // if - - // I need int i here. - for (int i = 0; i < points.size(); i++) { - EContourPoint point = points.get(i); - if (point.getHint().length == 0) { - continue; - } // if - - loadHint(retval, point, i); - } // for i - - return retval; - } - - private void loadContourPoint(TTGlyph a_glyph, EContourPoint a_point) { - double x = a_point.getX(); - double y = a_point.getY(); - Point p = new Point((int) x, (int) y); - int flag = 0; - if (a_point.isOn()) { - flag = TTGlyph.k_onCurve; - } // if - - a_glyph.addPoint(p); - a_glyph.addFlag(flag); - } - - private void loadGridfit(TTGlyph a_glyph, EContourPoint a_point, int a_index) { - if (!a_point.isRounded()) { - return; - } // if - - a_glyph.addInstruction(TTGlyph.PUSHB000); - a_glyph.addInstruction(a_index); - a_glyph.addInstruction(TTGlyph.MDAP1); - } - - - private void loadHint(TTGlyph a_glyph, EContourPoint a_point, int a_index) { - double x = a_point.getX(); - double y = a_point.getY(); - - XHint [] hints = a_point.getHint(); - - for (int i = 0; i < hints.length; i++) { - EHint hint = (EHint) hints[i]; - double xHint = hint.getX(); - double yHint = hint.getY(); - - if (x == xHint && y == yHint) { - continue; - } // if - - double xDelta = xHint - x; - double yDelta = yHint - y; - int instruction = TTGlyph.DELTAP1; - double deltaStep = ((double) Engine.getEm()) / hint.getPpem() / 8; - int xShift = (int) Math.round(xDelta / deltaStep); - int yShift = (int) Math.round(yDelta / deltaStep); - - if (xShift == 0 && yShift == 0) { - continue; - } // if - - a_glyph.addInstruction(TTGlyph.PUSHB000); - a_glyph.addInstruction((int) hint.getPpem()); - a_glyph.addInstruction(TTGlyph.SDB); - - if (xShift != 0) { - a_glyph.addInstruction(TTGlyph.SVTCA1); - a_glyph.addInstruction(TTGlyph.PUSHB010); - a_glyph.addInstruction(TTGlyph.toDeltaArg(0, xShift)); - a_glyph.addInstruction(a_index); - a_glyph.addInstruction(1); - a_glyph.addInstruction(TTGlyph.DELTAP1); - } // if - - if (yShift != 0) { - a_glyph.addInstruction(TTGlyph.SVTCA0); - a_glyph.addInstruction(TTGlyph.PUSHB010); - a_glyph.addInstruction(TTGlyph.toDeltaArg(0, yShift)); - a_glyph.addInstruction(a_index); - a_glyph.addInstruction(1); - a_glyph.addInstruction(TTGlyph.DELTAP1); - } // if - } // for i - } - - public class CircularIncludeException extends Exception {} + /* + * $Copyright: copyright (c) 2003-2008, e.e d3si9n $ + * $License: + * This source code is part of DoubleType. + * DoubleType is a graphical typeface designer. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * In addition, as a special exception, e.e d3si9n gives permission to + * link the code of this program with any Java Platform that is available + * to public with free of charge, including but not limited to + * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), + * and distribute linked combinations including the two. + * You must obey the GNU General Public License in all respects for all + * of the code used other than Java Platform. If you modify this file, + * you may extend this exception to your version of the file, but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. + * $ + */ + +package org.doubletype.ossa.module; + +import org.doubletype.ossa.*; +import org.doubletype.ossa.xml.*; +import org.doubletype.ossa.adapter.*; +import org.doubletype.ossa.truetype.*; + +import java.io.*; +import java.awt.*; +import java.awt.geom.*; + +import javax.xml.transform.*; +import javax.xml.transform.stream.*; +import javax.xml.transform.dom.*; +import java.net.*; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.w3c.dom.*; +import javax.xml.parsers.*; +import org.xml.sax.*; + +/** + * @author e.e + */ +public class GlyphFile extends GlyphModule { + protected static String s_emptyFileName = "empty.glyph"; + private static final String k_dotGlyph = ".glyph"; + private static Transformer s_transformer = null; + + static { + GlyphFactory.setFactory(EGlyphFactory.getFactory()); + } + + public static File createFileName(File a_dir, String a_name) { + return new File(a_dir, a_name + k_dotGlyph); + } + + /** + * http://www.atmarkit.co.jp/fxml/rensai2/xmltool04/02.html + * @return + */ + private static Transformer getTransformer() { + if (s_transformer == null) { + TransformerFactory transFactory + = TransformerFactory.newInstance(); + try { + s_transformer = transFactory.newTransformer(); + } + catch (TransformerConfigurationException e) { + } + + s_transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + s_transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + } // if + + return s_transformer; + } + + private static XStartGlyphElement loadGlyphElement(URL a_url) { + IGlyphFactory factory = GlyphFactory.getFactory(); + + XStartGlyphElement retval = null; + + try { + retval = factory.createXStartGlyphElement(a_url); + } catch( SAXException | ParserConfigurationException | IOException e) { + e.printStackTrace(); + } + + return retval; + } + + private static XStartGlyphElement loadGlyphElement(InputStream a_in) { + IGlyphFactory factory = GlyphFactory.getFactory(); + XStartGlyphElement retval = null; + + try { + retval = factory.createXStartGlyphElement(a_in); + } catch( SAXException | ParserConfigurationException | IOException e) { + e.printStackTrace(); + } + + return retval; + } + // -------------------------------------------------------------- + + protected XStartGlyphElement m_glyph; + protected File m_fileName; + protected long m_modifiedTime = 0; + protected long m_savedTime = 0; + + private final int k_halfWidth = 512; + private final int k_fullWidth = 1024; + private String m_selectedNodeName = ""; + private boolean m_isMoving = false; + private PointAggregate m_pointHost; + + + // -------------------------------------------------------------- + + /** + * creates new file + */ + public GlyphFile(File a_dir, String a_name, long a_unicode) { + super(); + + m_fileName = createFileName(a_dir, a_name); + + init(getClass().getResource(s_emptyFileName)); + setGlyphTitle(a_name); + setUnicode(Long.toHexString(a_unicode)); + + /*int eastAsianWidth = UCharacter.getIntPropertyValue( + (int) a_unicode, + 0x1004); //UProperty.EAST_ASIAN_WIDTH); + */ + int eastAsianWidth = 5; //?? + if (eastAsianWidth == 5 || eastAsianWidth == 1) { + setAdvanceWidth(k_fullWidth); + } // if + } + + /** + * creates new file + * @param a_dir parent dir + * @param a_name glyph name + */ + public GlyphFile(File a_dir, String a_name) throws FileNotFoundException { + super(); + init(getClass().getResource(s_emptyFileName)); + setGlyphTitle(a_name); + m_fileName = createFileName(a_dir, a_name); + } + + /** + * opens existing file + * @param a_file + */ + public GlyphFile(File a_file) { + super(); + + m_fileName = a_file; + + URL url = null; + + try { + url = a_file.toURI().toURL(); + } catch(MalformedURLException e) { + e.printStackTrace(); + } + + init(url); + } + + protected GlyphFile(URL a_url) { + super(); + init(a_url); + } + + private void init(URL a_url) { + m_glyph = loadGlyphElement(a_url); + ModuleManager.getSingletonInstance().clear(); + + //m_display = Engine.getSingletonInstance().getDisplay(); + + m_savedTime = m_modifiedTime; + } + + /** + * initialize .notdef + */ + public void initNotDef(int a_advanceWidth) { + setAdvanceWidth(a_advanceWidth); + + EContour contour = new EContour(); + contour.setType(EContour.k_cubic); + contour.addContourPoint(new EContourPoint(0.0, 0.0, true)); + contour.addContourPoint(new EContourPoint(438.0, 0.0, true)); + contour.addContourPoint(new EContourPoint(438.0, 683.0, true)); + contour.addContourPoint(new EContourPoint(0.0, 683.0, true)); + addContour(contour); + + contour = new EContour(); + contour.setType(EContour.k_cubic); + contour.addContourPoint(new EContourPoint(365.0, 73.0, true)); + contour.addContourPoint(new EContourPoint(73.0, 73.0, true)); + contour.addContourPoint(new EContourPoint(73.0, 610.0, true)); + contour.addContourPoint(new EContourPoint(365.0, 610.0, true)); + addContour(contour); + } + + public void initNullGlyph() { + setAdvanceWidth(0); + } + + public void initSpace(int a_advanceWidth) { + setAdvanceWidth(a_advanceWidth); + } + + public void beforePush() { + loadVar(); + } + + public void restore(Memento a_memento) { + m_glyph = loadGlyphElement(a_memento.getData()); + ModuleManager.getSingletonInstance().clear(); + } + + // -------------------------------------------------------------- + + public XStartGlyphElement getGlyph() { + return m_glyph; + } + + // -------------------------------------------------------------- + + public void saveGlyphFile(OutputStream a_output) { + try { + Transformer transformer = getTransformer(); + Document document = m_glyph.makeDocument(); + DOMSource source = new DOMSource(document); + StreamResult result = new StreamResult(a_output); + transformer.transform(source, result); + } catch (ParserConfigurationException | TransformerException e) { + e.printStackTrace(); + } + + m_savedTime = System.currentTimeMillis(); + m_modifiedTime = m_savedTime; + } + + public Memento createMemento(String a_description) { + m_modifiedTime = System.currentTimeMillis(); + byte [] bytes = m_glyph.makeTextDocument().getBytes(); + return new Memento(a_description, bytes); + } + + public boolean hasUnsavedChange() { + return (m_savedTime != m_modifiedTime); + } + + public void setAuthor(String a_value) { + m_glyph.getHead().setAuthor(a_value); + } + + public String getAuthor() { + return m_glyph.getHead().getAuthor(); + } + + public void setCopyrightYear(String a_value) { + m_glyph.getHead().setCopyright(a_value); + } + + public String getCopyrightYear() { + return m_glyph.getHead().getCopyright(); + } + + public void setAdvanceWidth(int a_width) { + m_glyph.getHead().setAdvanceWidth(a_width); + } + + public int getAdvanceWidth() { + if (!m_glyph.getHead().checkAdvanceWidth()) { + setAdvanceWidth(k_halfWidth); + } // if + + return (int) m_glyph.getHead().getAdvanceWidth(); + } + + public Iterator createIterator() { + return new GlyphIterator(this); + } + + + // -------------------------------------------------------------- + + public void display(Graphics2D g, AffineTransform a_trans) + { + Iterator i = createIterator(); + while (i.hasNext()) { + GlyphObject object = (GlyphObject) i.next(); + object.display(g, a_trans); + } // while + } + + // -------------------------------------------------------------- + + public static final int k_defaultPixelSize = 16; //PPM + + /** converts this glyph into Shape. + * It could be called for root's preview mode or by include invoke. + * Pushing either this GlyphFile or DIncludeInvoke should be + * handled before this. + */ + public Shape toShape(AffineTransform a_trans) { + + + int ppem = k_defaultPixelSize; + + GeneralPath retval = new GeneralPath(); + Iterator i = createIterator(); + while (i.hasNext()) { + GlyphObject object = (GlyphObject) i.next(); + + if (object instanceof EContourPoint + || object instanceof EHint) { + continue; + } // if + + retval.append(object.toShape(a_trans, ppem), false); + } // if + + return retval; + } + + // -------------------------------------------------------------- + + /** + * Generates array of XContour from local contours and modules. + * Used for TTF building. + */ + private XContour [] toContours() { + XContour [] retval; + ArrayList list = new ArrayList<>(); + XContour [] contours = m_glyph.getBody().getContour(); + for (int i = 0; i < contours.length; i++) { + EContour contour = (EContour) contours[i]; + list.add(contour.toQuadratic()); + } // for i + + XModule [] modules = m_glyph.getBody().getModule(); + for (int i = 0; i < modules.length; i++) { + EModuleInvoke module = (EModuleInvoke) modules[i]; + + // push and pop happens inside toContour + list.add(module.toContour(new AffineTransform())); + } // for i + + if (list.size() == 0) + return null; + + retval = new XContour[list.size()]; + for (int i = 0; i < list.size(); i++) { + retval[i] = list.get(i); + } // for i + + return retval; + } + + // -------------------------------------------------------------- + + public boolean isMoving() { + return m_isMoving; + } + + // -------------------------------------------------------------- + + public void beginMove() { + m_isMoving = true; + } + + // -------------------------------------------------------------- + + public void endMove() { + if (!m_isMoving) { + return; + } // if + + m_isMoving = false; + } + + // -------------------------------------------------------------- + + public void move(Point2D a_delta) { + int i; + for (i = 0; i < m_actives.size(); i++) { + GlyphObject active = m_actives.get(i); + active.move(a_delta); + } // for i + } + + + // -------------------------------------------------------------- + + public void fitMove() { + if (m_actives.hasActiveControlPoint()) { + EControlPoint controlPoint = m_actives.getActiveControlPoint(); + controlPoint.rotateTo45(); + } // if + } + + // -------------------------------------------------------------- + + public boolean isHittingSelected(Point2D a_point) { + ActiveList oldActiveObjects = new ActiveList(); + oldActiveObjects.setActives(m_actives); + + m_actives.unselectAll(); + hit(a_point, false, false); + + int i, j; + for (i = 0; i < m_actives.size(); i++) { + GlyphObject selected = m_actives.get(i); + for (j = 0; j < oldActiveObjects.size(); j++) { + GlyphObject old = oldActiveObjects.get(j); + + if (selected == old) { + m_actives.setActives(oldActiveObjects); + return true; + } // if + } // for j + } // for i + + m_actives.setActives(oldActiveObjects); + + return false; + } + + // -------------------------------------------------------------- + + /** hits a point to add them in active object queue. + * @param a_single when it is true, the method returns after + * finding the first hit. + */ + public boolean hit(Point2D a_point, + boolean a_isAppend, + boolean a_isSelectOnlyOne) { + if (a_point == null) { + return false; + } // if + + Rectangle2D rect = new Rectangle2D.Double( + a_point.getX(), a_point.getY(), + 1.0, 1.0); + return hit(rect, a_isAppend, a_isSelectOnlyOne); + } + + public void selectNext() { + Iterator i = new SelectionIterator(this); + + if (m_actives.size() == 1) { + boolean isFound = false; + + // loop the iterator in reverse order of drawing + while (i.hasNext()) { + GlyphObject object = (GlyphObject) i.next(); + + if (m_actives.isSelected(object)) { + isFound = true; + continue; + } // if + + if (!isFound) { + continue; + } // if + + m_actives.unselectAll(); + m_actives.addActive(object); + return; + } // while i + } // if + + i = new SelectionIterator(this); + if (i.hasNext()) { + GlyphObject object = (GlyphObject) i.next(); + m_actives.unselectAll(); + m_actives.addActive(object); + return; + } // if + } + + // -------------------------------------------------------------- + + public boolean hit(Rectangle2D a_rect, + boolean a_isAppend, + boolean a_single) { + + + if (!a_isAppend) { + m_actives.unselectAll(); + } // if + + return hitObjects(a_rect, a_single); + } + + // -------------------------------------------------------------- + + private boolean hitObjects(Rectangle2D a_rect, boolean a_isSelectOnlyOne) { + boolean retval = false; + + Iterator i = new SelectionIterator(this); + + // loop the iterator in reverse order of drawing + while (i.hasNext()) { + GlyphObject object = (GlyphObject) i.next(); + + if (!object.hit(a_rect, new AffineTransform())) { + continue; + } // if + + retval = true; + + if (a_isSelectOnlyOne) { + return true; + } // if + } // while i + + return retval; + } + + // -------------------------------------------------------------- + + /** used for cut and paste. + */ + public void addObjectFromClipboard(String a_value) throws CircularIncludeException { + Reader reader = new StringReader(a_value); + Document document = null; + try { + document = UJAXP.getDocument(reader); + } catch (Exception e) { + e.printStackTrace(); + return; + } // try-catch + + Element root = document.getDocumentElement(); + if (!root.getNodeName().equals("clipboard")) { + return; + } // if + + Node child; + for (child = root.getFirstChild(); child != null; + child = child.getNextSibling()) { + if (!(child instanceof Element)) { + continue; + } // if + Element element = (Element) child; + + IGlyphFactory factory = GlyphFactory.getFactory(); + + + if (XModule.isMatch(element)) { + EModuleInvoke module = (EModuleInvoke) factory.createXModule(element); + addModule(module); + continue; + } // if + + if (XContour.isMatch(element)) { + EContour contour = (EContour) factory.createXContour(element); + addContour(contour); + continue; + } // if + + if (XInclude.isMatch(element)) { + EIncludeInvoke include = (EIncludeInvoke) factory.createXInclude(element); + addInclude(include); + continue; + } // if + } // while + } + + // -------------------------------------------------------------- + + private boolean isCircularInclude(String a_href) { + if (getShortFileName().equals(a_href)) { + return true; + } // if + + ModuleManager manager = ModuleManager.getSingletonInstance(); + XInclude [] includes = m_glyph.getBody().getInclude(); + int i; + for (i = 0; i < includes.length; i++) { + XInclude include = includes[i]; + GlyphFile child = manager.getGlyphFile(include.getHref()); + + if (child.isCircularInclude(a_href)) { + return true; + } // if + } // for i + + return false; + } + + // -------------------------------------------------------------- + + public void addInclude(String a_fileName) throws CircularIncludeException { + addInclude(EIncludeInvoke.create(a_fileName)); + } + + public void addInclude(XInclude a_include) throws CircularIncludeException { + if (isCircularInclude(a_include.getHref())) { + throw new CircularIncludeException(); + } // if + + m_actives.unselectAll(); + m_actives.addActive((GlyphObject) a_include); + m_glyph.getBody().addInclude(a_include); + } + + // -------------------------------------------------------------- + + /** + * pasted module from clipboard or ModuleInvokeAction + * @param a_module + */ + public XModule addModule(EModuleInvoke a_module) { + m_actives.unselectAll(); + m_actives.addActive(a_module); + m_glyph.getBody().addModule(a_module); + + return a_module; + } + + // -------------------------------------------------------------- + + /** add contour from clipboard or ContourAction + * @param a_contour + */ + public void addContour(EContour a_contour) { + m_actives.unselectAll(); + m_actives.addActive(a_contour); + m_glyph.getBody().addContour(a_contour); + } + + + // -------------------------------------------------------------- + + + public void addPoint() { + if (!m_actives.hasActivePoint()) { + return; + } // if + + EContourPoint contourPoint = m_actives.getActivePoint(); + m_actives.unselectAll(); + m_actives.addActive(contourPoint.add()); + } + + // -------------------------------------------------------------- + + public void addHint(int a_ppem) { + if (!m_actives.hasActivePoint()) + return; + + EContourPoint contourPoint = m_actives.getActivePoint(); + m_actives.unselectAll(); + m_actives.addActive(contourPoint.addHint(a_ppem)); + + if (contourPoint.hasControlPoint1()) { + EContourPoint p = (EContourPoint) contourPoint.getControlPoint1().getContourPoint(); + m_actives.addActive(p.addHint(a_ppem)); + } // if + + if (contourPoint.hasControlPoint2()) { + EContourPoint p = (EContourPoint) contourPoint.getControlPoint2().getContourPoint(); + m_actives.addActive(p.addHint(a_ppem)); + } // if + } + + public void toggleRounded() { + if (!m_actives.hasActivePoint()) + return; + + EContourPoint contourPoint = m_actives.getActivePoint(); + contourPoint.toggleRounded(); + } + + public void convertControlPoint() { + if (!m_actives.hasActiveControlPoint()) { + return; + } // if + + EControlPoint controlPoint = m_actives.getActiveControlPoint(); + controlPoint.convert(); + } + + public void convertContour() { + if (!m_actives.hasActiveContour()) { + return; + } // if + + EContour contour = m_actives.getActiveContour(); + contour.convert(); + } + + // -------------------------------------------------------------- + + public void remove() { + if (!m_actives.hasSelected()) + return; + + int i; + for (i = 0; i < m_actives.size(); i++) { + GlyphObject active = m_actives.get(i); + active.remove(); + } // for i + + m_actives.unselectAll(); + } + + // -------------------------------------------------------------- + + public void toggleOnOff() { + if (!m_actives.hasSelected()) + return; + + int i; + for (i = 0; i < m_actives.size(); i++) { + GlyphObject active = m_actives.get(i); + if (!(active instanceof EContourPoint)) { + continue; + } // if + + EContourPoint point = (EContourPoint) active; + point.toggleOnCurve(); + } // for i + } + + private void loadVar() { + XParamListParam [] params = m_glyph.getHead().getHeadGlobal().getParamListParam(); + int i; + for (i = 0; i < params.length; i++) { + XParamListParam param = params[i]; + addVar(param.getName(), param.getContent()); + } // for i + } + + public String getSelectedNodeName() { + return m_selectedNodeName; + } + + public void addFileVar() { + XParamListParam param = new XParamListParam(); + param.setName("New parameter"); + param.setContent(0.0); + + m_glyph.getHead().getHeadGlobal().addParamListParam(param); + } + + public void removeFileVar(int a_index) { + m_glyph.getHead().getHeadGlobal().removeParamListParam(a_index); + } + + + public void addInvokeArg(int a_type) { + + } + + public void removeInvokeArg(int a_type, int a_index) { + + } + + public String getIncludeName() { + String retval = ""; + + if (!m_actives.hasActiveInclude()) + return retval; + retval = m_actives.getActiveInclude().getHref(); + + return retval; + } + + public void setIncludeName(String a_name) { + if (!m_actives.hasActiveInclude()) + return; + + m_actives.getActiveInclude().setHref(a_name); + } + + public void setGlyphTitle(String a_title) { + m_glyph.getHead().setTitle(a_title); + } + + public String getGlyphTitle() { + String retval = ""; + + retval = m_glyph.getHead().getTitle(); + + if (retval.equals("empty")) { + retval = ""; + } // if + + return retval; + } + + public String getModuleName() { + String retval = ""; + + if (!m_actives.hasActiveModule()) + return retval; + retval = m_actives.getActiveModule().getName(); + + return retval; + } + + public String getUnicode() { + return getUnicodeAsString(); + } + + public String getUnicodeAsString() { + return m_glyph.getHead().getUnicode(); + } + + public long getUnicodeAsLong() { + long retval = -1; + + String s = getUnicodeAsString(); + if (s.equals("")) { + return retval; + } // if + + try { + retval = Long.parseLong(s, 16); + } catch (NumberFormatException e) { + retval = -1; + } // try-catch + + return retval; + } + + protected void setUnicode(String a_unicode) { + m_glyph.getHead().setUnicode(a_unicode); + } + + public boolean isSimple() { + return (m_glyph.getBody().getInclude().length == 0); + } + + public boolean isWhiteSpace() { + long unicode = getUnicodeAsLong(); + + if (unicode == 0x0020 + || unicode == 0x00a0 + || unicode == 0x200b + || unicode == 0x2060 + || unicode == 0x3000 + || unicode == 0xfeff) + { + return true; + } // if + + return false; + } + + public String getShortFileName() { + return m_fileName.getName(); + } + + public void setLicense(String a_value) { + m_glyph.getHead().setLicense(a_value); + } + + public String getLicense() { + return m_glyph.getHead().getLicense(); + } + + public PointAggregate getPointHost() { + return m_pointHost; + } + + public void buildPointHost() { + m_pointHost = null; + + /*if (!GlyphAction.isPointVisible()) { + return; + } // if*/ + + int i; + for (i = 0; i < m_actives.size(); i++) { + GlyphObject object = (GlyphObject) m_actives.get(i); + PointAggregate host = null; + + if (object instanceof EContourPoint) { + EContourPoint point = (EContourPoint) object; + host = point.getParent(); + + if (host instanceof EContourPoint) { + EContourPoint hostPoint = (EContourPoint) host; + host = hostPoint.getParent(); + } // if + } else if (object instanceof EHint) { + EHint hint = (EHint) object; + host = hint.getPointHost(); + } // if-else + + if (host == null) { + continue; + } // if + + if (m_pointHost == null) { + m_pointHost = host; + } else { + if (m_pointHost != host) { + m_pointHost = null; + return; + } // if + } // if + } // while + } + + public boolean isRequiredGlyph() { + long unicode = getUnicodeAsLong(); + + return (unicode == TTUnicodeRange.k_notDef + || unicode == TTUnicodeRange.k_null + || unicode == TTUnicodeRange.k_cr + || unicode == TTUnicodeRange.k_space); + } + + public TTGlyph toSimpleGlyph() { + // convert the file into array of contours + XContour [] contours = toContours(); + if ((contours == null) && (!isRequiredGlyph())) { + return null; + } // if + + TTGlyph retval = new TTGlyph(); + retval.setSimple(true); + retval.setAdvanceWidth(getAdvanceWidth()); + + if (contours == null) { + return retval; + } // if + + ArrayList points = new ArrayList<>(); + for (int i = 0; i < contours.length; i++) { + XContour contour = contours[i]; + XContourPoint [] contourPoints = contour.getContourPoint(); + for (int j = 0; j < contourPoints.length; j++) { + points.add((EContourPoint) contourPoints[j]); + } // for j + retval.addEndPoint(points.size() - 1); + } // for i + + for (EContourPoint point: points) { + loadContourPoint(retval, point); + } // for point + + boolean hasGridfit = false; + // I need int i here. + for (int i = 0; i < points.size(); i++) { + EContourPoint point = points.get(i); + + if (!point.isRounded()) { + continue; + } // if + + hasGridfit = true; + loadGridfit(retval, point, i); + } // for i + + if (hasGridfit) { + retval.addInstruction(TTGlyph.IUP1); + retval.addInstruction(TTGlyph.IUP0); + } // if + + // I need int i here. + for (int i = 0; i < points.size(); i++) { + EContourPoint point = points.get(i); + if (point.getHint().length == 0) { + continue; + } // if + + loadHint(retval, point, i); + } // for i + + return retval; + } + + private void loadContourPoint(TTGlyph a_glyph, EContourPoint a_point) { + double x = a_point.getX(); + double y = a_point.getY(); + Point p = new Point((int) x, (int) y); + int flag = 0; + if (a_point.isOn()) { + flag = TTGlyph.k_onCurve; + } // if + + a_glyph.addPoint(p); + a_glyph.addFlag(flag); + } + + private void loadGridfit(TTGlyph a_glyph, EContourPoint a_point, int a_index) { + if (!a_point.isRounded()) { + return; + } // if + + a_glyph.addInstruction(TTGlyph.PUSHB000); + a_glyph.addInstruction(a_index); + a_glyph.addInstruction(TTGlyph.MDAP1); + } + + + private void loadHint(TTGlyph a_glyph, EContourPoint a_point, int a_index) { + double x = a_point.getX(); + double y = a_point.getY(); + + XHint [] hints = a_point.getHint(); + + for (int i = 0; i < hints.length; i++) { + EHint hint = (EHint) hints[i]; + double xHint = hint.getX(); + double yHint = hint.getY(); + + if (x == xHint && y == yHint) { + continue; + } // if + + double xDelta = xHint - x; + double yDelta = yHint - y; + int instruction = TTGlyph.DELTAP1; + double deltaStep = ((double) Engine.getEm()) / hint.getPpem() / 8; + int xShift = (int) Math.round(xDelta / deltaStep); + int yShift = (int) Math.round(yDelta / deltaStep); + + if (xShift == 0 && yShift == 0) { + continue; + } // if + + a_glyph.addInstruction(TTGlyph.PUSHB000); + a_glyph.addInstruction((int) hint.getPpem()); + a_glyph.addInstruction(TTGlyph.SDB); + + if (xShift != 0) { + a_glyph.addInstruction(TTGlyph.SVTCA1); + a_glyph.addInstruction(TTGlyph.PUSHB010); + a_glyph.addInstruction(TTGlyph.toDeltaArg(0, xShift)); + a_glyph.addInstruction(a_index); + a_glyph.addInstruction(1); + a_glyph.addInstruction(TTGlyph.DELTAP1); + } // if + + if (yShift != 0) { + a_glyph.addInstruction(TTGlyph.SVTCA0); + a_glyph.addInstruction(TTGlyph.PUSHB010); + a_glyph.addInstruction(TTGlyph.toDeltaArg(0, yShift)); + a_glyph.addInstruction(a_index); + a_glyph.addInstruction(1); + a_glyph.addInstruction(TTGlyph.DELTAP1); + } // if + } // for i + } + + public class CircularIncludeException extends Exception {} } \ No newline at end of file diff --git a/libsrc/ttf/src/org/doubletype/ossa/module/TypefaceFile.java b/libsrc/ttf/src/org/doubletype/ossa/module/TypefaceFile.java index 9133ea84f..b08e580e3 100644 --- a/libsrc/ttf/src/org/doubletype/ossa/module/TypefaceFile.java +++ b/libsrc/ttf/src/org/doubletype/ossa/module/TypefaceFile.java @@ -1,677 +1,655 @@ -/* - * $Copyright: copyright (c) 2003-2008, e.e d3si9n $ - * $License: - * This source code is part of DoubleType. - * DoubleType is a graphical typeface designer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * In addition, as a special exception, e.e d3si9n gives permission to - * link the code of this program with any Java Platform that is available - * to public with free of charge, including but not limited to - * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), - * and distribute linked combinations including the two. - * You must obey the GNU General Public License in all respects for all - * of the code used other than Java Platform. If you modify this file, - * you may extend this exception to your version of the file, but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. - * $ - */ - -package org.doubletype.ossa.module; - -import java.io.*; -import java.util.*; - -import org.doubletype.ossa.*; -import org.doubletype.ossa.xml.*; -import org.doubletype.ossa.adapter.*; -import org.doubletype.ossa.truetype.*; -import java.awt.*; - -/** - * @author e.e - */ -public class TypefaceFile extends GlyphFile { - private final double k_defaultTopSideBearing = 170; // 2 px - private final double k_defaultAscender = 683; // 8 px - private final double k_defaultXHeight = 424; // 5 px - private final double k_defaultDescender = 171; // 2 px - private final double k_defaultBottomSideBearing = 0; // 0 px - private final double k_em = 1024; - private final int k_defaultAdvanceWidth = 512; - private final String k_dotDtyp = ".dtyp"; - private final String k_dotTtf = ".ttf"; - - private File m_dir; - private Hashtable m_nameToIndeces = new Hashtable<>(); - private File m_ttfFile; - private Font m_font = null; - private File m_binFolder; - - public TypefaceFile(String a_name, File a_dir) throws FileNotFoundException { - super(TypefaceFile.class.getResource(s_emptyFileName)); - - m_dir = a_dir; - setGlyphTitle(a_name); - - m_fileName = new File(m_dir, a_name + k_dotDtyp); - initFileName(); - - saveGlyphFile(); - } - - public TypefaceFile(File a_file) { - super(a_file); - - m_dir = a_file.getParentFile(); - m_fileName = a_file; - - initFileName(); - } - - private void initFileName() { - m_binFolder = new File(m_dir, "bin"); - if (!m_binFolder.exists()) { - m_binFolder.mkdir(); - } // if - - String fileName = getGlyphTitle() + k_dotTtf; - m_ttfFile = new File(m_binFolder, fileName); - } - - public GlyphFile createGlyph(long a_unicode) throws FileNotFoundException { - String name = Character.getName((int) a_unicode); - if (name == null) { - name = "NAC_" + Long.toHexString(a_unicode); - } // if - - name = name.replace(' ', '_'); - return new GlyphFile( - getGlyphPath(), name, a_unicode); - } - - public boolean addRequiredGlyphs() throws FileNotFoundException { - boolean retval = false; - - if (unicodeToFileName(TTUnicodeRange.k_notDef) == null) { - GlyphFile glyph = new GlyphFile(getGlyphPath(), "NOTDEF", TTUnicodeRange.k_notDef); - glyph.initNotDef(k_defaultAdvanceWidth); - addGlyph(0, glyph); - retval = true; - } // if - - if (unicodeToFileName(TTUnicodeRange.k_null) == null) { - GlyphFile glyph = new GlyphFile(getGlyphPath(), "NULL", TTUnicodeRange.k_null); - glyph.initNullGlyph(); - addGlyph(1, glyph); - retval = true; - } // if - - if (unicodeToFileName(TTUnicodeRange.k_cr) == null) { - GlyphFile glyph = new GlyphFile(getGlyphPath(), "CR", TTUnicodeRange.k_cr); - glyph.initSpace(k_defaultAdvanceWidth); - addGlyph(2, glyph); - retval = true; - } // if - - if (unicodeToFileName(TTUnicodeRange.k_space) == null) { - GlyphFile glyph = new GlyphFile(getGlyphPath(), "SPACE", TTUnicodeRange.k_space); - glyph.initSpace(k_defaultAdvanceWidth); - addGlyph(3, glyph); - retval = true; - } // if - - if (retval) { - saveGlyphFile(); - } // if - - return retval; - } - - public void addBasicLatinGlyphs() throws FileNotFoundException { - String basicLatin = Character.UnicodeBlock.BASIC_LATIN.toString(); - TTUnicodeRange.find(basicLatin); - TTUnicodeRange range = TTUnicodeRange.getLastFound(); - addUnicodeRange(basicLatin); - for (long i = range.getStartCode(); i <= range.getEndCode(); i++) { - if (i != 0x0020) { - addGlyph(createGlyph(i)); - } // if - } // for i - - saveGlyphFile(); - } - - public File getGlyphPath() { - return m_dir; - } - - public String unicodeToFileName(long a_unicode) { - for (XGlyphFile glyphFile: m_glyph.getBody().getGlyphFile()) { - if (glyphFile.getUnicode() == a_unicode) { - return glyphFile.getHref(); - } // if - } // for i - - return null; - } - - /** - * change glyph's unicode mapping. - * @param a_glyphFile - * @param a_unicode - */ - public void setGlyphUnicode(GlyphFile a_glyphFile, long a_unicode) throws FileNotFoundException { - int i; - XGlyphFile [] glyphFiles = m_glyph.getBody().getGlyphFile(); - for (i = 0; i < glyphFiles.length; i++) { - XGlyphFile glyphFile = glyphFiles[i]; - - if (glyphFile.getHref().equals( - a_glyphFile.getShortFileName())) { - continue; - } // if - - glyphFile.setUnicode(a_unicode); - a_glyphFile.setUnicode(Long.toHexString(a_unicode)); - a_glyphFile.saveGlyphFile(); - saveGlyphFile(); - - return; - } // for i - } - - public void addGlyph(GlyphFile a_file) { - XGlyphFile xglyphFile = new XGlyphFile(); - xglyphFile.setHref(a_file.getShortFileName()); - xglyphFile.setUnicode(a_file.getUnicodeAsLong()); - m_glyph.getBody().addGlyphFile(xglyphFile); - } - - public void addGlyph(int a_index, GlyphFile a_file) { - XGlyphFile xglyphFile = new XGlyphFile(); - xglyphFile.setHref(a_file.getShortFileName()); - xglyphFile.setUnicode(a_file.getUnicodeAsLong()); - m_glyph.getBody().addGlyphFile(a_index, xglyphFile); - } - - public void removeGlyph(String a_fileName) { - for (XGlyphFile file: m_glyph.getBody().getGlyphFile()) { - if (file.getHref().equals(a_fileName)) { - m_glyph.getBody().removeGlyphFile(file); - return; - } // if - } - } - - public ArrayList getChildFileNames() { - ArrayList retval = new ArrayList<>(); - XGlyphFile [] files = m_glyph.getBody().getGlyphFile(); - - for (int i = 0; i < files.length; i++) { - XGlyphFile file = files[i]; - retval.add(file.getHref()); - } // for i - - return retval; - } - - public Object [] getCodePages() { - int i; - Object [] retval; - String [] codePages = m_glyph.getHead().getCodePage(); - retval = new Object[codePages.length]; - for (i = 0; i < codePages.length; i++) { - retval[i] = codePages[i]; - } // for i - - return retval; - } - - public boolean containsUnicodeRange(String a_unicodeRange) { - int i; - String [] unicodeRanges = m_glyph.getHead().getUnicodeRange(); - - for (i = 0; i < unicodeRanges.length; i++) { - if (unicodeRanges[i].equals(a_unicodeRange)) { - return true; - } // if - } // for i - - return false; - } - - public void addUnicodeRange(String a_unicodeRange) throws FileNotFoundException { - if (containsUnicodeRange(a_unicodeRange)) { - return; - } // if - - m_glyph.getHead().addUnicodeRange(a_unicodeRange); - saveGlyphFile(); - } - - public boolean containsCodePage(String a_codePage) { - int i; - String [] codePages = m_glyph.getHead().getCodePage(); - - for (i = 0; i < codePages.length; i++) { - if (codePages[i].equals(a_codePage)) { - return true; - } // if - } // for i - - return false; - } - - public void addCodePage(String a_codePage) throws FileNotFoundException { - if (containsCodePage(a_codePage)) { - return; - } // if - - m_glyph.getHead().addCodePage(a_codePage); - saveGlyphFile(); - } - - public void removeCodePage(String a_codePage) throws FileNotFoundException { - if (!containsCodePage(a_codePage)) { - return; - } // if - - m_glyph.getHead().removeCodePage(a_codePage); - saveGlyphFile(); - } - - public void setFontFamilyName(String a_value) throws FileNotFoundException { - m_glyph.getHead().setFontFamily(a_value); - saveGlyphFile(); - } - - public String getFontFamilyName() { - return m_glyph.getHead().getFontFamily(); - } - - public String getVersion() throws FileNotFoundException { - if (m_glyph.getHead().getVersion() == null) { - m_glyph.getHead().setVersion("0.1"); - saveGlyphFile(); - } // if - - return m_glyph.getHead().getVersion(); - } - - public void setSubFamily(String a_value) throws FileNotFoundException { - m_glyph.getHead().setFontSubFamily(a_value); - saveGlyphFile(); - } - - public void setDefaultMetrics() throws FileNotFoundException { - XHead head = m_glyph.getHead(); - head.setTopSideBearing(k_defaultTopSideBearing); - head.setAscender(k_defaultAscender); - head.setXHeight(k_defaultXHeight); - head.setDescender(k_defaultDescender); - head.setBottomSideBearing(k_defaultBottomSideBearing); - - saveGlyphFile(); - } - - public double getEm() { - return k_em; - } - - public double getBaseline() throws FileNotFoundException { - return getBottomSideBearing() + getDescender(); - } - - public double getMeanline() throws FileNotFoundException { - return getBottomSideBearing() - + getDescender() + getXHeight(); - } - - public double getBodyBottom() throws FileNotFoundException { - return getBottomSideBearing(); - } - - public double getBodyTop() throws FileNotFoundException { - return getEm() - getTopSideBearing(); - } - - public double getTopSideBearing() throws FileNotFoundException { - if (!m_glyph.getHead().checkTopSideBearing()) { - setDefaultMetrics(); - } // if - - return m_glyph.getHead().getTopSideBearing(); - } - - public double getAscender() throws FileNotFoundException { - if (!m_glyph.getHead().checkAscender()) { - setDefaultMetrics(); - } // if - - return m_glyph.getHead().getAscender(); - } - - public double getXHeight() throws FileNotFoundException { - if (!m_glyph.getHead().checkXHeight()) { - setDefaultMetrics(); - } // if - - return m_glyph.getHead().getXHeight(); - } - - public double getDescender() throws FileNotFoundException { - if (!m_glyph.getHead().checkDescender()) { - setDefaultMetrics(); - } // if - - return m_glyph.getHead().getDescender(); - } - - public double getBottomSideBearing() throws FileNotFoundException { - if (!m_glyph.getHead().checkBottomSideBearing()) { - setDefaultMetrics(); - } // if - - return m_glyph.getHead().getBottomSideBearing(); - } - - public void setTopSideBearing(double a_value) throws OutOfRangeException, FileNotFoundException { - checkBoundary(a_value); - m_glyph.getHead().setTopSideBearing(a_value); - saveGlyphFile(); - } - - private void checkBoundary(double a_value) throws OutOfRangeException { - if (a_value > k_em || a_value < 0) { - throw new OutOfRangeException(a_value); - } // if - } - - public void setAscender(double a_value) throws OutOfRangeException, FileNotFoundException { - checkBoundary(a_value); - m_glyph.getHead().setAscender(a_value); - saveGlyphFile(); - } - - public void setXHeight(double a_value) throws OutOfRangeException, FileNotFoundException { - checkBoundary(a_value); - if (a_value > getAscender()) { - throw new OutOfRangeException(a_value); - } // if - - m_glyph.getHead().setXHeight(a_value); - - m_history.record("setXHeight"); - saveGlyphFile(); - } - - public void setDescender(double a_value) throws OutOfRangeException, FileNotFoundException { - checkBoundary(a_value); - m_glyph.getHead().setDescender(a_value); - saveGlyphFile(); - } - - public void setBottomSideBearing(double a_value) throws OutOfRangeException, FileNotFoundException { - checkBoundary(a_value); - m_glyph.getHead().setBottomSideBearing(a_value); - saveGlyphFile(); - } - - public double getBodyHeight() throws FileNotFoundException { - return k_em - getTopSideBearing() - getBottomSideBearing(); - } - -// -------------------------------------------------------------------- - - /** - * Calls FontFileWriter to produce TrueType font file. - * @throws FileNotFoundException - */ - public void buildTTF(boolean a_isDebug) throws Exception { - String randomString = UUID.randomUUID().toString().substring(0, 4); - - File tempFile = new File(m_binFolder, - getGlyphTitle() + "_" + randomString + k_dotTtf); - File target; - String fontFamilyName; - - if (a_isDebug) { - target = tempFile; - fontFamilyName = getGlyphTitle() + " " + randomString; - } else { - target = m_ttfFile; - fontFamilyName = getFontFamilyName(); - } // if-else - - target.delete(); - FontFileWriter writer; - ModuleManager.getSingletonInstance().clear(); - m_stack.clear(); - m_stack.push(this); - try (RandomAccessFile randomAccessFile = new RandomAccessFile(target, "rw")) { - writer = new FontFileWriter(randomAccessFile); - - writer.setFontFamilyName(fontFamilyName); - writer.setCopyrightYear(getCopyrightYear()); - writer.setFontVersion(getVersion()); - writer.setManufacturer(getAuthor()); - writer.setAscent((int) getAscender()); - writer.setXHeight((int) getXHeight()); - writer.setDescent((int) getDescender()); - writer.setLineGap((int) (getTopSideBearing() + getBottomSideBearing())); - - loadCodePages(writer); - loadUnicodeRanges(writer); - loadGlyphs(writer); - writer.write(); - } - if (!a_isDebug && target.exists()) { - copyFile(target, tempFile); - } // if - - FileInputStream in = new FileInputStream(tempFile); - m_font = Font.createFont(Font.TRUETYPE_FONT, - (InputStream) in); - in.close(); - - ModuleManager.getSingletonInstance().clear(); - m_stack.pop(); // pop this - } - - private void copyFile(File a_in, File a_out) throws Exception { - FileInputStream in = new FileInputStream(a_in); - FileOutputStream out = new FileOutputStream(a_out); - byte [] buffer = new byte[1024]; - int i = 0; - while ((i = in.read(buffer)) != -1) { - out.write(buffer, 0, i); - } // while - - in.close(); - out.close(); - } - - public Font getFont() { - return m_font; - } - - private void loadCodePages(FontFileWriter a_writer) { - for (String codePageName: m_glyph.getHead().getCodePage()) { - TTCodePage codePage = TTCodePage.forName(codePageName); - if (codePage == null) { - continue; - } // if - - a_writer.setCodeRangeFlag(codePage.getOsTwoFlag()); - } // for codePageName - } - - private void loadUnicodeRanges(FontFileWriter a_writer) { - String [] unicodeRanges = m_glyph.getHead().getUnicodeRange(); - int i; - for (i = 0; i < unicodeRanges.length; i++) { - if (!TTUnicodeRange.find(unicodeRanges[i])) { - continue; - } // if - - a_writer.addUnicodeRange(TTUnicodeRange.getLastFound()); - } // for i - } - - private void loadGlyphs(FontFileWriter a_writer) throws Exception { - m_nameToIndeces.clear(); - - for (String fileName: getChildFileNames()) { - GlyphFile glyphFile = nameToGlyphFile(fileName); - loadGlyph(glyphFile, glyphFile, a_writer); - } // for - } - - private GlyphFile nameToGlyphFile(String a_fileName) throws FileNotFoundException { - File file = new File(m_dir, a_fileName); - - if (!file.exists()) { - throw new FileNotFoundException(a_fileName); - } // if - - GlyphFile retval = new GlyphFile(file); - - return retval; - } - - /** - * load the glyph into FontFileWriter. - * @param a_fileName - * @param a_writer - * @throws Exception - */ - private void loadGlyph(GlyphFile a_glyphFile, VarStackFrame a_frame, FontFileWriter a_writer) throws Exception { - if (m_nameToIndeces.containsKey(a_glyphFile.getShortFileName())) { - return; - } // if - - /* - if (a_glyphFile.getUnicodeAsLong() == TTUnicodeRange.k_null) { - return; - } // if - */ - - TTGlyph glyph = null; - m_stack.push(a_frame); - - if (a_glyphFile.isSimple()) { - // glyph will be null if it is empty - glyph = a_glyphFile.toSimpleGlyph(); - } else { - glyph = createCompoundGlyph(a_glyphFile, a_writer); - } // if - - m_stack.pop(); - - if (glyph == null && a_glyphFile.isWhiteSpace()) { - glyph = new TTGlyph(); - } // if - - if (glyph == null) { - return; - } // if - - int glyphIndex = a_writer.addGlyph(glyph); - m_nameToIndeces.put(a_glyphFile.getShortFileName(), glyphIndex); - long unicode = a_glyphFile.getUnicodeAsLong(); - - if (unicode != -1 && glyph != null) { - long existingIndex = a_writer.getCharacterMapping(unicode); - if (existingIndex != 0) { - throw new Exception(Long.toHexString(unicode) + " is mapped already."); - } // if - - a_writer.addCharacterMapping(unicode, glyphIndex); - } // if - } - - private TTGlyph createCompoundGlyph(GlyphFile a_glyphFile, - FontFileWriter a_writer) throws Exception - { - TTGlyph retval = new TTGlyph(); - ArrayList locs = new ArrayList<>(); - ArrayList indeces = new ArrayList<>(); - - retval.setSimple(false); - retval.setAdvanceWidth(a_glyphFile.getAdvanceWidth()); - - TTGlyph simple = a_glyphFile.toSimpleGlyph(); - if (simple != null) { - int glyphIndex = a_writer.addGlyph(simple); - - locs.add(new Point(0, 0)); - indeces.add(glyphIndex); - } // if - - XInclude [] includes = a_glyphFile.m_glyph.getBody().getInclude(); - int i; - for (i = 0; i < includes.length; i++) { - EIncludeInvoke include = (EIncludeInvoke) includes[i]; - GlyphFile glyphFile = nameToGlyphFile(include.getHref()); - - // load the glyph included in this one - loadGlyph(glyphFile, include, a_writer); - Integer n = m_nameToIndeces.get(glyphFile.getShortFileName()); - if (n == null) { - continue; - } // if - - indeces.add(n); - XPoint2d pos = include.getInvoke().getInvokePos().getPoint2d(); - locs.add(new Point((int) pos.getX(), (int) pos.getY())); - } // for i - - int flag = TTGlyph.ARG_1_AND_2_ARE_WORDS - | TTGlyph.ARGS_ARE_XY_VALUES - | TTGlyph.ROUND_XY_TO_GRID; - int numOfCompositePoints = 0; - int numOfCompositeContours = 0; - int componentDepth = 0; - - for (int glyfIndex: indeces) { - TTGlyph glyph = a_writer.getGlyph(glyfIndex); - numOfCompositePoints += glyph.getNumOfCompositePoints(); - numOfCompositeContours += glyph.getNumOfCompositeContours(); - if (glyph.getComponentDepth() > componentDepth) { - componentDepth = glyph.getComponentDepth(); - } // if - - retval.addGlyfIndex(glyfIndex); - if (i < indeces.size() - 1) { - retval.addFlag(flag | TTGlyph.MORE_COMPONENTS); - } else { - retval.addFlag(flag); - } // if-else - - Point loc = locs.get(i); - retval.addArg1(loc.x); - retval.addArg2(loc.y); - } // for - - retval.setNumOfCompositePoints(numOfCompositePoints); - retval.setNumOfCompositeContours(numOfCompositeContours); - retval.setComponentDepth(componentDepth + 1); - - return retval; - } -} +/* + * $Copyright: copyright (c) 2003-2008, e.e d3si9n $ + * $License: + * This source code is part of DoubleType. + * DoubleType is a graphical typeface designer. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * In addition, as a special exception, e.e d3si9n gives permission to + * link the code of this program with any Java Platform that is available + * to public with free of charge, including but not limited to + * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), + * and distribute linked combinations including the two. + * You must obey the GNU General Public License in all respects for all + * of the code used other than Java Platform. If you modify this file, + * you may extend this exception to your version of the file, but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. + * $ + */ + +package org.doubletype.ossa.module; + +import java.io.*; +import java.util.*; + +import org.doubletype.ossa.*; +import org.doubletype.ossa.xml.*; +import org.doubletype.ossa.adapter.*; +import org.doubletype.ossa.truetype.*; +import java.awt.*; +import java.util.List; + +/** + * @author e.e + */ +public class TypefaceFile extends GlyphFile { + private final double k_defaultTopSideBearing = 170; // 2 px + private final double k_defaultAscender = 683; // 8 px + private final double k_defaultXHeight = 424; // 5 px + private final double k_defaultDescender = 171; // 2 px + private final double k_defaultBottomSideBearing = 0; // 0 px + private final double k_em = 1024; + private final int k_defaultAdvanceWidth = 512; + private final String k_dotDtyp = ".dtyp"; + private final String k_dotTtf = ".ttf"; + + private File m_dir; + private Hashtable m_nameToIndeces = new Hashtable<>(); + private File m_ttfFile; + private Font m_font = null; + private File m_binFolder; + private Map m_glyphFiles = new HashMap<>(); + + public TypefaceFile(String a_name, File a_dir) throws FileNotFoundException { + super(TypefaceFile.class.getResource(s_emptyFileName)); + + m_dir = a_dir; + setGlyphTitle(a_name); + + m_fileName = new File(m_dir, a_name + k_dotDtyp); + initFileName(); + } + + public TypefaceFile(File a_file) { + super(a_file); + + m_dir = a_file.getParentFile(); + m_fileName = a_file; + + initFileName(); + } + + private void initFileName() { + m_binFolder = new File(m_dir, "bin"); + if (!m_binFolder.exists()) { + m_binFolder.mkdir(); + } // if + + String fileName = getGlyphTitle() + k_dotTtf; + m_ttfFile = new File(m_binFolder, fileName); + } + + public GlyphFile createGlyph(long a_unicode) { + String name = Character.getName((int) a_unicode); + if (name == null) { + name = "NAC_" + Long.toHexString(a_unicode); + } // if + + name = name.replace(' ', '_'); + return new GlyphFile( + getGlyphPath(), name, a_unicode); + } + + public boolean addRequiredGlyphs() { + boolean retval = false; + + if (unicodeToFileName(TTUnicodeRange.k_notDef) == null) { + GlyphFile glyph = new GlyphFile(getGlyphPath(), "NOTDEF", TTUnicodeRange.k_notDef); + glyph.initNotDef(k_defaultAdvanceWidth); + addGlyph(0, glyph); + retval = true; + } // if + + if (unicodeToFileName(TTUnicodeRange.k_null) == null) { + GlyphFile glyph = new GlyphFile(getGlyphPath(), "NULL", TTUnicodeRange.k_null); + glyph.initNullGlyph(); + addGlyph(1, glyph); + retval = true; + } // if + + if (unicodeToFileName(TTUnicodeRange.k_cr) == null) { + GlyphFile glyph = new GlyphFile(getGlyphPath(), "CR", TTUnicodeRange.k_cr); + glyph.initSpace(k_defaultAdvanceWidth); + addGlyph(2, glyph); + retval = true; + } // if + + if (unicodeToFileName(TTUnicodeRange.k_space) == null) { + GlyphFile glyph = new GlyphFile(getGlyphPath(), "SPACE", TTUnicodeRange.k_space); + glyph.initSpace(k_defaultAdvanceWidth); + addGlyph(3, glyph); + retval = true; + } // if + + return retval; + } + + public void addBasicLatinGlyphs() { + String basicLatin = Character.UnicodeBlock.BASIC_LATIN.toString(); + TTUnicodeRange.find(basicLatin); + TTUnicodeRange range = TTUnicodeRange.getLastFound(); + addUnicodeRange(basicLatin); + for (long i = range.getStartCode(); i <= range.getEndCode(); i++) { + if (i != 0x0020) { + addGlyph(createGlyph(i)); + } // if + } // for i + } + + public File getGlyphPath() { + return m_dir; + } + + public String unicodeToFileName(long a_unicode) { + for (XGlyphFile glyphFile: m_glyph.getBody().getGlyphFile()) { + if (glyphFile.getUnicode() == a_unicode) { + return glyphFile.getHref(); + } // if + } // for i + + return null; + } + + /** + * change glyph's unicode mapping. + * @param a_glyphFile + * @param a_unicode + */ + public void setGlyphUnicode(GlyphFile a_glyphFile, long a_unicode) { + int i; + XGlyphFile [] glyphFiles = m_glyph.getBody().getGlyphFile(); + for (i = 0; i < glyphFiles.length; i++) { + XGlyphFile glyphFile = glyphFiles[i]; + + if (glyphFile.getHref().equals( + a_glyphFile.getShortFileName())) { + continue; + } // if + + glyphFile.setUnicode(a_unicode); + a_glyphFile.setUnicode(Long.toHexString(a_unicode)); + + return; + } // for i + } + + public void addGlyph(GlyphFile a_file) { + String shortFileName = a_file.getShortFileName(); + m_glyphFiles.put(shortFileName, a_file); + XGlyphFile xglyphFile = new XGlyphFile(); + xglyphFile.setHref(shortFileName); + xglyphFile.setUnicode(a_file.getUnicodeAsLong()); + m_glyph.getBody().addGlyphFile(xglyphFile); + } + + public void addGlyph(int a_index, GlyphFile a_file) { + String shortFileName = a_file.getShortFileName(); + m_glyphFiles.put(shortFileName, a_file); + XGlyphFile xglyphFile = new XGlyphFile(); + xglyphFile.setHref(shortFileName); + xglyphFile.setUnicode(a_file.getUnicodeAsLong()); + m_glyph.getBody().addGlyphFile(a_index, xglyphFile); + } + + public void removeGlyph(String a_fileName) { + for (XGlyphFile file: m_glyph.getBody().getGlyphFile()) { + if (file.getHref().equals(a_fileName)) { + m_glyph.getBody().removeGlyphFile(file); + return; + } // if + } + } + + public ArrayList getChildFileNames() { + ArrayList retval = new ArrayList<>(); + XGlyphFile [] files = m_glyph.getBody().getGlyphFile(); + + for (int i = 0; i < files.length; i++) { + XGlyphFile file = files[i]; + retval.add(file.getHref()); + } // for i + + return retval; + } + + public Object [] getCodePages() { + int i; + Object [] retval; + String [] codePages = m_glyph.getHead().getCodePage(); + retval = new Object[codePages.length]; + for (i = 0; i < codePages.length; i++) { + retval[i] = codePages[i]; + } // for i + + return retval; + } + + public boolean containsUnicodeRange(String a_unicodeRange) { + int i; + String [] unicodeRanges = m_glyph.getHead().getUnicodeRange(); + + for (i = 0; i < unicodeRanges.length; i++) { + if (unicodeRanges[i].equals(a_unicodeRange)) { + return true; + } // if + } // for i + + return false; + } + + public void addUnicodeRange(String a_unicodeRange) { + if (containsUnicodeRange(a_unicodeRange)) { + return; + } // if + + m_glyph.getHead().addUnicodeRange(a_unicodeRange); + } + + public boolean containsCodePage(String a_codePage) { + int i; + String [] codePages = m_glyph.getHead().getCodePage(); + + for (i = 0; i < codePages.length; i++) { + if (codePages[i].equals(a_codePage)) { + return true; + } // if + } // for i + + return false; + } + + public void addCodePage(String a_codePage) { + if (containsCodePage(a_codePage)) { + return; + } // if + + m_glyph.getHead().addCodePage(a_codePage); + } + + public void removeCodePage(String a_codePage) { + if (!containsCodePage(a_codePage)) { + return; + } // if + + m_glyph.getHead().removeCodePage(a_codePage); + } + + public void setFontFamilyName(String a_value) { + m_glyph.getHead().setFontFamily(a_value); + } + + public String getFontFamilyName() { + return m_glyph.getHead().getFontFamily(); + } + + public String getVersion() { + if (m_glyph.getHead().getVersion() == null) { + m_glyph.getHead().setVersion("0.1"); + } // if + + return m_glyph.getHead().getVersion(); + } + + public void setSubFamily(String a_value) { + m_glyph.getHead().setFontSubFamily(a_value); + } + + public void setDefaultMetrics() { + XHead head = m_glyph.getHead(); + head.setTopSideBearing(k_defaultTopSideBearing); + head.setAscender(k_defaultAscender); + head.setXHeight(k_defaultXHeight); + head.setDescender(k_defaultDescender); + head.setBottomSideBearing(k_defaultBottomSideBearing); + } + + public double getEm() { + return k_em; + } + + public double getBaseline() { + return getBottomSideBearing() + getDescender(); + } + + public double getMeanline() { + return getBottomSideBearing() + + getDescender() + getXHeight(); + } + + public double getBodyBottom() { + return getBottomSideBearing(); + } + + public double getBodyTop() { + return getEm() - getTopSideBearing(); + } + + public double getTopSideBearing() { + if (!m_glyph.getHead().checkTopSideBearing()) { + setDefaultMetrics(); + } // if + + return m_glyph.getHead().getTopSideBearing(); + } + + public double getAscender() { + if (!m_glyph.getHead().checkAscender()) { + setDefaultMetrics(); + } // if + + return m_glyph.getHead().getAscender(); + } + + public double getXHeight() { + if (!m_glyph.getHead().checkXHeight()) { + setDefaultMetrics(); + } // if + + return m_glyph.getHead().getXHeight(); + } + + public double getDescender() { + if (!m_glyph.getHead().checkDescender()) { + setDefaultMetrics(); + } // if + + return m_glyph.getHead().getDescender(); + } + + public double getBottomSideBearing() { + if (!m_glyph.getHead().checkBottomSideBearing()) { + setDefaultMetrics(); + } // if + + return m_glyph.getHead().getBottomSideBearing(); + } + + public void setTopSideBearing(double a_value) throws OutOfRangeException { + checkBoundary(a_value); + m_glyph.getHead().setTopSideBearing(a_value); + } + + private void checkBoundary(double a_value) throws OutOfRangeException { + if (a_value > k_em || a_value < 0) { + throw new OutOfRangeException(a_value); + } // if + } + + public void setAscender(double a_value) throws OutOfRangeException { + checkBoundary(a_value); + m_glyph.getHead().setAscender(a_value); + } + + public void setXHeight(double a_value) throws OutOfRangeException { + checkBoundary(a_value); + if (a_value > getAscender()) { + throw new OutOfRangeException(a_value); + } // if + + m_glyph.getHead().setXHeight(a_value); + } + + public void setDescender(double a_value) throws OutOfRangeException { + checkBoundary(a_value); + m_glyph.getHead().setDescender(a_value); + } + + public void setBottomSideBearing(double a_value) throws OutOfRangeException { + checkBoundary(a_value); + m_glyph.getHead().setBottomSideBearing(a_value); + } + + public double getBodyHeight() { + return k_em - getTopSideBearing() - getBottomSideBearing(); + } + +// -------------------------------------------------------------------- + + /** + * Calls FontFileWriter to produce TrueType font file. + */ + public void buildTTF(boolean a_isDebug) throws Exception { + String randomString = UUID.randomUUID().toString().substring(0, 4); + + File tempFile = new File(m_binFolder, + getGlyphTitle() + "_" + randomString + k_dotTtf); + File target; + String fontFamilyName; + + if (a_isDebug) { + target = tempFile; + fontFamilyName = getGlyphTitle() + " " + randomString; + } else { + target = m_ttfFile; + fontFamilyName = getFontFamilyName(); + } // if-else + + target.delete(); + FontFileWriter writer; + ModuleManager.getSingletonInstance().clear(); + m_stack.clear(); + m_stack.push(this); + try (RandomAccessFile randomAccessFile = new RandomAccessFile(target, "rw")) { + writer = new FontFileWriter(randomAccessFile); + + writer.setFontFamilyName(fontFamilyName); + writer.setCopyrightYear(getCopyrightYear()); + writer.setFontVersion(getVersion()); + writer.setManufacturer(getAuthor()); + writer.setAscent((int) getAscender()); + writer.setXHeight((int) getXHeight()); + writer.setDescent((int) getDescender()); + writer.setLineGap((int) (getTopSideBearing() + getBottomSideBearing())); + + loadCodePages(writer); + loadUnicodeRanges(writer); + loadGlyphs(writer); + writer.write(); + } + if (!a_isDebug && target.exists()) { + copyFile(target, tempFile); + } // if + + FileInputStream in = new FileInputStream(tempFile); + m_font = Font.createFont(Font.TRUETYPE_FONT, + (InputStream) in); + in.close(); + + ModuleManager.getSingletonInstance().clear(); + m_stack.pop(); // pop this + } + + private void copyFile(File a_in, File a_out) throws Exception { + FileInputStream in = new FileInputStream(a_in); + FileOutputStream out = new FileOutputStream(a_out); + byte [] buffer = new byte[1024]; + int i = 0; + while ((i = in.read(buffer)) != -1) { + out.write(buffer, 0, i); + } // while + + in.close(); + out.close(); + } + + public Font getFont() { + return m_font; + } + + private void loadCodePages(FontFileWriter a_writer) { + for (String codePageName: m_glyph.getHead().getCodePage()) { + TTCodePage codePage = TTCodePage.forName(codePageName); + if (codePage == null) { + continue; + } // if + + a_writer.setCodeRangeFlag(codePage.getOsTwoFlag()); + } // for codePageName + } + + private void loadUnicodeRanges(FontFileWriter a_writer) { + String [] unicodeRanges = m_glyph.getHead().getUnicodeRange(); + int i; + for (i = 0; i < unicodeRanges.length; i++) { + if (!TTUnicodeRange.find(unicodeRanges[i])) { + continue; + } // if + + a_writer.addUnicodeRange(TTUnicodeRange.getLastFound()); + } // for i + } + + private void loadGlyphs(FontFileWriter a_writer) throws Exception { + m_nameToIndeces.clear(); + + for (String fileName: getChildFileNames()) { + GlyphFile glyphFile = nameToGlyphFile(fileName); + loadGlyph(glyphFile, glyphFile, a_writer); + } // for + } + + private GlyphFile nameToGlyphFile(String a_fileName) throws FileNotFoundException { + if (!m_glyphFiles.containsKey(a_fileName)) { + throw new FileNotFoundException(a_fileName); + } // if + + GlyphFile retval = m_glyphFiles.get(a_fileName); + + return retval; + } + + /** + * load the glyph into FontFileWriter. + * @param a_fileName + * @param a_writer + * @throws Exception + */ + private void loadGlyph(GlyphFile a_glyphFile, VarStackFrame a_frame, FontFileWriter a_writer) throws Exception { + if (m_nameToIndeces.containsKey(a_glyphFile.getShortFileName())) { + return; + } // if + + /* + if (a_glyphFile.getUnicodeAsLong() == TTUnicodeRange.k_null) { + return; + } // if + */ + + TTGlyph glyph = null; + m_stack.push(a_frame); + + if (a_glyphFile.isSimple()) { + // glyph will be null if it is empty + glyph = a_glyphFile.toSimpleGlyph(); + } else { + glyph = createCompoundGlyph(a_glyphFile, a_writer); + } // if + + m_stack.pop(); + + if (glyph == null && a_glyphFile.isWhiteSpace()) { + glyph = new TTGlyph(); + } // if + + if (glyph == null) { + return; + } // if + + int glyphIndex = a_writer.addGlyph(glyph); + m_nameToIndeces.put(a_glyphFile.getShortFileName(), glyphIndex); + long unicode = a_glyphFile.getUnicodeAsLong(); + + if (unicode != -1 && glyph != null) { + long existingIndex = a_writer.getCharacterMapping(unicode); + if (existingIndex != 0) { + throw new Exception(Long.toHexString(unicode) + " is mapped already."); + } // if + + a_writer.addCharacterMapping(unicode, glyphIndex); + } // if + } + + private TTGlyph createCompoundGlyph(GlyphFile a_glyphFile, + FontFileWriter a_writer) throws Exception + { + TTGlyph retval = new TTGlyph(); + ArrayList locs = new ArrayList<>(); + ArrayList indeces = new ArrayList<>(); + + retval.setSimple(false); + retval.setAdvanceWidth(a_glyphFile.getAdvanceWidth()); + + TTGlyph simple = a_glyphFile.toSimpleGlyph(); + if (simple != null) { + int glyphIndex = a_writer.addGlyph(simple); + + locs.add(new Point(0, 0)); + indeces.add(glyphIndex); + } // if + + XInclude [] includes = a_glyphFile.m_glyph.getBody().getInclude(); + int i; + for (i = 0; i < includes.length; i++) { + EIncludeInvoke include = (EIncludeInvoke) includes[i]; + GlyphFile glyphFile = nameToGlyphFile(include.getHref()); + + // load the glyph included in this one + loadGlyph(glyphFile, include, a_writer); + Integer n = m_nameToIndeces.get(glyphFile.getShortFileName()); + if (n == null) { + continue; + } // if + + indeces.add(n); + XPoint2d pos = include.getInvoke().getInvokePos().getPoint2d(); + locs.add(new Point((int) pos.getX(), (int) pos.getY())); + } // for i + + int flag = TTGlyph.ARG_1_AND_2_ARE_WORDS + | TTGlyph.ARGS_ARE_XY_VALUES + | TTGlyph.ROUND_XY_TO_GRID; + int numOfCompositePoints = 0; + int numOfCompositeContours = 0; + int componentDepth = 0; + + for (int glyfIndex: indeces) { + TTGlyph glyph = a_writer.getGlyph(glyfIndex); + numOfCompositePoints += glyph.getNumOfCompositePoints(); + numOfCompositeContours += glyph.getNumOfCompositeContours(); + if (glyph.getComponentDepth() > componentDepth) { + componentDepth = glyph.getComponentDepth(); + } // if + + retval.addGlyfIndex(glyfIndex); + if (i < indeces.size() - 1) { + retval.addFlag(flag | TTGlyph.MORE_COMPONENTS); + } else { + retval.addFlag(flag); + } // if-else + + Point loc = locs.get(i); + retval.addArg1(loc.x); + retval.addArg2(loc.y); + } // for + + retval.setNumOfCompositePoints(numOfCompositePoints); + retval.setNumOfCompositeContours(numOfCompositeContours); + retval.setComponentDepth(componentDepth + 1); + + return retval; + } +} diff --git a/libsrc/ttf/src/org/doubletype/ossa/truetype/GlyfWriter.java b/libsrc/ttf/src/org/doubletype/ossa/truetype/GlyfWriter.java index 8a89e92b1..a0e650029 100644 --- a/libsrc/ttf/src/org/doubletype/ossa/truetype/GlyfWriter.java +++ b/libsrc/ttf/src/org/doubletype/ossa/truetype/GlyfWriter.java @@ -1,203 +1,204 @@ -/* - * $Id: GlyfWriter.java,v 1.17 2004/09/23 07:47:39 eed3si9n Exp $ - * - * $Copyright: copyright (c) 2003, e.e d3si9n $ - * $License: - * This source code is part of DoubleType. - * DoubleType is a graphical typeface designer. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * In addition, as a special exception, e.e d3si9n gives permission to - * link the code of this program with any Java Platform that is available - * to public with free of charge, including but not limited to - * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), - * and distribute linked combinations including the two. - * You must obey the GNU General Public License in all respects for all - * of the code used other than Java Platform. If you modify this file, - * you may extend this exception to your version of the file, but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. - * $ - */ - - -package org.doubletype.ossa.truetype; - -import java.io.*; -import java.awt.*; -import java.util.*; - -/** - * @author e.e - */ -public class GlyfWriter extends FontFormatWriter { - private ArrayList m_glyphs; - - private LocaWriter m_loca; - private MaxpWriter m_maxp; - private HeadWriter m_head; - private HdmxWriter m_hdmx; - - public GlyfWriter(LocaWriter a_loca, MaxpWriter a_maxp, - HeadWriter a_head, HdmxWriter a_hdmx) { - super(); - - m_loca = a_loca; - m_maxp = a_maxp; - m_head = a_head; - m_hdmx = a_hdmx; - m_glyphs = new ArrayList<>(); - } - - public void write() throws IOException { - m_hdmx.setNumGlyphs(numOfGlyph()); - m_maxp.setNumGlyphs(numOfGlyph()); - m_loca.m_offsets.clear(); - - for (int i = 0; i < m_glyphs.size(); i++) { - writeGlyph(m_glyphs.get(i)); - m_hdmx.updatePixelWidth(i, m_glyphs.get(i)); - } // for i - - m_loca.m_offsets.add(size()); - } - - public int add(TTGlyph a_glyph) { - m_head.updateMax(a_glyph.getMax()); - m_head.updateMin(a_glyph.getMin()); - - m_glyphs.add(a_glyph); - return m_glyphs.size() - 1; - } - - public int numOfGlyph() { - return m_glyphs.size(); - } - - public TTGlyph getGlyph(int a_index) { - return m_glyphs.get(a_index); - } - - private void writeGlyph(TTGlyph a_glyph) throws IOException { - m_loca.m_offsets.add(size()); - - if (a_glyph == null) { - return; - } // if - - if (a_glyph.isSimple()) { - writeSimpleGlyph(a_glyph); - } else { - writeCompoundGlyph(a_glyph); - } // if-else - - pad(); - } - - /** - * @param a_glyph - * @throws IOException - */ - private void writeSimpleGlyph(TTGlyph a_glyph) throws IOException { - if (a_glyph.getNumOfContours() == 0) { - return; - } // if - - m_maxp.updateNumOfContours(a_glyph.getNumOfContours()); - writeInt16(a_glyph.getNumOfContours()); - writeMinMax(a_glyph); - - int i; - for (i = 0; i < a_glyph.getNumOfContours(); i++) { - writeUInt16(a_glyph.getEndPoint(i)); - } // for i - - int numOfInst = a_glyph.getNumOfInstructions(); - m_maxp.updateSizeOfInstructions(numOfInst); - - writeUInt16(numOfInst); - for (i = 0; i < numOfInst; i++) { - writeUInt8(a_glyph.getInstruction(i)); - } // for i - - for (i = 0; i < a_glyph.getNumOfFlags(); i++) { - int flag = a_glyph.getFlag(i); - writeUInt8(flag); - } // for i - - // update num of points - m_maxp.updateNumOfPoints(a_glyph.getNumOfPoints()); - - int lastX = 0; - for (i = 0; i < a_glyph.getNumOfPoints(); i++) { - Point point = a_glyph.getPoint(i); - - writeInt16(point.x - lastX); - lastX = point.x; - } // for i - - int lastY = 0; - for (i = 0; i < a_glyph.getNumOfPoints(); i++) { - Point point = a_glyph.getPoint(i); - - writeInt16(point.y - lastY); - lastY = point.y; - } // for i - } - - /** - * @param a_glyph - * @throws IOException - */ - private void writeCompoundGlyph(TTGlyph a_glyph) throws IOException { - int i; - - m_maxp.updateNumOfCompositePoints(a_glyph.getNumOfCompositePoints()); - m_maxp.updateNumOfCompositeContours(a_glyph.getNumOfCompositeContours()); - - writeInt16(-1); - writeMinMax(a_glyph); - - int numOfGlyphs = a_glyph.getNumOfFlags(); - m_maxp.updateNumOfComponentElements(numOfGlyphs); - m_maxp.updateComponentDepth(a_glyph.getComponentDepth()); - - for (i = 0; i < numOfGlyphs; i++) { - writeUInt16(a_glyph.getFlag(i)); - writeUInt16(a_glyph.getGlyfIndex(i)); - writeInt16(a_glyph.getArg1(i)); - writeInt16(a_glyph.getArg2(i)); - } // for i - } - - /** - * @param a_glyph - * @throws IOException - */ - private void writeMinMax(TTGlyph a_glyph) throws IOException { - Point min = a_glyph.getMin(); - Point max = a_glyph.getMax(); - - writeFWord(min.x); - writeFWord(min.y); - writeFWord(max.x); - writeFWord(max.y); - } - - protected String getTag() { - return "glyf"; - } -} +/* + * $Id: GlyfWriter.java,v 1.17 2004/09/23 07:47:39 eed3si9n Exp $ + * + * $Copyright: copyright (c) 2003, e.e d3si9n $ + * $License: + * This source code is part of DoubleType. + * DoubleType is a graphical typeface designer. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * In addition, as a special exception, e.e d3si9n gives permission to + * link the code of this program with any Java Platform that is available + * to public with free of charge, including but not limited to + * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), + * and distribute linked combinations including the two. + * You must obey the GNU General Public License in all respects for all + * of the code used other than Java Platform. If you modify this file, + * you may extend this exception to your version of the file, but you are not + * obligated to do so. If you do not wish to do so, delete this exception + * statement from your version. + * $ + */ + + +package org.doubletype.ossa.truetype; + +import java.io.*; +import java.awt.*; +import java.util.*; + +/** + * @author e.e + */ +public class GlyfWriter extends FontFormatWriter { + private ArrayList m_glyphs; + + private LocaWriter m_loca; + private MaxpWriter m_maxp; + private HeadWriter m_head; + private HdmxWriter m_hdmx; + + public GlyfWriter(LocaWriter a_loca, MaxpWriter a_maxp, + HeadWriter a_head, HdmxWriter a_hdmx) { + super(); + + m_loca = a_loca; + m_maxp = a_maxp; + m_head = a_head; + m_hdmx = a_hdmx; + m_glyphs = new ArrayList<>(); + } + + public void write() throws IOException { + m_hdmx.setNumGlyphs(numOfGlyph()); + m_maxp.setNumGlyphs(numOfGlyph()); + m_loca.m_offsets.clear(); + + for (int i = 0; i < m_glyphs.size(); i++) { + TTGlyph glyph = m_glyphs.get(i); + writeGlyph(glyph); + m_hdmx.updatePixelWidth(i, glyph); + } // for i + + m_loca.m_offsets.add(size()); + } + + public int add(TTGlyph a_glyph) { + m_head.updateMax(a_glyph.getMax()); + m_head.updateMin(a_glyph.getMin()); + + m_glyphs.add(a_glyph); + return m_glyphs.size() - 1; + } + + public int numOfGlyph() { + return m_glyphs.size(); + } + + public TTGlyph getGlyph(int a_index) { + return m_glyphs.get(a_index); + } + + private void writeGlyph(TTGlyph a_glyph) throws IOException { + m_loca.m_offsets.add(size()); + + if (a_glyph == null) { + return; + } // if + + if (a_glyph.isSimple()) { + writeSimpleGlyph(a_glyph); + } else { + writeCompoundGlyph(a_glyph); + } // if-else + + pad(); + } + + /** + * @param a_glyph + * @throws IOException + */ + private void writeSimpleGlyph(TTGlyph a_glyph) throws IOException { + if (a_glyph.getNumOfContours() == 0) { + return; + } // if + + m_maxp.updateNumOfContours(a_glyph.getNumOfContours()); + writeInt16(a_glyph.getNumOfContours()); + writeMinMax(a_glyph); + + int i; + for (i = 0; i < a_glyph.getNumOfContours(); i++) { + writeUInt16(a_glyph.getEndPoint(i)); + } // for i + + int numOfInst = a_glyph.getNumOfInstructions(); + m_maxp.updateSizeOfInstructions(numOfInst); + + writeUInt16(numOfInst); + for (i = 0; i < numOfInst; i++) { + writeUInt8(a_glyph.getInstruction(i)); + } // for i + + for (i = 0; i < a_glyph.getNumOfFlags(); i++) { + int flag = a_glyph.getFlag(i); + writeUInt8(flag); + } // for i + + // update num of points + m_maxp.updateNumOfPoints(a_glyph.getNumOfPoints()); + + int lastX = 0; + for (i = 0; i < a_glyph.getNumOfPoints(); i++) { + Point point = a_glyph.getPoint(i); + + writeInt16(point.x - lastX); + lastX = point.x; + } // for i + + int lastY = 0; + for (i = 0; i < a_glyph.getNumOfPoints(); i++) { + Point point = a_glyph.getPoint(i); + + writeInt16(point.y - lastY); + lastY = point.y; + } // for i + } + + /** + * @param a_glyph + * @throws IOException + */ + private void writeCompoundGlyph(TTGlyph a_glyph) throws IOException { + int i; + + m_maxp.updateNumOfCompositePoints(a_glyph.getNumOfCompositePoints()); + m_maxp.updateNumOfCompositeContours(a_glyph.getNumOfCompositeContours()); + + writeInt16(-1); + writeMinMax(a_glyph); + + int numOfGlyphs = a_glyph.getNumOfFlags(); + m_maxp.updateNumOfComponentElements(numOfGlyphs); + m_maxp.updateComponentDepth(a_glyph.getComponentDepth()); + + for (i = 0; i < numOfGlyphs; i++) { + writeUInt16(a_glyph.getFlag(i)); + writeUInt16(a_glyph.getGlyfIndex(i)); + writeInt16(a_glyph.getArg1(i)); + writeInt16(a_glyph.getArg2(i)); + } // for i + } + + /** + * @param a_glyph + * @throws IOException + */ + private void writeMinMax(TTGlyph a_glyph) throws IOException { + Point min = a_glyph.getMin(); + Point max = a_glyph.getMax(); + + writeFWord(min.x); + writeFWord(min.y); + writeFWord(max.x); + writeFWord(max.y); + } + + protected String getTag() { + return "glyf"; + } +}