From a02164197ec1541dc7b2d5e9bcc966e8367e5310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Mon, 29 Jul 2013 07:22:26 +0200 Subject: [PATCH] Issue #250 Export FLA: Static text spacing and marigins Better text viewer code formatting --- .../flash/abc/avm2/graph/AVM2Graph.java | 1 - .../decompiler/flash/gui/ExportDialog.java | 24 +-- .../com/jpexs/decompiler/flash/gui/Main.java | 21 +-- .../jpexs/decompiler/flash/gui/MainFrame.java | 19 +- .../flash/gui/abc/ASMSourceEditorPane.java | 1 - .../flash/gui/abc/DecompiledEditorPane.java | 4 - .../gui/abc/SlotConstTraitDetailPanel.java | 1 - .../flash/tags/DefineBitsLossless2Tag.java | 4 - .../flash/tags/DefineEditTextTag.java | 3 +- .../decompiler/flash/tags/DefineFont2Tag.java | 8 +- .../decompiler/flash/tags/DefineFont3Tag.java | 12 +- .../decompiler/flash/tags/DefineFontTag.java | 2 +- .../decompiler/flash/tags/DefineText2Tag.java | 34 ++-- .../decompiler/flash/tags/DefineTextTag.java | 33 ++-- .../decompiler/flash/tags/base/FontTag.java | 41 +++++ .../decompiler/flash/tags/base/ImageTag.java | 27 +-- .../decompiler/flash/tags/base/TextTag.java | 164 +++++++++++++++++- .../jpexs/decompiler/flash/types/SHAPE.java | 2 + .../decompiler/flash/types/ZONERECORD.java | 8 - .../flash/types/shaperecords/SHAPERECORD.java | 4 - .../decompiler/flash/xfl/XFLConverter.java | 25 ++- 21 files changed, 298 insertions(+), 140 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java index 404d058ce..bc322f220 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2Graph.java @@ -50,7 +50,6 @@ import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictEqAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictNeqAVM2Item; import com.jpexs.decompiler.flash.abc.types.ABCException; import com.jpexs.decompiler.flash.abc.types.MethodBody; -import com.jpexs.decompiler.flash.helpers.Helper; import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphPart; import com.jpexs.decompiler.graph.GraphPartMulti; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/ExportDialog.java b/trunk/src/com/jpexs/decompiler/flash/gui/ExportDialog.java index 6e34170df..ab18c985c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/ExportDialog.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/ExportDialog.java @@ -59,33 +59,33 @@ public class ExportDialog extends AppDialog { Container cnt = getContentPane(); cnt.setLayout(new BorderLayout()); - JPanel comboPanel=new JPanel(null); + JPanel comboPanel = new JPanel(null); combos = new JComboBox[optionNames.length]; - JLabel labels[]=new JLabel[optionNames.length]; - int labWidth=0; + JLabel labels[] = new JLabel[optionNames.length]; + int labWidth = 0; for (int i = 0; i < optionNames.length; i++) { labels[i] = new JLabel(optionNames[i]); - if(labels[i].getPreferredSize().width>labWidth){ + if (labels[i].getPreferredSize().width > labWidth) { labWidth = labels[i].getPreferredSize().width; } } - int comboWidth=200; + int comboWidth = 200; int top = 10; for (int i = 0; i < optionNames.length; i++) { JLabel lab = new JLabel(optionNames[i]); lab.setBounds(10, top, lab.getPreferredSize().width, lab.getPreferredSize().height); comboPanel.add(lab); combos[i] = new JComboBox<>(options[i]); - combos[i].setBounds(10+labWidth+10, top, comboWidth, combos[i].getPreferredSize().height); + combos[i].setBounds(10 + labWidth + 10, top, comboWidth, combos[i].getPreferredSize().height); comboPanel.add(combos[i]); top += combos[i].getHeight(); } - Dimension dim=new Dimension(10+labWidth+10+comboWidth+10,top+10); + Dimension dim = new Dimension(10 + labWidth + 10 + comboWidth + 10, top + 10); comboPanel.setMinimumSize(dim); comboPanel.setPreferredSize(dim); - cnt.add(comboPanel,BorderLayout.CENTER); + cnt.add(comboPanel, BorderLayout.CENTER); - JPanel buttonsPanel=new JPanel(new FlowLayout()); + JPanel buttonsPanel = new JPanel(new FlowLayout()); JButton okButton = new JButton(translate("button.ok")); okButton.addActionListener(new ActionListener() { @Override @@ -93,7 +93,7 @@ public class ExportDialog extends AppDialog { setVisible(false); } }); - + JButton cancelButton = new JButton(translate("button.cancel")); cancelButton.addActionListener(new ActionListener() { @Override @@ -102,11 +102,11 @@ public class ExportDialog extends AppDialog { setVisible(false); } }); - + buttonsPanel.add(okButton); buttonsPanel.add(cancelButton); - cnt.add(buttonsPanel,BorderLayout.SOUTH); + cnt.add(buttonsPanel, BorderLayout.SOUTH); pack(); //setSize(245, top + getInsets().top); View.centerScreen(this); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java index 7ad29fa5f..cd900dd67 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java @@ -36,36 +36,22 @@ import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel; import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; import com.jpexs.decompiler.flash.helpers.Cache; import com.jpexs.decompiler.flash.helpers.Helper; -import com.jpexs.decompiler.flash.types.ZONERECORD; import com.sun.jna.Platform; import com.sun.jna.WString; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.awt.font.GlyphVector; -import java.awt.font.LineMetrics; -import java.awt.font.TextAttribute; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; -import java.awt.geom.QuadCurve2D; import java.io.*; import java.net.Socket; import java.net.URLDecoder; import java.security.AccessController; import java.security.PrivilegedAction; -import java.text.AttributedCharacterIterator.Attribute; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Locale; -import java.util.Map; import java.util.Properties; import java.util.Scanner; import java.util.logging.ConsoleHandler; @@ -77,12 +63,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JFileChooser; import javax.swing.JFrame; -import static javax.swing.JFrame.EXIT_ON_CLOSE; import javax.swing.JOptionPane; -import javax.swing.JPanel; import javax.swing.SwingWorker; import javax.swing.UIManager; -import static javax.swing.WindowConstants.HIDE_ON_CLOSE; import javax.swing.filechooser.FileFilter; /** @@ -523,7 +506,7 @@ public class Main { } public static void initLang() { - if (Configuration.containsConfig("locale")) { + if (Configuration.containsConfig("locale")) { Locale.setDefault(Locale.forLanguageTag((String) Configuration.getConfig("locale", "en"))); } UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok")); @@ -630,7 +613,7 @@ public class Main { initLang(); View.setLookAndFeel(); - + if ((Boolean) Configuration.getConfig("cacheOnDisk", Boolean.TRUE)) { Cache.setStorageType(Cache.STORAGE_FILES); } else { diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index 3f646dcac..7baf25e15 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -1162,8 +1162,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel fontParams1.add(fontAddCharsPanel); JPanel fontSelectionPanel = new JPanel(new FlowLayout()); fontSelectionPanel.add(new JLabel(translate("font.source"))); - String fontNames[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); - fontSelection = new JComboBox<>(fontNames); + fontSelection = new JComboBox<>(FontTag.fontNames.toArray(new String[FontTag.fontNames.size()])); fontSelection.setSelectedIndex(0); fontSelection.setSelectedItem("Times New Roman"); fontSelection.setSelectedItem("Arial"); @@ -2382,16 +2381,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel if (fontName == null) { fontName = font.getFontName(tags); } - // - if (!fontNames.contains(fontName)) { - fontName = "Times New Roman"; - } - if (!fontNames.contains(fontName)) { - fontName = "Arial"; - } - if (!fontNames.contains(fontName)) { - fontName = fontSelection.getItemAt(0); - } + fontName = FontTag.findInstalledFontName(fontName); Font f = new Font(fontName, font.getFontStyle(), 18); if (!f.canDisplay(character)) { View.showMessageDialog(null, translate("error.font.nocharacter").replace("%char%", "" + character), translate("error"), JOptionPane.ERROR_MESSAGE); @@ -3105,10 +3095,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel if (sourceFontsMap.containsKey(ft.getFontId())) { fontSelection.setSelectedItem(sourceFontsMap.get(ft.getFontId())); } else { - fontSelection.setSelectedIndex(0); - fontSelection.setSelectedItem("Times New Roman"); - fontSelection.setSelectedItem("Arial"); - fontSelection.setSelectedItem(ft.getFontName(swf.tags)); + fontSelection.setSelectedItem(FontTag.findInstalledFontName(ft.getFontName(swf.tags))); } fontChangeList.componentResized(null); showDetailWithPreview(CARDFONTPANEL); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java b/trunk/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java index 12792f80e..65d2c06cb 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/abc/ASMSourceEditorPane.java @@ -33,7 +33,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Stack; -import javax.swing.JOptionPane; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/trunk/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index c95c98515..2008ed819 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -27,16 +27,12 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst; import static com.jpexs.decompiler.flash.gui.AppStrings.translate; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.helpers.Cache; -import com.jpexs.decompiler.flash.helpers.Helper; import com.jpexs.decompiler.flash.helpers.Highlighting; import com.jpexs.decompiler.flash.tags.ABCContainerTag; -import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/abc/SlotConstTraitDetailPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/abc/SlotConstTraitDetailPanel.java index 3016719a5..b5214ca48 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/abc/SlotConstTraitDetailPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/abc/SlotConstTraitDetailPanel.java @@ -25,7 +25,6 @@ import static com.jpexs.decompiler.flash.gui.AppStrings.translate; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.helpers.Helper; import java.awt.BorderLayout; -import java.awt.Color; import java.awt.Font; import java.util.ArrayList; import javax.swing.*; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java index 0fc858296..81eb180d6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java @@ -24,11 +24,7 @@ import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA; import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA; import com.jpexs.decompiler.flash.types.ARGB; -import com.jpexs.decompiler.flash.types.RGBA; -import java.awt.AlphaComposite; -import java.awt.Color; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 507493859..fe82f4763 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; import com.jpexs.decompiler.flash.tags.base.TextTag; @@ -50,7 +49,7 @@ import java.util.regex.Pattern; * * @author JPEXS */ -public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextTag { +public class DefineEditTextTag extends TextTag { public int characterID; public RECT bounds; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index e71c78428..97659cd60 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -26,7 +26,6 @@ import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPE; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; import java.awt.Font; -import java.awt.font.GlyphVector; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -78,7 +77,7 @@ public class DefineFont2Tag extends FontTag { if (fontFlagsHasLayout) { return fontAdvanceTable.get(glyphIndex); } else { - return getGlyphWidth(glyphIndex) + 20; + return -1; } } @@ -348,4 +347,9 @@ public class DefineFont2Tag extends FontTag { } return ret; } + + @Override + public boolean hasLayout() { + return fontFlagsHasLayout; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index e7f7ab1f9..876671847 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -32,11 +32,8 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.JPanel; public class DefineFont3Tag extends FontTag { @@ -71,7 +68,7 @@ public class DefineFont3Tag extends FontTag { @Override public int getGlyphWidth(int glyphIndex) { - return glyphShapeTable.get(glyphIndex).getBounds().getWidth() / 20; + return glyphShapeTable.get(glyphIndex).getBounds().getWidth(); } @Override @@ -79,7 +76,7 @@ public class DefineFont3Tag extends FontTag { if (fontFlagsHasLayout) { return fontAdvanceTable.get(glyphIndex) / 20; } else { - return getGlyphWidth(glyphIndex) + 20; + return -1; } } @@ -349,4 +346,9 @@ public class DefineFont3Tag extends FontTag { } return ret; } + + @Override + public boolean hasLayout() { + return fontFlagsHasLayout; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java index 873976ecf..3709f0fcb 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java @@ -49,7 +49,7 @@ public class DefineFontTag extends FontTag { @Override public int getGlyphAdvance(int glyphIndex) { - return getGlyphWidth(glyphIndex); + return -1; } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index 0f7b6ea41..12c98de32 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.Helper; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.FontTag; @@ -64,7 +63,7 @@ import java.util.regex.Pattern; * * @author JPEXS */ -public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag, DrawableTag { +public class DefineText2Tag extends TextTag implements DrawableTag { public int characterID; public RECT textBounds; @@ -343,17 +342,15 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag, } tr.glyphEntries[i].glyphIndex = font.charToGlyph(tags, c); - /*if (tr.glyphEntries[i].glyphIndex == -1) { - throw new ParseException("Font does not contain glyph for character '" + c + "'", lexer.yyline()); - }*/ - tr.glyphEntries[i].glyphAdvance = textHeight * font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) / 1024; - - int gw = textHeight * font.getGlyphWidth(tr.glyphEntries[i].glyphIndex) / 1024; - if (i == 0) { - currentX += gw; + int advance; + if (font.hasLayout()) { + advance = (int) Math.round((double) textHeight * font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) / (font.getDivider() * 1024.0)); } else { - currentX += tr.glyphEntries[i].glyphAdvance; + advance = 20 * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), textHeight / 20, c); } + tr.glyphEntries[i].glyphAdvance = advance; + + currentX += advance; if (SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex) > glyphBits) { glyphBits = SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex); } @@ -461,6 +458,8 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag, @Override public BufferedImage toImage(int frame, List tags, RECT displayRect, HashMap characters, Stack visited) { RECT bound = getBounds(); + int fixX = -bound.Xmin; + int fixY = -bound.Ymin; BufferedImage ret = new BufferedImage(bound.Xmax / 20, bound.Ymax / 20, BufferedImage.TYPE_INT_ARGB); Color textColor = new Color(0, 0, 0); FontTag font = null; @@ -482,10 +481,10 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag, textHeight = rec.textHeight; } if (rec.styleFlagsHasXOffset) { - x = rec.xOffset * 1024 / textHeight; + x = rec.xOffset; } if (rec.styleFlagsHasYOffset) { - y = rec.yOffset * 1024 / textHeight; + y = rec.yOffset; } for (GLYPHENTRY entry : rec.glyphEntries) { @@ -494,14 +493,15 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag, rect.Xmin /= font.getDivider(); rect.Ymax /= font.getDivider(); rect.Ymin /= font.getDivider(); - BufferedImage img = SHAPERECORD.shapeToImage(tags, 4, null, null, glyphs.get(entry.glyphIndex).shapeRecords, textColor); + BufferedImage img = SHAPERECORD.shapeToImage(tags, 1, null, null, glyphs.get(entry.glyphIndex).shapeRecords, textColor); AffineTransform tr = new AffineTransform(); tr.setToIdentity(); float rat = textHeight / 1024f; - tr.translate(rat * x / 20, rat * (y + rect.Ymin) / 20); - tr.scale(rat / font.getDivider(), rat / font.getDivider()); + tr.scale(1 / 20f, 1 / 20f); + tr.translate(x + fixX, y + rat * rect.Ymin + fixY); + tr.scale(rat, rat); g.drawImage(img, tr, null); - x += entry.glyphAdvance * 1024 / textHeight; + x += entry.glyphAdvance; } } return ret; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index fc1f8c78d..fb01690d1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.helpers.Helper; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.FontTag; @@ -64,7 +63,7 @@ import java.util.regex.Pattern; * * @author JPEXS */ -public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag, DrawableTag { +public class DefineTextTag extends TextTag implements DrawableTag { public int characterID; public RECT textBounds; @@ -342,19 +341,15 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag, } tr.glyphEntries[i].glyphIndex = font.charToGlyph(tags, c); - - - /*if (tr.glyphEntries[i].glyphIndex == -1) { - throw new ParseException("Font does not contain glyph for character '" + c + "'", lexer.yyline()); - }*/ - tr.glyphEntries[i].glyphAdvance = textHeight * font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) / 1024; - - int gw = textHeight * font.getGlyphWidth(tr.glyphEntries[i].glyphIndex) / 1024; - if (i == 0) { - currentX += gw; + int advance; + if (font.hasLayout()) { + advance = (int) Math.round((double) textHeight * font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) / (font.getDivider() * 1024.0)); } else { - currentX += tr.glyphEntries[i].glyphAdvance; + advance = 20 * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), textHeight / 20, c); } + tr.glyphEntries[i].glyphAdvance = advance; + + currentX += advance; if (SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex) > glyphBits) { glyphBits = SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex); } @@ -497,10 +492,10 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag, textHeight = rec.textHeight; } if (rec.styleFlagsHasXOffset) { - x = rec.xOffset * 1024 / textHeight; + x = rec.xOffset; } if (rec.styleFlagsHasYOffset) { - y = rec.yOffset * 1024 / textHeight; + y = rec.yOffset; } for (GLYPHENTRY entry : rec.glyphEntries) { @@ -513,11 +508,11 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag, AffineTransform tr = new AffineTransform(); tr.setToIdentity(); float rat = textHeight / 1024f; - tr.translate(rat * x / 20, rat * (y + rect.Ymin) / 20); - tr.scale(rat / font.getDivider(), rat / font.getDivider()); - tr.translate(fixX, fixY); + tr.scale(1 / 20f, 1 / 20f); + tr.translate(x + fixX, y + rat * rect.Ymin + fixY); + tr.scale(rat, rat); g.drawImage(img, tr, null); - x += entry.glyphAdvance * 1024 / textHeight; + x += entry.glyphAdvance; } } return ret; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index 5819e5b83..c48ae445c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -24,7 +24,12 @@ import com.jpexs.decompiler.flash.types.GLYPHENTRY; import com.jpexs.decompiler.flash.types.SHAPE; import com.jpexs.decompiler.flash.types.TEXTRECORD; import java.awt.Font; +import java.awt.GraphicsEnvironment; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -67,6 +72,10 @@ public abstract class FontTag extends CharacterTag implements AloneTag { public abstract int getLeading(); + public boolean hasLayout() { + return false; + } + public boolean containsChar(List tags, char character) { return charToGlyph(tags, character) > -1; } @@ -125,4 +134,36 @@ public abstract class FontTag extends CharacterTag implements AloneTag { } } } + + public static int getSystemFontAdvance(String fontName, int fontStyle, int fontSize, char character) { + return getSystemFontAdvance(new Font(fontName, fontStyle, fontSize), character); + } + + public static int getSystemFontAdvance(Font aFont, char character) { + GlyphVector gv = aFont.createGlyphVector(new FontRenderContext(aFont.getTransform(), true, true), "" + character); + GlyphMetrics gm = gv.getGlyphMetrics(0); + return Math.round(gm.getAdvanceX()); + } + public static List fontNames = Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()); + + public static String findInstalledFontName(String fontName) { + if (fontNames.contains(fontName)) { + return fontName; + } + if (fontName.contains("_")) { + String beforeUnderscore = fontName.substring(0, fontName.indexOf("_")); + if (fontNames.contains(beforeUnderscore)) { + return beforeUnderscore; + } + } + fontName = "Times New Roman"; + if (fontNames.contains(fontName)) { + return fontName; + } + fontName = "Arial"; + if (fontNames.contains(fontName)) { + return fontName; + } + return fontNames.get(0); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java index 8bfa394dc..7ed65d1c4 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java @@ -60,23 +60,24 @@ public abstract class ImageTag extends CharacterTag { return "unk"; } - - protected static int max255(float val){ - if(val>255){ + + protected static int max255(float val) { + if (val > 255) { return 255; } - return (int)val; + return (int) val; } - - protected static Color intToColor(int val){ - return new Color(val&0xff,(val>>8)&0xff,(val>>16)&0xff,(val>>24)&0xff); + + protected static Color intToColor(int val) { + return new Color(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff); } - protected static int colorToInt(Color c){ - return (c.getAlpha()<<24)|(c.getBlue()<<16)|(c.getGreen()<<8)|c.getRed(); + + protected static int colorToInt(Color c) { + return (c.getAlpha() << 24) | (c.getBlue() << 16) | (c.getGreen() << 8) | c.getRed(); } - - protected static Color multiplyAlpha(Color c){ - float multiplier = c.getAlpha()==0?0:255.0f/c.getAlpha(); - return new Color(max255(c.getRed()*multiplier), max255(c.getGreen()*multiplier), max255(c.getBlue()*multiplier), c.getAlpha()); + + protected static Color multiplyAlpha(Color c) { + float multiplier = c.getAlpha() == 0 ? 0 : 255.0f / c.getAlpha(); + return new Color(max255(c.getRed() * multiplier), max255(c.getGreen() * multiplier), max255(c.getBlue() * multiplier), c.getAlpha()); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java index 43863262d..5bc927e60 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java @@ -16,29 +16,177 @@ */ package com.jpexs.decompiler.flash.tags.base; +import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.text.ParseException; +import com.jpexs.decompiler.flash.types.GLYPHENTRY; import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.TEXTRECORD; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GraphicsEnvironment; +import java.awt.Point; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * * @author JPEXS */ -public interface TextTag { +public abstract class TextTag extends CharacterTag implements BoundedTag { - public MATRIX getTextMatrix(); + public TextTag(SWF swf, int id, String name, byte[] data, long pos) { + super(swf, id, name, data, pos); + } - public String getText(List tags); + public abstract MATRIX getTextMatrix(); - public String getFormattedText(List tags); + public abstract String getText(List tags); - public boolean setFormattedText(MissingCharacterHandler missingCharHandler, List tags, String text, String fontName) throws ParseException; + public abstract String getFormattedText(List tags); - public int getCharacterId(); + public abstract boolean setFormattedText(MissingCharacterHandler missingCharHandler, List tags, String text, String fontName) throws ParseException; - public RECT getBounds(); + @Override + public abstract int getCharacterId(); - public void setBounds(RECT r); + public abstract RECT getBounds(); + + public abstract void setBounds(RECT r); + + private static void updateRect(RECT ret, int x, int y) { + if (x < ret.Xmin) { + ret.Xmin = x; + } + if (x > ret.Xmax) { + ret.Xmax = x; + } + if (y < ret.Ymin) { + ret.Ymin = y; + } + if (y > ret.Ymax) { + ret.Ymax = y; + } + } + + public static Map getTextRecordsAttributes(List list, List tags) { + Map att = new HashMap<>(); + RECT textBounds = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE); + FontTag font = null; + int x = 0; + int y = 0; + int textHeight = 12; + int lineSpacing = 0; + double leading = 0; + double ascent = 0; + double descent = 0; + double lineDistance = 0; + + List availableFonts = Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()); + + List glyphs = new ArrayList<>(); + boolean firstLine = true; + double top = 0; + List allLeftMargins = new ArrayList<>(); + List allLetterSpacings = new ArrayList<>(); + FontMetrics fontMetrics = null; + BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB); + Font aFont = null; + int currentLeftMargin = 0; + for (int r = 0; r < list.size(); r++) { + TEXTRECORD rec = list.get(r); + if (rec.styleFlagsHasFont) { + for (Tag t : tags) { + if (t instanceof FontTag) { + FontTag ft = (FontTag) t; + if (ft.getFontId() == rec.fontId) { + font = ft; + } + } + } + textHeight = rec.textHeight; + glyphs = font.getGlyphShapeTable(); + + if (font.getLeading() == -1) { + String fontName = font.getFontName(tags); + if (!availableFonts.contains(fontName)) { + fontName = "Times New Roman"; + } + if (!availableFonts.contains(fontName)) { + fontName = "Arial"; + } + aFont = new Font(fontName, font.getFontStyle(), textHeight / 20); + fontMetrics = bi.getGraphics().getFontMetrics(aFont); + LineMetrics lm = fontMetrics.getLineMetrics("A", bi.getGraphics()); + ascent = lm.getAscent(); + descent = lm.getDescent(); + leading = lm.getLeading(); + lineDistance = ascent + descent; + } else { + leading = ((double) font.getLeading() * textHeight / 1024.0 / font.getDivider() / 20.0); + ascent = ((double) font.getAscent() * textHeight / 1024.0 / font.getDivider() / 20.0); + descent = ((double) font.getDescent() * textHeight / 1024.0 / font.getDivider() / 20.0); + lineDistance = ascent + descent; + } + + } + currentLeftMargin = 0; + if (rec.styleFlagsHasXOffset) { + x = rec.xOffset; + currentLeftMargin = x; + } + if (rec.styleFlagsHasYOffset) { + if (!firstLine) { + top += lineDistance; + int topint = 20 * (int) Math.round(top); + lineSpacing = rec.yOffset - topint; + top += ((double) lineSpacing) / 20; + } else { + top = ascent - 2.0; //I don't know why, but there are always 2 pixels + } + y = rec.yOffset; + } + firstLine = false; + String lineStr = ""; + allLeftMargins.add(currentLeftMargin); + int letterSpacing = 0; + for (int e = 0; e < rec.glyphEntries.length; e++) { + GLYPHENTRY entry = rec.glyphEntries[e]; + GLYPHENTRY nextEntry = null; + if (e < rec.glyphEntries.length - 1) { + nextEntry = rec.glyphEntries[e + 1]; + } + RECT rect = SHAPERECORD.getBounds(glyphs.get(entry.glyphIndex).shapeRecords); + rect.Xmax = (int) Math.round(((double) rect.Xmax * textHeight) / (font.getDivider() * 1024)); + rect.Xmin = (int) Math.round(((double) rect.Xmin * textHeight) / (font.getDivider() * 1024)); + rect.Ymax = (int) Math.round(((double) rect.Ymax * textHeight) / (font.getDivider() * 1024)); + rect.Ymin = (int) Math.round(((double) rect.Ymin * textHeight) / (font.getDivider() * 1024)); + updateRect(textBounds, x + rect.Xmin, y + rect.Ymin); + updateRect(textBounds, x + rect.Xmax, y + rect.Ymax); + int adv = entry.glyphAdvance; + int defaultAdvance = 20 * FontTag.getSystemFontAdvance(aFont, font.glyphToChar(tags, entry.glyphIndex)); + letterSpacing = adv - defaultAdvance; + x += adv; + } + allLetterSpacings.add(letterSpacing); + } + att.put("indent", 0); //? + att.put("rightMargin", 0); //? + att.put("lineSpacing", lineSpacing); + att.put("textBounds", textBounds); + att.put("allLeftMargins", allLeftMargins); + att.put("allLetterSpacings", allLetterSpacings); + return att; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java b/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java index 6c3933eca..b25ee4529 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java @@ -19,6 +19,8 @@ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import java.awt.Point; import java.awt.image.BufferedImage; import java.util.HashSet; import java.util.List; diff --git a/trunk/src/com/jpexs/decompiler/flash/types/ZONERECORD.java b/trunk/src/com/jpexs/decompiler/flash/types/ZONERECORD.java index c11dba749..6c501cccb 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/ZONERECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/ZONERECORD.java @@ -16,14 +16,6 @@ */ package com.jpexs.decompiler.flash.types; -import java.awt.Font; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphMetrics; -import java.awt.font.GlyphVector; -import java.awt.font.LineBreakMeasurer; -import java.awt.font.LineMetrics; -import javax.swing.JFrame; - /** * Represents 32-bit alpha, red, green and blue value * diff --git a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java index ef5499313..bd1b6726d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java @@ -35,7 +35,6 @@ import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsEnvironment; import java.awt.LinearGradientPaint; @@ -49,10 +48,8 @@ import java.awt.TexturePaint; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; -import java.awt.geom.Path2D; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; -import java.awt.geom.QuadCurve2D; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Arrays; @@ -63,7 +60,6 @@ import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.JFrame; import javax.swing.JPanel; /** diff --git a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 18eb95103..c666bfc82 100644 --- a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -2277,6 +2277,8 @@ public class XFLConverter { ret += " instanceName=\"" + xmlString(instanceName) + "\""; } ret += antiAlias; + Map attrs = TextTag.getTextRecordsAttributes(textRecords, tags); + ret += " width=\"" + tag.getBounds().getWidth() / 2 + "\" height=\"" + tag.getBounds().getHeight() + "\" autoExpand=\"true\" isSelectable=\"false\">"; ret += matStr; @@ -2289,7 +2291,14 @@ public class XFLConverter { int textHeight = -1; RGB textColor = null; RGBA textColorA = null; - for (TEXTRECORD rec : textRecords) { + boolean newline = false; + boolean firstRun = true; + @SuppressWarnings("unchecked") + List leftMargins = (List) attrs.get("allLeftMargins"); + @SuppressWarnings("unchecked") + List letterSpacings = (List) attrs.get("allLetterSpacings"); + for (int r = 0; r < textRecords.size(); r++) { + TEXTRECORD rec = textRecords.get(r); if (rec.styleFlagsHasColor) { if (tag instanceof DefineTextTag) { textColor = rec.textColor; @@ -2327,13 +2336,23 @@ public class XFLConverter { } } } + newline = false; + if (!firstRun && rec.styleFlagsHasYOffset) { + newline = true; + } + firstRun = false; if (font != null) { ret += ""; - ret += "" + xmlString(rec.getText(tags, font)) + ""; + ret += "" + xmlString((newline ? "\r" : "") + rec.getText(tags, font)) + ""; ret += ""; ret += "