mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-26 15:10:51 +00:00
remove character functionality
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -145,11 +145,17 @@ public class DefineFontInfo2Tag extends FontInfoTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCharacter(int index, int character) {
|
||||
public void addFontCharacter(int index, int character) {
|
||||
codeTable.add(index, character);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFontCharacter(int index) {
|
||||
codeTable.remove(index);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontName() {
|
||||
return fontName;
|
||||
|
||||
@@ -146,11 +146,17 @@ public class DefineFontInfoTag extends FontInfoTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCharacter(int index, int character) {
|
||||
public void addFontCharacter(int index, int character) {
|
||||
codeTable.add(index, character);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFontCharacter(int index) {
|
||||
codeTable.remove(index);
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontName() {
|
||||
return fontName;
|
||||
|
||||
@@ -1,346 +1,382 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
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.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontInfoTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.awt.Font;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 1)
|
||||
public class DefineFontTag extends FontTag {
|
||||
|
||||
public static final int ID = 10;
|
||||
|
||||
public static final String NAME = "DefineFont";
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int fontId;
|
||||
|
||||
public List<SHAPE> glyphShapeTable;
|
||||
|
||||
@Internal
|
||||
private FontInfoTag fontInfoTag = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineFontTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
fontId = swf.getNextCharacterId();
|
||||
glyphShapeTable = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineFontTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
fontId = sis.readUI16("fontId");
|
||||
glyphShapeTable = new ArrayList<>();
|
||||
|
||||
if (sis.available() > 0) {
|
||||
long pos = sis.getPos();
|
||||
int firstOffset = sis.readUI16("firstOffset");
|
||||
int nGlyphs = firstOffset / 2;
|
||||
|
||||
long[] offsetTable = new long[nGlyphs];
|
||||
offsetTable[0] = firstOffset;
|
||||
for (int i = 1; i < nGlyphs; i++) {
|
||||
offsetTable[i] = sis.readUI16("offset");
|
||||
}
|
||||
for (int i = 0; i < nGlyphs; i++) {
|
||||
sis.seek(pos + offsetTable[i]);
|
||||
glyphShapeTable.add(sis.readSHAPE(1, false, "shape"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(fontId);
|
||||
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
||||
List<Integer> offsetTable = new ArrayList<>();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion());
|
||||
for (SHAPE shape : glyphShapeTable) {
|
||||
offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos());
|
||||
sos2.writeSHAPE(shape, 1);
|
||||
}
|
||||
for (int offset : offsetTable) {
|
||||
sos.writeUI16(offset);
|
||||
}
|
||||
sos.write(baos2.toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSmall() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getGlyphAdvance(int glyphIndex) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlyphWidth(int glyphIndex) {
|
||||
return glyphShapeTable.get(glyphIndex).getBounds().getWidth();
|
||||
}
|
||||
|
||||
private void ensureFontInfo() {
|
||||
if (fontInfoTag == null) {
|
||||
List<CharacterIdTag> characterIdTags = swf.getCharacterIdTags(fontId);
|
||||
if (characterIdTags != null) {
|
||||
for (CharacterIdTag t : characterIdTags) {
|
||||
if (t instanceof FontInfoTag) {
|
||||
if (((FontInfoTag) t).fontID == fontId) {
|
||||
fontInfoTag = (FontInfoTag) t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char glyphToChar(int glyphIndex) {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
return (char) (int) fontInfoTag.getCodeTable().get(glyphIndex);
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int charToGlyph(char c) {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
return fontInfoTag.getCodeTable().indexOf((int) c);
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SHAPE> getGlyphShapeTable() {
|
||||
return glyphShapeTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return fontId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.fontId = characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontNameIntag() {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
return fontInfoTag.getFontName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBold() {
|
||||
if (fontInfoTag != null) {
|
||||
return fontInfoTag.getFontFlagsBold();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItalic() {
|
||||
if (fontInfoTag != null) {
|
||||
return fontInfoTag.getFontFlagsItalic();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSmallEditable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBoldEditable() {
|
||||
return fontInfoTag != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItalicEditable() {
|
||||
return fontInfoTag != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSmall(boolean value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBold(boolean value) {
|
||||
if (fontInfoTag != null) {
|
||||
fontInfoTag.setFontFlagsBold(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItalic(boolean value) {
|
||||
if (fontInfoTag != null) {
|
||||
fontInfoTag.setFontFlagsItalic(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAscent() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDescent() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLeading() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDivider() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCharacter(char character, Font font) {
|
||||
SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character);
|
||||
ensureFontInfo();
|
||||
int code = (int) character;
|
||||
int pos = -1;
|
||||
boolean exists = false;
|
||||
if (fontInfoTag != null) {
|
||||
List<Integer> codeTable = fontInfoTag.getCodeTable();
|
||||
for (int i = 0; i < codeTable.size(); i++) {
|
||||
if (codeTable.get(i) >= code) {
|
||||
if (codeTable.get(i) == code) {
|
||||
exists = true;
|
||||
}
|
||||
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == -1) {
|
||||
pos = codeTable.size();
|
||||
}
|
||||
} else {
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
shiftGlyphIndices(fontId, pos);
|
||||
glyphShapeTable.add(pos, shp);
|
||||
if (fontInfoTag != null) {
|
||||
fontInfoTag.addCharacter(pos, (int) character);
|
||||
}
|
||||
} else {
|
||||
glyphShapeTable.set(pos, shp);
|
||||
}
|
||||
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdvanceValues(Font font) {
|
||||
throw new UnsupportedOperationException("Setting the advance values for DefineFontTag is not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterCount() {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
List<Integer> codeTable = fontInfoTag.getCodeTable();
|
||||
return codeTable.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacters() {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
List<Integer> codeTable = fontInfoTag.getCodeTable();
|
||||
StringBuilder ret = new StringBuilder(codeTable.size());
|
||||
for (int i : codeTable) {
|
||||
ret.append((char) i);
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharKerningAdjustment(char c1, char c2) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
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.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontInfoTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.awt.Font;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 1)
|
||||
public class DefineFontTag extends FontTag {
|
||||
|
||||
public static final int ID = 10;
|
||||
|
||||
public static final String NAME = "DefineFont";
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int fontId;
|
||||
|
||||
public List<SHAPE> glyphShapeTable;
|
||||
|
||||
@Internal
|
||||
private FontInfoTag fontInfoTag = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public DefineFontTag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
fontId = swf.getNextCharacterId();
|
||||
glyphShapeTable = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineFontTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
fontId = sis.readUI16("fontId");
|
||||
glyphShapeTable = new ArrayList<>();
|
||||
|
||||
if (sis.available() > 0) {
|
||||
long pos = sis.getPos();
|
||||
int firstOffset = sis.readUI16("firstOffset");
|
||||
int nGlyphs = firstOffset / 2;
|
||||
|
||||
long[] offsetTable = new long[nGlyphs];
|
||||
offsetTable[0] = firstOffset;
|
||||
for (int i = 1; i < nGlyphs; i++) {
|
||||
offsetTable[i] = sis.readUI16("offset");
|
||||
}
|
||||
for (int i = 0; i < nGlyphs; i++) {
|
||||
sis.seek(pos + offsetTable[i]);
|
||||
glyphShapeTable.add(sis.readSHAPE(1, false, "shape"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUI16(fontId);
|
||||
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
||||
List<Integer> offsetTable = new ArrayList<>();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion());
|
||||
for (SHAPE shape : glyphShapeTable) {
|
||||
offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos());
|
||||
sos2.writeSHAPE(shape, 1);
|
||||
}
|
||||
for (int offset : offsetTable) {
|
||||
sos.writeUI16(offset);
|
||||
}
|
||||
sos.write(baos2.toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSmall() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getGlyphAdvance(int glyphIndex) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlyphWidth(int glyphIndex) {
|
||||
return glyphShapeTable.get(glyphIndex).getBounds().getWidth();
|
||||
}
|
||||
|
||||
private void ensureFontInfo() {
|
||||
if (fontInfoTag == null) {
|
||||
List<CharacterIdTag> characterIdTags = swf.getCharacterIdTags(fontId);
|
||||
if (characterIdTags != null) {
|
||||
for (CharacterIdTag t : characterIdTags) {
|
||||
if (t instanceof FontInfoTag) {
|
||||
if (((FontInfoTag) t).fontID == fontId) {
|
||||
fontInfoTag = (FontInfoTag) t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char glyphToChar(int glyphIndex) {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
return (char) (int) fontInfoTag.getCodeTable().get(glyphIndex);
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int charToGlyph(char c) {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
return fontInfoTag.getCodeTable().indexOf((int) c);
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SHAPE> getGlyphShapeTable() {
|
||||
return glyphShapeTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return fontId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.fontId = characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFontNameIntag() {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
return fontInfoTag.getFontName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBold() {
|
||||
if (fontInfoTag != null) {
|
||||
return fontInfoTag.getFontFlagsBold();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItalic() {
|
||||
if (fontInfoTag != null) {
|
||||
return fontInfoTag.getFontFlagsItalic();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSmallEditable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBoldEditable() {
|
||||
return fontInfoTag != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItalicEditable() {
|
||||
return fontInfoTag != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSmall(boolean value) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBold(boolean value) {
|
||||
if (fontInfoTag != null) {
|
||||
fontInfoTag.setFontFlagsBold(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItalic(boolean value) {
|
||||
if (fontInfoTag != null) {
|
||||
fontInfoTag.setFontFlagsItalic(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAscent() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDescent() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLeading() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDivider() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCharacter(char character, Font font) {
|
||||
SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character);
|
||||
ensureFontInfo();
|
||||
int code = (int) character;
|
||||
int pos = -1;
|
||||
boolean exists = false;
|
||||
if (fontInfoTag != null) {
|
||||
List<Integer> codeTable = fontInfoTag.getCodeTable();
|
||||
for (int i = 0; i < codeTable.size(); i++) {
|
||||
if (codeTable.get(i) >= code) {
|
||||
if (codeTable.get(i) == code) {
|
||||
exists = true;
|
||||
}
|
||||
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == -1) {
|
||||
pos = codeTable.size();
|
||||
}
|
||||
} else {
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
shiftGlyphIndices(fontId, pos, true);
|
||||
glyphShapeTable.add(pos, shp);
|
||||
if (fontInfoTag != null) {
|
||||
fontInfoTag.addFontCharacter(pos, (int) character);
|
||||
}
|
||||
} else {
|
||||
glyphShapeTable.set(pos, shp);
|
||||
}
|
||||
|
||||
setModified(true);
|
||||
getSwf().clearImageCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(char character) {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int code = (int) character;
|
||||
int pos = -1;
|
||||
List<Integer> codeTable = fontInfoTag.getCodeTable();
|
||||
for (int i = 0; i < codeTable.size(); i++) {
|
||||
if (codeTable.get(i) >= code) {
|
||||
if (codeTable.get(i) == code) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glyphShapeTable.remove(pos);
|
||||
fontInfoTag.removeFontCharacter(pos);
|
||||
|
||||
shiftGlyphIndices(fontId, pos + 1, false);
|
||||
|
||||
setModified(true);
|
||||
getSwf().clearImageCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdvanceValues(Font font) {
|
||||
throw new UnsupportedOperationException("Setting the advance values for DefineFontTag is not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterCount() {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
List<Integer> codeTable = fontInfoTag.getCodeTable();
|
||||
return codeTable.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacters() {
|
||||
ensureFontInfo();
|
||||
if (fontInfoTag != null) {
|
||||
List<Integer> codeTable = fontInfoTag.getCodeTable();
|
||||
StringBuilder ret = new StringBuilder(codeTable.size());
|
||||
for (int i : codeTable) {
|
||||
ret.append((char) i);
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharKerningAdjustment(char c1, char c2) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,259 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
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.SoundStreamHeadTypeTag;
|
||||
import com.jpexs.decompiler.flash.timeline.Timeline;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Reserved;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.decompiler.flash.types.sound.SoundExportFormat;
|
||||
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 3)
|
||||
public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag {
|
||||
|
||||
public static final int ID = 45;
|
||||
|
||||
public static final String NAME = "SoundStreamHead2";
|
||||
|
||||
@Reserved
|
||||
@SWFType(value = BasicType.UB, count = 4)
|
||||
public int reserved;
|
||||
|
||||
@SWFType(value = BasicType.UB, count = 2)
|
||||
public int playBackSoundRate;
|
||||
|
||||
public boolean playBackSoundSize;
|
||||
|
||||
public boolean playBackSoundType;
|
||||
|
||||
@SWFType(value = BasicType.UB, count = 4)
|
||||
public int streamSoundCompression;
|
||||
|
||||
@SWFType(value = BasicType.UB, count = 2)
|
||||
public int streamSoundRate;
|
||||
|
||||
public boolean streamSoundSize;
|
||||
|
||||
public boolean streamSoundType;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int streamSoundSampleCount;
|
||||
|
||||
@SWFType(BasicType.SI16)
|
||||
@Conditional(value = "streamSoundCompression", options = {2})
|
||||
public int latencySeek;
|
||||
|
||||
@Internal
|
||||
private int virtualCharacterId = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public SoundStreamHead2Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public SoundStreamHead2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
reserved = (int) sis.readUB(4, "reserved");
|
||||
playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate");
|
||||
playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1;
|
||||
playBackSoundType = sis.readUB(1, "playBackSoundType") == 1;
|
||||
streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression");
|
||||
streamSoundRate = (int) sis.readUB(2, "streamSoundRate");
|
||||
streamSoundSize = sis.readUB(1, "streamSoundSize") == 1;
|
||||
streamSoundType = sis.readUB(1, "streamSoundType") == 1;
|
||||
streamSoundSampleCount = sis.readUI16("streamSoundSampleCount");
|
||||
if (streamSoundCompression == 2) {
|
||||
latencySeek = sis.readSI16("latencySeek");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUB(4, reserved);
|
||||
sos.writeUB(2, playBackSoundRate);
|
||||
sos.writeUB(1, playBackSoundSize ? 1 : 0);
|
||||
sos.writeUB(1, playBackSoundType ? 1 : 0);
|
||||
sos.writeUB(4, streamSoundCompression);
|
||||
sos.writeUB(2, streamSoundRate);
|
||||
sos.writeUB(1, streamSoundSize ? 1 : 0);
|
||||
sos.writeUB(1, streamSoundType ? 1 : 0);
|
||||
sos.writeUI16(streamSoundSampleCount);
|
||||
if (streamSoundCompression == 2) {
|
||||
sos.writeSI16(latencySeek);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return virtualCharacterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
virtualCharacterId = characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundExportFormat getExportFormat() {
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
|
||||
return SoundExportFormat.MP3;
|
||||
}
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_ADPCM) {
|
||||
return SoundExportFormat.WAV;
|
||||
}
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) {
|
||||
return SoundExportFormat.WAV;
|
||||
}
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) {
|
||||
return SoundExportFormat.WAV;
|
||||
}
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER16KHZ || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER8KHZ) {
|
||||
return SoundExportFormat.WAV;
|
||||
}
|
||||
return SoundExportFormat.FLV;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSoundSampleCount() {
|
||||
return streamSoundSampleCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVirtualCharacterId(int ch) {
|
||||
virtualCharacterId = ch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSoundFormatId() {
|
||||
return streamSoundCompression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSoundRate() {
|
||||
return streamSoundRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getSoundSize() {
|
||||
return streamSoundSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getSoundType() {
|
||||
return streamSoundType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SoundStreamBlockTag> getBlocks() {
|
||||
Timeline timeline = swf.getTimeline();
|
||||
List<SoundStreamBlockTag> ret = timeline.getSoundStreamBlocks(this);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean importSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSound(InputStream is, int newSoundFormat) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ByteArrayRange> getRawSoundData() {
|
||||
List<ByteArrayRange> ret = new ArrayList<>();
|
||||
List<SoundStreamBlockTag> blocks = getBlocks();
|
||||
for (SoundStreamBlockTag block : blocks) {
|
||||
ByteArrayRange data = block.streamSoundData;
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
|
||||
ret.add(data.getSubRange(4, data.getLength() - 4));
|
||||
} else {
|
||||
ret.add(data);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalSoundSampleCount() {
|
||||
return getBlocks().size() * streamSoundSampleCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundFormat getSoundFormat() {
|
||||
final int[] rateMap = {5512, 11025, 22050, 44100};
|
||||
return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterExportFileName() {
|
||||
String exportName = swf.getExportName(getCharacterId());
|
||||
return getCharacterId() + (exportName != null ? "_" + exportName : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTagInfo(TagInfo tagInfo) {
|
||||
super.getTagInfo(tagInfo);
|
||||
SoundFormat soundFormat = getSoundFormat();
|
||||
tagInfo.addInfo("general", "codecName", soundFormat.getFormatName());
|
||||
tagInfo.addInfo("general", "exportFormat", soundFormat.getNativeExportFormat());
|
||||
tagInfo.addInfo("general", "samplingRate", soundFormat.samplingRate);
|
||||
tagInfo.addInfo("general", "stereo", soundFormat.stereo);
|
||||
tagInfo.addInfo("general", "sampleCount", streamSoundSampleCount);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
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.SoundStreamHeadTypeTag;
|
||||
import com.jpexs.decompiler.flash.timeline.Timeline;
|
||||
import com.jpexs.decompiler.flash.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Reserved;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
|
||||
import com.jpexs.decompiler.flash.types.sound.SoundExportFormat;
|
||||
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
@SWFVersion(from = 3)
|
||||
public class SoundStreamHead2Tag extends Tag implements SoundStreamHeadTypeTag {
|
||||
|
||||
public static final int ID = 45;
|
||||
|
||||
public static final String NAME = "SoundStreamHead2";
|
||||
|
||||
@Reserved
|
||||
@SWFType(value = BasicType.UB, count = 4)
|
||||
public int reserved;
|
||||
|
||||
@SWFType(value = BasicType.UB, count = 2)
|
||||
public int playBackSoundRate;
|
||||
|
||||
public boolean playBackSoundSize;
|
||||
|
||||
public boolean playBackSoundType;
|
||||
|
||||
@SWFType(value = BasicType.UB, count = 4)
|
||||
public int streamSoundCompression;
|
||||
|
||||
@SWFType(value = BasicType.UB, count = 2)
|
||||
public int streamSoundRate;
|
||||
|
||||
public boolean streamSoundSize;
|
||||
|
||||
public boolean streamSoundType;
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int streamSoundSampleCount;
|
||||
|
||||
@SWFType(BasicType.SI16)
|
||||
@Conditional(value = "streamSoundCompression", options = {2})
|
||||
public int latencySeek;
|
||||
|
||||
@Internal
|
||||
private int virtualCharacterId = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
*/
|
||||
public SoundStreamHead2Tag(SWF swf) {
|
||||
super(swf, ID, NAME, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param sis
|
||||
* @param data
|
||||
* @throws IOException
|
||||
*/
|
||||
public SoundStreamHead2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
|
||||
super(sis.getSwf(), ID, NAME, data);
|
||||
readData(sis, data, 0, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
|
||||
reserved = (int) sis.readUB(4, "reserved");
|
||||
playBackSoundRate = (int) sis.readUB(2, "playBackSoundRate");
|
||||
playBackSoundSize = sis.readUB(1, "playBackSoundSize") == 1;
|
||||
playBackSoundType = sis.readUB(1, "playBackSoundType") == 1;
|
||||
streamSoundCompression = (int) sis.readUB(4, "streamSoundCompression");
|
||||
streamSoundRate = (int) sis.readUB(2, "streamSoundRate");
|
||||
streamSoundSize = sis.readUB(1, "streamSoundSize") == 1;
|
||||
streamSoundType = sis.readUB(1, "streamSoundType") == 1;
|
||||
streamSoundSampleCount = sis.readUI16("streamSoundSampleCount");
|
||||
if (streamSoundCompression == 2) {
|
||||
latencySeek = sis.readSI16("latencySeek");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data bytes
|
||||
*
|
||||
* @param sos SWF output stream
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
@Override
|
||||
public void getData(SWFOutputStream sos) throws IOException {
|
||||
sos.writeUB(4, reserved);
|
||||
sos.writeUB(2, playBackSoundRate);
|
||||
sos.writeUB(1, playBackSoundSize ? 1 : 0);
|
||||
sos.writeUB(1, playBackSoundType ? 1 : 0);
|
||||
sos.writeUB(4, streamSoundCompression);
|
||||
sos.writeUB(2, streamSoundRate);
|
||||
sos.writeUB(1, streamSoundSize ? 1 : 0);
|
||||
sos.writeUB(1, streamSoundType ? 1 : 0);
|
||||
sos.writeUI16(streamSoundSampleCount);
|
||||
if (streamSoundCompression == 2) {
|
||||
sos.writeSI16(latencySeek);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return virtualCharacterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
virtualCharacterId = characterId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundExportFormat getExportFormat() {
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
|
||||
return SoundExportFormat.MP3;
|
||||
}
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_ADPCM) {
|
||||
return SoundExportFormat.WAV;
|
||||
}
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN) {
|
||||
return SoundExportFormat.WAV;
|
||||
}
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN) {
|
||||
return SoundExportFormat.WAV;
|
||||
}
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER16KHZ || streamSoundCompression == SoundFormat.FORMAT_NELLYMOSER8KHZ) {
|
||||
return SoundExportFormat.WAV;
|
||||
}
|
||||
return SoundExportFormat.FLV;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSoundSampleCount() {
|
||||
return streamSoundSampleCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVirtualCharacterId(int ch) {
|
||||
virtualCharacterId = ch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSoundFormatId() {
|
||||
return streamSoundCompression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSoundRate() {
|
||||
return streamSoundRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getSoundSize() {
|
||||
return streamSoundSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getSoundType() {
|
||||
return streamSoundType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SoundStreamBlockTag> getBlocks() {
|
||||
Timeline timeline = swf.getTimeline();
|
||||
List<SoundStreamBlockTag> ret = timeline.getSoundStreamBlocks(this);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean importSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSound(InputStream is, int newSoundFormat) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ByteArrayRange> getRawSoundData() {
|
||||
List<ByteArrayRange> ret = new ArrayList<>();
|
||||
List<SoundStreamBlockTag> blocks = getBlocks();
|
||||
if (blocks != null) {
|
||||
for (SoundStreamBlockTag block : blocks) {
|
||||
ByteArrayRange data = block.streamSoundData;
|
||||
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
|
||||
ret.add(data.getSubRange(4, data.getLength() - 4));
|
||||
} else {
|
||||
ret.add(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalSoundSampleCount() {
|
||||
return getBlocks().size() * streamSoundSampleCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundFormat getSoundFormat() {
|
||||
final int[] rateMap = {5512, 11025, 22050, 44100};
|
||||
return new SoundFormat(getSoundFormatId(), rateMap[getSoundRate()], getSoundType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterExportFileName() {
|
||||
String exportName = swf.getExportName(getCharacterId());
|
||||
return getCharacterId() + (exportName != null ? "_" + exportName : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTagInfo(TagInfo tagInfo) {
|
||||
super.getTagInfo(tagInfo);
|
||||
SoundFormat soundFormat = getSoundFormat();
|
||||
tagInfo.addInfo("general", "codecName", soundFormat.getFormatName());
|
||||
tagInfo.addInfo("general", "exportFormat", soundFormat.getNativeExportFormat());
|
||||
tagInfo.addInfo("general", "samplingRate", soundFormat.samplingRate);
|
||||
tagInfo.addInfo("general", "stereo", soundFormat.stereo);
|
||||
tagInfo.addInfo("general", "sampleCount", streamSoundSampleCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
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.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class FontInfoTag extends Tag implements CharacterIdTag {
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int fontID;
|
||||
|
||||
public FontInfoTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract List<Integer> getCodeTable();
|
||||
|
||||
public abstract void addCharacter(int index, int character);
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return fontID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.fontID = characterId;
|
||||
}
|
||||
|
||||
public abstract String getFontName();
|
||||
|
||||
public abstract boolean getFontFlagsBold();
|
||||
|
||||
public abstract void setFontFlagsBold(boolean value);
|
||||
|
||||
public abstract boolean getFontFlagsItalic();
|
||||
|
||||
public abstract void setFontFlagsItalic(boolean value);
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
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.types.BasicType;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class FontInfoTag extends Tag implements CharacterIdTag {
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int fontID;
|
||||
|
||||
public FontInfoTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract List<Integer> getCodeTable();
|
||||
|
||||
public abstract void addFontCharacter(int index, int character);
|
||||
|
||||
public abstract void removeFontCharacter(int index);
|
||||
|
||||
@Override
|
||||
public int getCharacterId() {
|
||||
return fontID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterId(int characterId) {
|
||||
this.fontID = characterId;
|
||||
}
|
||||
|
||||
public abstract String getFontName();
|
||||
|
||||
public abstract boolean getFontFlagsBold();
|
||||
|
||||
public abstract void setFontFlagsBold(boolean value);
|
||||
|
||||
public abstract boolean getFontFlagsItalic();
|
||||
|
||||
public abstract void setFontFlagsItalic(boolean value);
|
||||
}
|
||||
|
||||
@@ -1,411 +1,417 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.helpers.FontHelper;
|
||||
import com.jpexs.decompiler.flash.tags.DefineFontNameTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
|
||||
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 com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphMetrics;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.Area;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class FontTag extends DrawableTag implements AloneTag {
|
||||
|
||||
public static final int PREVIEWSIZE = 500;
|
||||
|
||||
public FontTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract List<SHAPE> getGlyphShapeTable();
|
||||
|
||||
public abstract void addCharacter(char character, Font font);
|
||||
|
||||
public abstract void setAdvanceValues(Font font);
|
||||
|
||||
public abstract char glyphToChar(int glyphIndex);
|
||||
|
||||
public abstract int charToGlyph(char c);
|
||||
|
||||
public abstract double getGlyphAdvance(int glyphIndex);
|
||||
|
||||
public abstract int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex);
|
||||
|
||||
public abstract int getCharKerningAdjustment(char c1, char c2);
|
||||
|
||||
public abstract int getGlyphWidth(int glyphIndex);
|
||||
|
||||
public abstract String getFontNameIntag();
|
||||
|
||||
public abstract boolean isSmall();
|
||||
|
||||
public abstract boolean isBold();
|
||||
|
||||
public abstract boolean isItalic();
|
||||
|
||||
public abstract boolean isSmallEditable();
|
||||
|
||||
public abstract boolean isBoldEditable();
|
||||
|
||||
public abstract boolean isItalicEditable();
|
||||
|
||||
public abstract void setSmall(boolean value);
|
||||
|
||||
public abstract void setBold(boolean value);
|
||||
|
||||
public abstract void setItalic(boolean value);
|
||||
|
||||
public abstract double getDivider();
|
||||
|
||||
public abstract int getAscent();
|
||||
|
||||
public abstract int getDescent();
|
||||
|
||||
public abstract int getLeading();
|
||||
|
||||
public String getFontName() {
|
||||
DefineFontNameTag fontNameTag = getFontNameTag();
|
||||
if (fontNameTag == null) {
|
||||
return getFontNameIntag();
|
||||
}
|
||||
return fontNameTag.fontName;
|
||||
}
|
||||
|
||||
public String getFontCopyright() {
|
||||
DefineFontNameTag fontNameTag = getFontNameTag();
|
||||
if (fontNameTag == null) {
|
||||
return "";
|
||||
}
|
||||
return fontNameTag.fontCopyright;
|
||||
}
|
||||
|
||||
public static Map<String, Map<String, Font>> installedFontsByFamily;
|
||||
|
||||
public static Map<String, Font> installedFontsByName;
|
||||
|
||||
public static String defaultFontName;
|
||||
|
||||
static {
|
||||
reload();
|
||||
}
|
||||
|
||||
public int getFontId() {
|
||||
return getCharacterId();
|
||||
}
|
||||
|
||||
public boolean hasLayout() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsChar(char character) {
|
||||
return charToGlyph(character) > -1;
|
||||
}
|
||||
|
||||
public int getFontStyle() {
|
||||
int fontStyle = 0;
|
||||
if (isBold()) {
|
||||
fontStyle |= Font.BOLD;
|
||||
}
|
||||
if (isItalic()) {
|
||||
fontStyle |= Font.ITALIC;
|
||||
}
|
||||
return fontStyle;
|
||||
}
|
||||
|
||||
public abstract int getCharacterCount();
|
||||
|
||||
public abstract String getCharacters();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
String nameAppend = "";
|
||||
if (exportName != null) {
|
||||
nameAppend = ": " + exportName;
|
||||
}
|
||||
if (className != null) {
|
||||
nameAppend = ": " + className;
|
||||
}
|
||||
String fontName = getFontNameIntag();
|
||||
if (fontName != null) {
|
||||
nameAppend = ": " + fontName;
|
||||
}
|
||||
return tagName + " (" + getCharacterId() + nameAppend + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
String result = super.getExportFileName();
|
||||
String fontName = getFontNameIntag();
|
||||
if (fontName != null) {
|
||||
fontName = fontName.replace(" ", "_");
|
||||
}
|
||||
return result + (fontName != null ? "_" + fontName : "");
|
||||
}
|
||||
|
||||
public String getSystemFontName() {
|
||||
int fontId = getFontId();
|
||||
String selectedFont = swf.sourceFontNamesMap.get(fontId);
|
||||
if (selectedFont == null) {
|
||||
SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(swf.getShortFileName());
|
||||
String key = fontId + "_" + getFontNameIntag();
|
||||
if (swfConf != null) {
|
||||
selectedFont = swfConf.fontPairingMap.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedFont == null) {
|
||||
selectedFont = Configuration.getFontToNameMap().get(getFontNameIntag());
|
||||
}
|
||||
|
||||
if (selectedFont != null && FontTag.installedFontsByName.containsKey(selectedFont)) {
|
||||
return selectedFont;
|
||||
}
|
||||
|
||||
// findInstalledFontName always returns an available font name
|
||||
return FontTag.findInstalledFontName(getFontName());
|
||||
}
|
||||
|
||||
public Font getSystemFont() {
|
||||
return FontTag.installedFontsByName.get(getSystemFontName());
|
||||
}
|
||||
|
||||
protected void shiftGlyphIndices(int fontId, int startIndex) {
|
||||
for (Tag t : swf.getTags()) {
|
||||
List<TEXTRECORD> textRecords = null;
|
||||
if (t instanceof StaticTextTag) {
|
||||
textRecords = ((StaticTextTag) t).textRecords;
|
||||
}
|
||||
|
||||
if (textRecords != null) {
|
||||
int curFontId = 0;
|
||||
for (TEXTRECORD tr : textRecords) {
|
||||
if (tr.styleFlagsHasFont) {
|
||||
curFontId = tr.fontId;
|
||||
}
|
||||
|
||||
if (curFontId != fontId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (GLYPHENTRY en : tr.glyphEntries) {
|
||||
if (en == null) { //Currently edited
|
||||
continue;
|
||||
}
|
||||
if (en.glyphIndex >= startIndex) {
|
||||
en.glyphIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
t.setModified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float getSystemFontAdvance(String fontName, int fontStyle, int fontSize, Character character, Character nextCharacter) {
|
||||
return getSystemFontAdvance(new Font(fontName, fontStyle, fontSize), character, nextCharacter);
|
||||
}
|
||||
|
||||
public static float getSystemFontAdvance(Font aFont, Character character, Character nextCharacter) {
|
||||
String chars = "" + character + (nextCharacter == null ? "" : nextCharacter);
|
||||
GlyphVector gv = aFont.layoutGlyphVector(new FontRenderContext(aFont.getTransform(), true, true), chars.toCharArray(), 0, chars.length(), Font.LAYOUT_LEFT_TO_RIGHT);
|
||||
GlyphMetrics gm = gv.getGlyphMetrics(0);
|
||||
return gm.getAdvanceX();
|
||||
}
|
||||
|
||||
public static void reload() {
|
||||
installedFontsByFamily = FontHelper.getInstalledFonts();
|
||||
installedFontsByName = new HashMap<>();
|
||||
|
||||
for (String fam : installedFontsByFamily.keySet()) {
|
||||
for (String nam : installedFontsByFamily.get(fam).keySet()) {
|
||||
installedFontsByName.put(nam, installedFontsByFamily.get(fam).get(nam));
|
||||
}
|
||||
}
|
||||
|
||||
if (installedFontsByFamily.containsKey("Times New Roman")) {
|
||||
defaultFontName = "Times New Roman";
|
||||
} else if (installedFontsByFamily.containsKey("Arial")) {
|
||||
defaultFontName = "Arial";
|
||||
} else {
|
||||
defaultFontName = installedFontsByFamily.keySet().iterator().next();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFontNameWithFallback(String fontName) {
|
||||
if (installedFontsByFamily.containsKey(fontName)) {
|
||||
return fontName;
|
||||
}
|
||||
if (installedFontsByFamily.containsKey("Times New Roman")) {
|
||||
return "Times New Roman";
|
||||
}
|
||||
if (installedFontsByFamily.containsKey("Arial")) {
|
||||
return "Arial";
|
||||
}
|
||||
|
||||
//First font
|
||||
return installedFontsByFamily.keySet().iterator().next();
|
||||
}
|
||||
|
||||
public static String isFontFamilyInstalled(String fontFamily) {
|
||||
if (installedFontsByFamily.containsKey(fontFamily)) {
|
||||
return fontFamily;
|
||||
}
|
||||
if (fontFamily.contains("_")) {
|
||||
String beforeUnderscore = fontFamily.substring(0, fontFamily.indexOf('_'));
|
||||
if (installedFontsByFamily.containsKey(beforeUnderscore)) {
|
||||
return beforeUnderscore;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String findInstalledFontName(String fontName) {
|
||||
if (installedFontsByName.containsKey(fontName)) {
|
||||
return fontName;
|
||||
}
|
||||
if (fontName != null && fontName.contains("_")) {
|
||||
String beforeUnderscore = fontName.substring(0, fontName.indexOf('_'));
|
||||
if (installedFontsByName.containsKey(beforeUnderscore)) {
|
||||
return beforeUnderscore;
|
||||
}
|
||||
}
|
||||
return defaultFontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedParameters() {
|
||||
return PARAMETER_FRAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
|
||||
RECT r = getRect();
|
||||
return new Area(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
|
||||
SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, frame, Color.black, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
|
||||
List<SHAPE> shapes = getGlyphShapeTable();
|
||||
result.append("\tdefaultFill = textColor;\r\n");
|
||||
result.append("\tswitch(ch){\r\n");
|
||||
for (int i = 0; i < shapes.size(); i++) {
|
||||
char c = glyphToChar(i);
|
||||
String cs = "" + c;
|
||||
cs = cs.replace("\\", "\\\\").replace("\"", "\\\"");
|
||||
result.append("\t\tcase \"").append(cs).append("\":\r\n");
|
||||
CanvasShapeExporter exporter = new CanvasShapeExporter(null, unitDivisor, swf, shapes.get(i), null, 0, 0);
|
||||
exporter.export();
|
||||
result.append("\t\t").append(exporter.getShapeData().replaceAll("\r\n", "\r\n\t\t"));
|
||||
result.append("\tbreak;\r\n");
|
||||
}
|
||||
result.append("\t}\r\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
int frameCount = (getGlyphShapeTable().size() - 1) / SHAPERECORD.MAX_CHARACTERS_IN_FONT_PREVIEW + 1;
|
||||
if (frameCount < 1) {
|
||||
frameCount = 1;
|
||||
}
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return getRect(null); // parameter not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return new RECT(0, (int) (PREVIEWSIZE * SWF.unitDivisor), 0, (int) (PREVIEWSIZE * SWF.unitDivisor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterExportFileName() {
|
||||
return super.getCharacterExportFileName() + "_" + getFontNameIntag();
|
||||
}
|
||||
|
||||
public DefineFontNameTag getFontNameTag() {
|
||||
for (Tag t : swf.getTags()) {
|
||||
if (t instanceof DefineFontNameTag) {
|
||||
DefineFontNameTag dfn = (DefineFontNameTag) t;
|
||||
if (dfn.fontId == getFontId()) {
|
||||
return dfn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getCopyright() {
|
||||
DefineFontNameTag dfn = getFontNameTag();
|
||||
if (dfn == null) {
|
||||
return null;
|
||||
}
|
||||
return dfn.fontCopyright;
|
||||
}
|
||||
|
||||
public RECT getGlyphBounds(int glyphIndex) {
|
||||
return getGlyphShapeTable().get(glyphIndex).getBounds();
|
||||
}
|
||||
|
||||
public FontTag toClassicFont() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
|
||||
import com.jpexs.decompiler.flash.helpers.FontHelper;
|
||||
import com.jpexs.decompiler.flash.tags.DefineFontNameTag;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
|
||||
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 com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphMetrics;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.Area;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public abstract class FontTag extends DrawableTag implements AloneTag {
|
||||
|
||||
public static final int PREVIEWSIZE = 500;
|
||||
|
||||
public FontTag(SWF swf, int id, String name, ByteArrayRange data) {
|
||||
super(swf, id, name, data);
|
||||
}
|
||||
|
||||
public abstract List<SHAPE> getGlyphShapeTable();
|
||||
|
||||
public abstract void addCharacter(char character, Font font);
|
||||
|
||||
public abstract boolean removeCharacter(char character);
|
||||
|
||||
public abstract void setAdvanceValues(Font font);
|
||||
|
||||
public abstract char glyphToChar(int glyphIndex);
|
||||
|
||||
public abstract int charToGlyph(char c);
|
||||
|
||||
public abstract double getGlyphAdvance(int glyphIndex);
|
||||
|
||||
public abstract int getGlyphKerningAdjustment(int glyphIndex, int nextGlyphIndex);
|
||||
|
||||
public abstract int getCharKerningAdjustment(char c1, char c2);
|
||||
|
||||
public abstract int getGlyphWidth(int glyphIndex);
|
||||
|
||||
public abstract String getFontNameIntag();
|
||||
|
||||
public abstract boolean isSmall();
|
||||
|
||||
public abstract boolean isBold();
|
||||
|
||||
public abstract boolean isItalic();
|
||||
|
||||
public abstract boolean isSmallEditable();
|
||||
|
||||
public abstract boolean isBoldEditable();
|
||||
|
||||
public abstract boolean isItalicEditable();
|
||||
|
||||
public abstract void setSmall(boolean value);
|
||||
|
||||
public abstract void setBold(boolean value);
|
||||
|
||||
public abstract void setItalic(boolean value);
|
||||
|
||||
public abstract double getDivider();
|
||||
|
||||
public abstract int getAscent();
|
||||
|
||||
public abstract int getDescent();
|
||||
|
||||
public abstract int getLeading();
|
||||
|
||||
public String getFontName() {
|
||||
DefineFontNameTag fontNameTag = getFontNameTag();
|
||||
if (fontNameTag == null) {
|
||||
return getFontNameIntag();
|
||||
}
|
||||
return fontNameTag.fontName;
|
||||
}
|
||||
|
||||
public String getFontCopyright() {
|
||||
DefineFontNameTag fontNameTag = getFontNameTag();
|
||||
if (fontNameTag == null) {
|
||||
return "";
|
||||
}
|
||||
return fontNameTag.fontCopyright;
|
||||
}
|
||||
|
||||
public static Map<String, Map<String, Font>> installedFontsByFamily;
|
||||
|
||||
public static Map<String, Font> installedFontsByName;
|
||||
|
||||
public static String defaultFontName;
|
||||
|
||||
static {
|
||||
reload();
|
||||
}
|
||||
|
||||
public int getFontId() {
|
||||
return getCharacterId();
|
||||
}
|
||||
|
||||
public boolean hasLayout() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsChar(char character) {
|
||||
return charToGlyph(character) > -1;
|
||||
}
|
||||
|
||||
public int getFontStyle() {
|
||||
int fontStyle = 0;
|
||||
if (isBold()) {
|
||||
fontStyle |= Font.BOLD;
|
||||
}
|
||||
if (isItalic()) {
|
||||
fontStyle |= Font.ITALIC;
|
||||
}
|
||||
return fontStyle;
|
||||
}
|
||||
|
||||
public abstract int getCharacterCount();
|
||||
|
||||
public abstract String getCharacters();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
String nameAppend = "";
|
||||
if (exportName != null) {
|
||||
nameAppend = ": " + exportName;
|
||||
}
|
||||
if (className != null) {
|
||||
nameAppend = ": " + className;
|
||||
}
|
||||
String fontName = getFontNameIntag();
|
||||
if (fontName != null) {
|
||||
nameAppend = ": " + fontName;
|
||||
}
|
||||
return tagName + " (" + getCharacterId() + nameAppend + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getExportFileName() {
|
||||
String result = super.getExportFileName();
|
||||
String fontName = getFontNameIntag();
|
||||
if (fontName != null) {
|
||||
fontName = fontName.replace(" ", "_");
|
||||
}
|
||||
return result + (fontName != null ? "_" + fontName : "");
|
||||
}
|
||||
|
||||
public String getSystemFontName() {
|
||||
int fontId = getFontId();
|
||||
String selectedFont = swf.sourceFontNamesMap.get(fontId);
|
||||
if (selectedFont == null) {
|
||||
SwfSpecificConfiguration swfConf = Configuration.getSwfSpecificConfiguration(swf.getShortFileName());
|
||||
String key = fontId + "_" + getFontNameIntag();
|
||||
if (swfConf != null) {
|
||||
selectedFont = swfConf.fontPairingMap.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedFont == null) {
|
||||
selectedFont = Configuration.getFontToNameMap().get(getFontNameIntag());
|
||||
}
|
||||
|
||||
if (selectedFont != null && FontTag.installedFontsByName.containsKey(selectedFont)) {
|
||||
return selectedFont;
|
||||
}
|
||||
|
||||
// findInstalledFontName always returns an available font name
|
||||
return FontTag.findInstalledFontName(getFontName());
|
||||
}
|
||||
|
||||
public Font getSystemFont() {
|
||||
return FontTag.installedFontsByName.get(getSystemFontName());
|
||||
}
|
||||
|
||||
protected void shiftGlyphIndices(int fontId, int startIndex, boolean increment) {
|
||||
for (Tag t : swf.getTags()) {
|
||||
List<TEXTRECORD> textRecords = null;
|
||||
if (t instanceof StaticTextTag) {
|
||||
textRecords = ((StaticTextTag) t).textRecords;
|
||||
}
|
||||
|
||||
if (textRecords != null) {
|
||||
int curFontId = 0;
|
||||
for (TEXTRECORD tr : textRecords) {
|
||||
if (tr.styleFlagsHasFont) {
|
||||
curFontId = tr.fontId;
|
||||
}
|
||||
|
||||
if (curFontId != fontId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (GLYPHENTRY en : tr.glyphEntries) {
|
||||
if (en == null) { //Currently edited
|
||||
continue;
|
||||
}
|
||||
if (en.glyphIndex >= startIndex) {
|
||||
if (increment) {
|
||||
en.glyphIndex++;
|
||||
} else {
|
||||
en.glyphIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.setModified(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float getSystemFontAdvance(String fontName, int fontStyle, int fontSize, Character character, Character nextCharacter) {
|
||||
return getSystemFontAdvance(new Font(fontName, fontStyle, fontSize), character, nextCharacter);
|
||||
}
|
||||
|
||||
public static float getSystemFontAdvance(Font aFont, Character character, Character nextCharacter) {
|
||||
String chars = "" + character + (nextCharacter == null ? "" : nextCharacter);
|
||||
GlyphVector gv = aFont.layoutGlyphVector(new FontRenderContext(aFont.getTransform(), true, true), chars.toCharArray(), 0, chars.length(), Font.LAYOUT_LEFT_TO_RIGHT);
|
||||
GlyphMetrics gm = gv.getGlyphMetrics(0);
|
||||
return gm.getAdvanceX();
|
||||
}
|
||||
|
||||
public static void reload() {
|
||||
installedFontsByFamily = FontHelper.getInstalledFonts();
|
||||
installedFontsByName = new HashMap<>();
|
||||
|
||||
for (String fam : installedFontsByFamily.keySet()) {
|
||||
for (String nam : installedFontsByFamily.get(fam).keySet()) {
|
||||
installedFontsByName.put(nam, installedFontsByFamily.get(fam).get(nam));
|
||||
}
|
||||
}
|
||||
|
||||
if (installedFontsByFamily.containsKey("Times New Roman")) {
|
||||
defaultFontName = "Times New Roman";
|
||||
} else if (installedFontsByFamily.containsKey("Arial")) {
|
||||
defaultFontName = "Arial";
|
||||
} else {
|
||||
defaultFontName = installedFontsByFamily.keySet().iterator().next();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFontNameWithFallback(String fontName) {
|
||||
if (installedFontsByFamily.containsKey(fontName)) {
|
||||
return fontName;
|
||||
}
|
||||
if (installedFontsByFamily.containsKey("Times New Roman")) {
|
||||
return "Times New Roman";
|
||||
}
|
||||
if (installedFontsByFamily.containsKey("Arial")) {
|
||||
return "Arial";
|
||||
}
|
||||
|
||||
//First font
|
||||
return installedFontsByFamily.keySet().iterator().next();
|
||||
}
|
||||
|
||||
public static String isFontFamilyInstalled(String fontFamily) {
|
||||
if (installedFontsByFamily.containsKey(fontFamily)) {
|
||||
return fontFamily;
|
||||
}
|
||||
if (fontFamily.contains("_")) {
|
||||
String beforeUnderscore = fontFamily.substring(0, fontFamily.indexOf('_'));
|
||||
if (installedFontsByFamily.containsKey(beforeUnderscore)) {
|
||||
return beforeUnderscore;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String findInstalledFontName(String fontName) {
|
||||
if (installedFontsByName.containsKey(fontName)) {
|
||||
return fontName;
|
||||
}
|
||||
if (fontName != null && fontName.contains("_")) {
|
||||
String beforeUnderscore = fontName.substring(0, fontName.indexOf('_'));
|
||||
if (installedFontsByName.containsKey(beforeUnderscore)) {
|
||||
return beforeUnderscore;
|
||||
}
|
||||
}
|
||||
return defaultFontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsedParameters() {
|
||||
return PARAMETER_FRAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) {
|
||||
RECT r = getRect();
|
||||
return new Area(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) {
|
||||
SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, frame, Color.black, colorTransform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toHtmlCanvas(StringBuilder result, double unitDivisor) {
|
||||
List<SHAPE> shapes = getGlyphShapeTable();
|
||||
result.append("\tdefaultFill = textColor;\r\n");
|
||||
result.append("\tswitch(ch){\r\n");
|
||||
for (int i = 0; i < shapes.size(); i++) {
|
||||
char c = glyphToChar(i);
|
||||
String cs = "" + c;
|
||||
cs = cs.replace("\\", "\\\\").replace("\"", "\\\"");
|
||||
result.append("\t\tcase \"").append(cs).append("\":\r\n");
|
||||
CanvasShapeExporter exporter = new CanvasShapeExporter(null, unitDivisor, swf, shapes.get(i), null, 0, 0);
|
||||
exporter.export();
|
||||
result.append("\t\t").append(exporter.getShapeData().replaceAll("\r\n", "\r\n\t\t"));
|
||||
result.append("\tbreak;\r\n");
|
||||
}
|
||||
result.append("\t}\r\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumFrames() {
|
||||
int frameCount = (getGlyphShapeTable().size() - 1) / SHAPERECORD.MAX_CHARACTERS_IN_FONT_PREVIEW + 1;
|
||||
if (frameCount < 1) {
|
||||
frameCount = 1;
|
||||
}
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFrame() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect() {
|
||||
return getRect(null); // parameter not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public RECT getRect(Set<BoundedTag> added) {
|
||||
return new RECT(0, (int) (PREVIEWSIZE * SWF.unitDivisor), 0, (int) (PREVIEWSIZE * SWF.unitDivisor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterExportFileName() {
|
||||
return super.getCharacterExportFileName() + "_" + getFontNameIntag();
|
||||
}
|
||||
|
||||
public DefineFontNameTag getFontNameTag() {
|
||||
for (Tag t : swf.getTags()) {
|
||||
if (t instanceof DefineFontNameTag) {
|
||||
DefineFontNameTag dfn = (DefineFontNameTag) t;
|
||||
if (dfn.fontId == getFontId()) {
|
||||
return dfn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getCopyright() {
|
||||
DefineFontNameTag dfn = getFontNameTag();
|
||||
if (dfn == null) {
|
||||
return null;
|
||||
}
|
||||
return dfn.fontCopyright;
|
||||
}
|
||||
|
||||
public RECT getGlyphBounds(int glyphIndex) {
|
||||
return getGlyphShapeTable().get(glyphIndex).getBounds();
|
||||
}
|
||||
|
||||
public FontTag toClassicFont() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ public final class DefineCompactedFont extends FontTag {
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
shiftGlyphIndices(fontId, pos);
|
||||
shiftGlyphIndices(fontId, pos, true);
|
||||
}
|
||||
|
||||
Font fnt = cfont.deriveFont(fontStyle, Math.round(font.nominalSize * d));
|
||||
@@ -198,6 +198,37 @@ public final class DefineCompactedFont extends FontTag {
|
||||
getSwf().clearImageCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeCharacter(char character) {
|
||||
FontType font = fonts.get(0);
|
||||
|
||||
int code = (int) character;
|
||||
int pos = -1;
|
||||
for (int i = 0; i < font.glyphInfo.size(); i++) {
|
||||
if (font.glyphInfo.get(i).glyphCode >= code) {
|
||||
if (font.glyphInfo.get(i).glyphCode == code) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
font.glyphInfo.remove(pos);
|
||||
font.glyphs.remove(pos);
|
||||
shapeCache.remove(pos);
|
||||
shiftGlyphIndices(fontId, pos + 1, false);
|
||||
|
||||
setModified(true);
|
||||
getSwf().clearImageCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdvanceValues(Font font) {
|
||||
throw new UnsupportedOperationException("Setting the advance values for DefineCompactedFont is not supported.");
|
||||
|
||||
Reference in New Issue
Block a user