Fixed: #2595 FLA export - incorrect handling of imported fonts

Fixed: FLA export - incorrect handling of imported sprites
This commit is contained in:
Jindra Petřík
2026-01-03 10:25:07 +01:00
parent df70665b02
commit ebf31a40c8
57 changed files with 375 additions and 170 deletions
@@ -426,7 +426,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private static final Logger logger = Logger.getLogger(MainPanel.class.getName());
private Map<TreeItem, Set<Integer>> neededCharacters = new WeakHashMap<>();
private Map<TreeItem, Set<String>> neededCharacterClasses = new WeakHashMap<>();
private Map<TreeItem, Set<Integer>> missingNeededCharacters = new WeakHashMap<>();
private Map<TreeItem, Set<String>> missingNeededCharacterClasses = new WeakHashMap<>();
private CalculateMissingNeededThread calculateMissingNeededThread;
@@ -4925,21 +4927,28 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
List<TreeItem> sel = getAllSelected();
Set<Integer> needed = new HashSet<>();
Set<String> neededClasses = new HashSet<>();
for (TreeItem item : sel) {
if (item instanceof CharacterTag) {
CharacterTag characterTag = (CharacterTag) item;
characterTag.getNeededCharactersDeep(needed);
characterTag.getNeededCharactersDeep(needed, neededClasses);
needed.add(characterTag.getCharacterId());
}
}
List<Tag> tagsToRemove = new ArrayList<>();
for (Tag tag : swf.getTags()) {
loopt: for (Tag tag : swf.getTags()) {
if (tag instanceof CharacterTag) {
CharacterTag characterTag = (CharacterTag) tag;
if (!needed.contains(characterTag.getCharacterId())) {
tagsToRemove.add(tag);
for (String cls : characterTag.getClassNames()) {
if (neededClasses.contains(cls)) {
continue loopt;
}
}
if (needed.contains(characterTag.getCharacterId())) {
continue loopt;
}
tagsToRemove.add(tag);
}
}
@@ -6485,13 +6494,20 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
tag.getTagInfo(tagInfo);
Set<Integer> needed;
Set<String> neededClasses;
if (neededCharacters.containsKey(treeItem)) {
needed = neededCharacters.get(treeItem);
neededClasses = neededCharacterClasses.get(treeItem);
} else {
needed = new LinkedHashSet<>();
tag.getNeededCharactersDeep(needed);
neededClasses = new LinkedHashSet<>();
tag.getNeededCharactersDeep(needed, neededClasses);
neededCharacters.put(treeItem, needed);
neededCharacterClasses.put(treeItem, neededClasses);
}
if (needed.size() > 0) {
tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", "));
@@ -6826,7 +6842,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
}
}
private static void calculateMissingNeededCharacters(Map<TreeItem, Set<Integer>> neededMap, Map<TreeItem, Set<Integer>> missingNeededCharacters, Timelined tim) {
private static void calculateMissingNeededCharacters(Map<TreeItem, Set<Integer>> neededMap, Map<TreeItem, Set<Integer>> missingNeededCharacters, Map<TreeItem, Set<String>> missingNeededCharacterClasses, Timelined tim) {
List<Tag> tags = tim.getTags().toArrayList();
Map<Integer, List<CharacterIdTag>> nestedTags = new HashMap<>();
for (Tag t : tags) {
@@ -6844,7 +6860,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
characterId = ((CharacterIdTag) t).getCharacterId();
}
Set<Integer> needed = new LinkedHashSet<>();
t.getNeededCharactersDeep(needed);
Set<String> neededClasses = new LinkedHashSet<>();
t.getNeededCharactersDeep(needed, neededClasses);
neededMap.put(t, needed);
if ((t instanceof CharacterIdTag) && !(t instanceof PlaceObjectTypeTag)) {
needed = new HashSet<>();
@@ -6853,15 +6870,21 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
if ((t instanceof PlaceObjectTypeTag) && (characterId != -1) && nestedTags.containsKey(characterId)) {
for (CharacterIdTag n : nestedTags.get(characterId)) {
((Tag) n).getNeededCharactersDeep(needed);
((Tag) n).getNeededCharactersDeep(needed, neededClasses);
}
}
missingNeededCharacters.put(t, t.getMissingNeededCharacters(needed));
Set<Integer> resultNeeded = new LinkedHashSet<>();
Set<String> resultNeededClasses = new LinkedHashSet<>();
t.getMissingNeededCharacters(needed, neededClasses, resultNeeded, resultNeededClasses);
missingNeededCharacters.put(t, resultNeeded);
missingNeededCharacterClasses.put(t, resultNeededClasses);
if (characterId != -1 && tim.getTimeline().swf.getCharacter(characterId) == null) {
missingNeededCharacters.get(t).add(characterId);
}
//FIXME: missingNeededCharacterClasses ??
}
/*if (t instanceof DefineSpriteTag) {
calculateMissingNeededCharacters(neededMap, missingNeededCharacters, (DefineSpriteTag) t);
@@ -6871,19 +6894,21 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private void calculateMissingNeededCharacters() {
Map<TreeItem, Set<Integer>> missingNeededCharacters = new WeakHashMap<>();
Map<TreeItem, Set<String>> missingNeededCharacterClasses = new WeakHashMap<>();
Map<TreeItem, Set<Integer>> neededCharacters = new WeakHashMap<>();
List<OpenableList> swfsLists = new ArrayList<>(openables);
for (OpenableList swfList : swfsLists) {
for (Openable openable : swfList) {
if (openable instanceof SWF) {
calculateMissingNeededCharacters(neededCharacters, missingNeededCharacters, (SWF) openable);
calculateMissingNeededCharacters(neededCharacters, missingNeededCharacters, missingNeededCharacterClasses, (SWF) openable);
//TODO: how about SubSWFs???
}
}
}
this.neededCharacters = neededCharacters;
this.missingNeededCharacters = missingNeededCharacters;
tagTree.setMissingNeededCharacters(missingNeededCharacters);
tagListTree.setMissingNeededCharacters(missingNeededCharacters);
}
@@ -81,7 +81,9 @@ public class TimelinedMaker {
jpegTablesTag = imageTag.getSwf().getJtt();
}
Set<Integer> needed = new LinkedHashSet<>();
imageTag.getNeededCharacters(needed, swf);
Set<String> neededClasses = new LinkedHashSet<>();
//TODO: handle classes?
imageTag.getNeededCharacters(needed, neededClasses, swf);
List<CharacterTag> neededCopies = new ArrayList<>();
for (int n : needed) {
@@ -168,8 +168,10 @@ import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
@@ -2609,7 +2611,9 @@ public class TagTreeContextMenu extends JPopupMenu {
AlterCharacterTag alterTag = new AlterCharacterTag(targetSwf, targetSameNameCharacter.getCharacterId());
Set<Integer> needed = new LinkedHashSet<>();
targetSameNameCharacter.getNeededCharacters(needed, targetSwf);
Set<String> neededClasses = new LinkedHashSet<>();
//TODO: handle classes?
targetSameNameCharacter.getNeededCharacters(needed, neededClasses, targetSwf);
int ind = realTargetTimelined.indexOfTag(targetSameNameCharacter);
realTargetTimelined.removeTag(ind);
realTargetTimelined.addTag(ind, alterTag);
@@ -5066,20 +5070,32 @@ public class TagTreeContextMenu extends JPopupMenu {
Set<TreeItem> newItems = new LinkedHashSet<>();
for (TreeItem item : items) {
Set<Integer> needed = new LinkedHashSet<>();
Set<String> neededClasses = new LinkedHashSet<>();
Tag tag = (Tag) item;
tag.getNeededCharactersDeep(needed);
tag.getNeededCharactersDeep(needed, neededClasses);
if (tag instanceof CharacterTag) {
needed.add(((CharacterTag) tag).getCharacterId());
for (String cls : ((CharacterTag) tag).getClassNames()) {
neededClasses.add(cls);
}
}
Set<CharacterTag> neededChars = Collections.newSetFromMap(new IdentityHashMap<>());
for (Integer characterId : needed) {
CharacterTag neededTag = sourceSwf.getCharacter(characterId);
neededChars.add(neededTag);
}
for (String cls : neededClasses) {
neededChars.add(sourceSwf.getCharacterByClass(cls));
}
for (CharacterTag neededTag : neededChars) {
newItems.add(neededTag);
List<Integer> mappedClasses = AbstractTagTree.getMappedTagIdsForClass(neededTag.getClass());
ReadOnlyTagList tags = neededTag.getTimelined().getTags();
for (int i = tags.indexOf(neededTag) + 1; i < tags.size(); i++) {
if (tags.get(i) instanceof CharacterIdTag) {
CharacterIdTag characterIdTag = (CharacterIdTag) tags.get(i);
if (mappedClasses.contains(((Tag) characterIdTag).getId()) && characterIdTag.getCharacterId() == characterId) {
if (mappedClasses.contains(((Tag) characterIdTag).getId()) && characterIdTag.getCharacterId() == neededTag.getCharacterId() && ((Tag) characterIdTag).getSwf() == neededTag.getSwf()) {
newItems.add((Tag) characterIdTag);
}
}
@@ -6065,7 +6081,9 @@ public class TagTreeContextMenu extends JPopupMenu {
Set<Integer> dependentCharacters = swf.getDependentCharacters(ch);
if (dependentCharacters.isEmpty()) {
Set<Integer> needed = new LinkedHashSet<>();
ct.getNeededCharacters(needed, swf);
Set<String> neededClasses = new LinkedHashSet<>();
//TODO: handle classes?
ct.getNeededCharacters(needed, neededClasses, swf);
List<CharacterIdTag> attachedTags = swf.getCharacterIdTags(ch);
for (CharacterIdTag cit : attachedTags) {
if (cit instanceof Tag) {