justify text

This commit is contained in:
2015-02-20 21:13:11 +01:00
parent c0e78c823b
commit 27551761e6
8 changed files with 136 additions and 90 deletions
@@ -318,6 +318,19 @@ public final class SWF implements SWFContainerItem, Timelined {
return getCharacters().get(characterId);
}
public FontTag getFont(int fontId) {
CharacterTag characterTag = getCharacters().get(fontId);
if (characterTag instanceof FontTag) {
return (FontTag) characterTag;
}
if (characterTag != null) {
logger.log(Level.SEVERE, "CharacterTag should be a FontTag. characterId: {0}", fontId);
}
return null;
}
public List<ABCContainerTag> getAbcList() {
if (abcList == null) {
synchronized (this) {
@@ -1550,7 +1563,6 @@ public final class SWF implements SWFContainerItem, Timelined {
fos.write(Utf8Helper.getBytes(((FontTag) ch).toHtmlCanvas(1)));
fos.write(Utf8Helper.getBytes("}\r\n\r\n"));
} else {
if (ch instanceof ImageTag) {
ImageTag image = (ImageTag) ch;
String format = image.getImageFormat();
@@ -2248,8 +2260,8 @@ public final class SWF implements SWFContainerItem, Timelined {
if (!layer.isVisible) {
continue;
}
CharacterTag character = timeline.swf.getCharacter(layer.characterId);
CharacterTag character = timeline.swf.getCharacter(layer.characterId);
if (colorTransform == null) {
colorTransform = new ColorTransform();
}
@@ -2398,6 +2410,7 @@ public final class SWF implements SWFContainerItem, Timelined {
if (!layer.isVisible) {
continue;
}
CharacterTag character = timeline.swf.getCharacter(layer.characterId);
Matrix mat = new Matrix(layer.matrix);
mat = mat.preConcatenate(transformation);
@@ -435,11 +435,12 @@ public class FrameExporter {
if (!layer.isVisible) {
continue;
}
CharacterTag character = timeline.swf.getCharacter(layer.characterId);
CharacterTag character = timeline.swf.getCharacter(layer.characterId);
if (colorTransform == null) {
colorTransform = new ColorTransform();
}
Matrix placeMatrix = new Matrix(layer.matrix);
placeMatrix.scaleX /= unitDivisor;
placeMatrix.scaleY /= unitDivisor;
@@ -23,7 +23,6 @@ import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
import com.jpexs.decompiler.flash.tags.base.RenderContext;
@@ -503,14 +502,10 @@ public class DefineEditTextTag extends TextTag {
try {
fontId = Integer.parseInt(paramValue);
CharacterTag characterTag = swf.getCharacter(fontId);
if (characterTag == null) {
FontTag ft = swf.getFont(fontId);
if (ft == null) {
throw new TextParseException("Font not found.", lexer.yyline());
}
if (!(characterTag instanceof FontTag)) {
throw new TextParseException("Character tag is not a Font tag. CharacterID: " + fontId, lexer.yyline());
}
} catch (NumberFormatException ne) {
throw new TextParseException("Invalid font value. Number expected. Found: " + paramValue, lexer.yyline());
}
@@ -641,6 +636,7 @@ public class DefineEditTextTag extends TextTag {
hasFontClass = true;
}
this.autoSize = autoSize;
this.align = align;
if ((leftMargin > -1)
|| (rightMargin > -1)
|| (indent > -1)
@@ -24,7 +24,6 @@ import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
import com.jpexs.decompiler.flash.tags.base.RenderContext;
@@ -220,16 +219,12 @@ public class DefineText2Tag extends TextTag {
try {
fontId = Integer.parseInt(paramValue);
CharacterTag characterTag = swf.getCharacter(fontId);
if (characterTag == null) {
FontTag ft = swf.getFont(fontId);
if (ft == null) {
throw new TextParseException("Font not found.", lexer.yyline());
}
if (!(characterTag instanceof FontTag)) {
throw new TextParseException("Character tag is not a Font tag. CharacterID: " + fontId, lexer.yyline());
}
font = (FontTag) characterTag;
font = (FontTag) ft;
fontName = font.getSystemFontName();
} catch (NumberFormatException nfe) {
throw new TextParseException("Invalid font id - number expected. Found: " + paramValue, lexer.yyline());
@@ -447,7 +442,7 @@ public class DefineText2Tag extends TextTag {
@Override
public boolean alignText(TextAlign textAlign) {
alignText(textRecords, textAlign);
alignText(swf, textRecords, textAlign);
setModified(true);
return true;
}
@@ -25,7 +25,6 @@ import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
import com.jpexs.decompiler.flash.tags.base.RenderContext;
@@ -226,16 +225,12 @@ public class DefineTextTag extends TextTag {
try {
fontId = Integer.parseInt(paramValue);
CharacterTag characterTag = swf.getCharacter(fontId);
if (characterTag == null) {
FontTag ft = swf.getFont(fontId);
if (ft == null) {
throw new TextParseException("Font not found.", lexer.yyline());
}
if (!(characterTag instanceof FontTag)) {
throw new TextParseException("Character tag is not a Font tag. CharacterID: " + fontId, lexer.yyline());
}
font = (FontTag) characterTag;
font = (FontTag) ft;
fontName = font.getSystemFontName();
} catch (NumberFormatException nfe) {
throw new TextParseException("Invalid font id - number expected. Found: " + paramValue, lexer.yyline());
@@ -455,7 +450,7 @@ public class DefineTextTag extends TextTag {
@Override
public boolean alignText(TextAlign textAlign) {
alignText(textRecords, textAlign);
alignText(swf, textRecords, textAlign);
setModified(true);
return true;
}
@@ -27,7 +27,6 @@ import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
import com.jpexs.decompiler.flash.importers.TextImportResizeTextBoundsMode;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.text.TextAlign;
import com.jpexs.decompiler.flash.tags.text.TextParseException;
import com.jpexs.decompiler.flash.types.ColorTransform;
@@ -117,9 +116,15 @@ public abstract class TextTag extends CharacterTag implements DrawableTag {
}
}
public static void alignText(List<TEXTRECORD> textRecords, TextAlign textAlign) {
public static void alignText(SWF swf, List<TEXTRECORD> textRecords, TextAlign textAlign) {
int xMin = Integer.MAX_VALUE;
int maxWidth = 0;
for (TEXTRECORD tr : textRecords) {
int xOffset = tr.styleFlagsHasXOffset ? tr.xOffset : 0;
if (xOffset < xMin) {
xMin = xOffset;
}
int width = tr.getTotalAdvance();
if (width > maxWidth) {
@@ -127,30 +132,98 @@ public abstract class TextTag extends CharacterTag implements DrawableTag {
}
}
FontTag font = null;
for (TEXTRECORD tr : textRecords) {
if (tr.styleFlagsHasFont) {
FontTag font2 = swf.getFont(tr.fontId);
if (font2 != null) {
font = font2;
}
}
/*if (tr.justified) {
// Text record was aligned in Justify mode earier
// restore the advances
for (GLYPHENTRY ge : tr.glyphEntries) {
char ch = font.glyphToChar(ge.glyphIndex);
if (Character.isWhitespace(ch)) {
ge.glyphAdvance = ge.originalAdvance;
}
}
}*/
int width = tr.getTotalAdvance();
switch (textAlign) {
case LEFT:
tr.xOffset = 0;
tr.xOffset = xMin;
tr.styleFlagsHasXOffset = true;
break;
case CENTER:
tr.xOffset = (maxWidth - width) / 2;
tr.xOffset = xMin + (maxWidth - width) / 2;
tr.styleFlagsHasXOffset = true;
break;
case RIGHT:
tr.xOffset = maxWidth - width;
tr.xOffset = xMin + maxWidth - width;
tr.styleFlagsHasXOffset = true;
break;
case JUSTIFY:
tr.xOffset = 0;
tr.xOffset = xMin;
tr.styleFlagsHasXOffset = true;
if (font != null) {
int diff = maxWidth - width;
if (diff > 0) {
int spaces = 0;
int spaces2 = 0;
int state = 0;
List<GLYPHENTRY> glyphEntries = new ArrayList<>();
List<GLYPHENTRY> glyphEntries2 = new ArrayList<>();
for (GLYPHENTRY ge : tr.glyphEntries) {
char ch = font.glyphToChar(ge.glyphIndex);
boolean whitespace = Character.isWhitespace(ch);
switch (state) {
case 0:
if (!whitespace) {
state = 1;
}
break;
case 1:
if (whitespace) {
spaces2++;
glyphEntries2.add(ge);
} else {
spaces += spaces2;
spaces2 = 0;
glyphEntries.addAll(glyphEntries2);
glyphEntries2.clear();
}
break;
}
}
if (spaces > 0) {
int fix = diff / spaces;
int remaining = diff - fix * spaces;
for (GLYPHENTRY ge : glyphEntries) {
int diff2 = fix;
if (remaining-- > 0) {
diff2++;
}
//ge.originalAdvance = ge.glyphAdvance;
ge.glyphAdvance += diff2;
}
//tr.justified = true;
}
}
}
break;
}
}
}
public static Map<String, Object> getTextRecordsAttributes(List<TEXTRECORD> list, List<Tag> tags) {
public static Map<String, Object> getTextRecordsAttributes(List<TEXTRECORD> list, SWF swf) {
Map<String, Object> att = new HashMap<>();
RECT textBounds = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
FontTag font = null;
@@ -176,13 +249,9 @@ public abstract class TextTag extends CharacterTag implements DrawableTag {
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;
}
}
FontTag font2 = swf.getFont(rec.fontId);
if (font2 != null) {
font = font2;
}
textHeight = rec.textHeight;
glyphs = font.getGlyphShapeTable();
@@ -332,9 +401,9 @@ public abstract class TextTag extends CharacterTag implements DrawableTag {
}
}
if (rec.styleFlagsHasFont) {
CharacterTag character = swf.getCharacter(rec.fontId);
if (character instanceof FontTag) {
font = (FontTag) character;
FontTag font2 = swf.getFont(rec.fontId);
if (font2 != null) {
font = font2;
}
glyphs = font == null ? null : font.getGlyphShapeTable();
textHeight = rec.textHeight;
@@ -381,7 +450,7 @@ public abstract class TextTag extends CharacterTag implements DrawableTag {
ExportRectangle result = null;
for (TEXTRECORD rec : textRecords) {
if (rec.styleFlagsHasFont) {
font = (FontTag) swf.getCharacter(rec.fontId);
font = swf.getFont(rec.fontId);
glyphs = font == null ? null : font.getGlyphShapeTable();
textHeight = rec.textHeight;
}
@@ -472,7 +541,7 @@ public abstract class TextTag extends CharacterTag implements DrawableTag {
}
}
if (rec.styleFlagsHasFont) {
font = (FontTag) swf.getCharacter(rec.fontId);
font = swf.getFont(rec.fontId);
fontId = rec.fontId;
glyphs = font.getGlyphShapeTable();
textHeight = rec.textHeight;
@@ -518,7 +587,7 @@ public abstract class TextTag extends CharacterTag implements DrawableTag {
}
}
if (rec.styleFlagsHasFont) {
font = (FontTag) swf.getCharacter(rec.fontId);
font = swf.getFont(rec.fontId);
glyphs = font.getGlyphShapeTable();
textHeight = rec.textHeight;
}
@@ -1282,7 +1282,7 @@ public class XFLConverter {
MATRIX matrix = rec.placeMatrix;
String recCharStr;
if (character instanceof TextTag) {
recCharStr = convertText(null, tags, (TextTag) character, matrix, filters, null);
recCharStr = convertText(null, (TextTag) character, matrix, filters, null);
} else if (character instanceof DefineVideoStreamTag) {
recCharStr = convertVideoInstance(null, matrix, (DefineVideoStreamTag) character, null);
} else {
@@ -1904,7 +1904,7 @@ public class XFLConverter {
} else {
shapeTween = false;
if (character instanceof TextTag) {
elements += convertText(instanceName, tags, (TextTag) character, matrix, filters, clipActions);
elements += convertText(instanceName, (TextTag) character, matrix, filters, clipActions);
} else if (character instanceof DefineVideoStreamTag) {
elements += convertVideoInstance(instanceName, matrix, (DefineVideoStreamTag) character, clipActions);
} else {
@@ -2332,7 +2332,7 @@ public class XFLConverter {
return ret;
}
public static String convertText(String instanceName, List<Tag> tags, TextTag tag, MATRIX m, List<FILTER> filters, CLIPACTIONS clipActions) {
public static String convertText(String instanceName, TextTag tag, MATRIX m, List<FILTER> filters, CLIPACTIONS clipActions) {
StringBuilder ret = new StringBuilder();
if (m == null) {
@@ -2349,7 +2349,8 @@ public class XFLConverter {
filterStr += "</filters>";
}
for (Tag t : tags) {
SWF swf = tag.getSwf();
for (Tag t : swf.tags) {
if (t instanceof CSMTextSettingsTag) {
CSMTextSettingsTag c = (CSMTextSettingsTag) t;
if (c.textID == tag.getCharacterId()) {
@@ -2358,6 +2359,7 @@ public class XFLConverter {
}
}
}
String fontRenderingMode = "standard";
String antiAlias = "";
if (csmts != null) {
@@ -2386,19 +2388,12 @@ public class XFLConverter {
textRecords = ((DefineText2Tag) tag).textRecords;
}
looprec:
for (TEXTRECORD rec : textRecords) {
if (rec.styleFlagsHasFont) {
for (Tag t : tags) {
if (t instanceof FontTag) {
FontTag ft = (FontTag) t;
if (ft.getFontId() == rec.fontId) {
if (ft.isSmall()) {
fontRenderingMode = "bitmap";
break looprec;
}
}
}
FontTag ft = swf.getFont(rec.fontId);
if (ft != null && ft.isSmall()) {
fontRenderingMode = "bitmap";
break;
}
}
}
@@ -2412,7 +2407,7 @@ public class XFLConverter {
ret.append(" instanceName=\"").append(xmlString(instanceName)).append("\"");
}
ret.append(antiAlias);
Map<String, Object> attrs = TextTag.getTextRecordsAttributes(textRecords, tags);
Map<String, Object> attrs = TextTag.getTextRecordsAttributes(textRecords, swf);
ret.append(" width=\"").append(tag.getBounds().getWidth() / 2).append("\" height=\"").append(tag.getBounds().getHeight()).append("\" autoExpand=\"true\" isSelectable=\"false\">");
ret.append(matStr);
@@ -2444,13 +2439,8 @@ public class XFLConverter {
fontId = rec.fontId;
fontName = null;
textHeight = rec.textHeight;
font = null;
for (Tag t : tags) {
if (t instanceof FontTag) {
if (((FontTag) t).getFontId() == fontId) {
font = (FontTag) t;
}
}
font = swf.getFont(fontId);
for (Tag t : swf.tags) {
if (t instanceof DefineFontNameTag) {
if (((DefineFontNameTag) t).fontId == fontId) {
fontName = ((DefineFontNameTag) t).fontName;
@@ -2506,16 +2496,9 @@ public class XFLConverter {
} else if (tag instanceof DefineEditTextTag) {
DefineEditTextTag det = (DefineEditTextTag) tag;
String tagName;
for (Tag t : tags) {
if (t instanceof FontTag) {
FontTag ft = (FontTag) t;
if (ft.getFontId() == det.fontId) {
if (ft.isSmall()) {
fontRenderingMode = "bitmap";
break;
}
}
}
FontTag ft = swf.getFont(det.fontId);
if (ft != null && ft.isSmall()) {
fontRenderingMode = "bitmap";
}
if (!det.useOutlines) {
fontRenderingMode = "device";
@@ -2579,7 +2562,7 @@ public class XFLConverter {
}
if (det.html) {
ret.append(convertHTMLText(tags, det, txt));
ret.append(convertHTMLText(swf.tags, det, txt));
} else {
ret.append("<DOMTextRun>");
ret.append("<characters>").append(xmlString(txt)).append("</characters>");
@@ -2598,18 +2581,12 @@ public class XFLConverter {
}
if (det.hasFont) {
String fontName = null;
FontTag ft = null;
for (Tag u : tags) {
for (Tag u : swf.tags) {
if (u instanceof DefineFontNameTag) {
if (((DefineFontNameTag) u).fontId == det.fontId) {
fontName = ((DefineFontNameTag) u).fontName;
}
}
if (u instanceof FontTag) {
if (((FontTag) u).getFontId() == det.fontId) {
ft = (FontTag) u;
}
}
if (fontName != null && ft != null) {
break;
}