From a3ac87a13684007d11bb77cb2f395a4b8b568104 Mon Sep 17 00:00:00 2001 From: Honfika Date: Sat, 1 Mar 2014 23:40:12 +0100 Subject: [PATCH] basic multiline text support (wordwrap is not supported yet) --- .../flash/tags/DefineEditTextTag.java | 170 +++++++++++------- .../flash/types/ColorTransform.java | 6 + 2 files changed, 115 insertions(+), 61 deletions(-) diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 4e1250b96..009100391 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -245,7 +245,10 @@ public class DefineEditTextTag extends TextTag implements DrawableTag { styles.add(style); break; case "br": - // todo + CharacterWithStyle cs = new CharacterWithStyle(); + cs.character = '\n'; + cs.style = style; + ret.add(cs); break; } //ret = entitiesReplace(ret); @@ -260,6 +263,13 @@ public class DefineEditTextTag extends TextTag implements DrawableTag { case "font": styles.pop(); break; + case "p": + TextStyle style = styles.peek(); + CharacterWithStyle cs = new CharacterWithStyle(); + cs.character = '\n'; + cs.style = style; + ret.add(cs); + break; } } @@ -738,78 +748,105 @@ public class DefineEditTextTag extends TextTag implements DrawableTag { } } if (hasText) { - List textRecords = new ArrayList<>(); - TEXTRECORD tr = null; + List> paragraphs = new ArrayList<>(); + List textRecords = new ArrayList<>(); + paragraphs.add(textRecords); + SameStyleTextRecord tr = null; List txt = getTextWithStyle(); - List glyphEntries = new ArrayList<>(); - int width = 0; TextStyle lastStyle = null; for (int i = 0; i < txt.size(); i++) { CharacterWithStyle cs = txt.get(i); - if (cs.style != lastStyle) { - if (tr != null) { - tr.glyphEntries = glyphEntries.toArray(new GLYPHENTRY[glyphEntries.size()]); - textRecords.add(tr); - glyphEntries.clear(); - tr = null; - } - tr = new TEXTRECORD(); - tr.styleFlagsHasFont = true; - tr.fontId = fontId; - tr.textHeight = fontHeight; - tr.styleFlagsHasYOffset = true; - tr.yOffset = fontHeight; - if (cs.style.textColor != null) { - tr.styleFlagsHasColor = true; - tr.textColorA = cs.style.textColor; - } - lastStyle = cs.style; - } char c = cs.character; - Character nextChar = null; - if (i + 1 < txt.size()) { - nextChar = txt.get(i + 1).character; - } - int advance; - GLYPHENTRY ge = new GLYPHENTRY(); - ge.glyphIndex = font.charToGlyph(tags, c); - if (font.hasLayout()) { - int kerningAdjustment = 0; - if (nextChar != null) { - kerningAdjustment = font.getGlyphKerningAdjustment(tags, ge.glyphIndex, font.charToGlyph(tags, nextChar)); - kerningAdjustment /= font.getDivider(); + if (c != '\n') { + if (cs.style != lastStyle) { + lastStyle = cs.style; + tr = new SameStyleTextRecord(); + tr.style = lastStyle; + textRecords.add(tr); } - advance = (int) Math.round(font.getDivider() * Math.round((double) lastStyle.fontHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment) / (font.getDivider() * 1024.0))); + Character nextChar = null; + if (i + 1 < txt.size()) { + nextChar = txt.get(i + 1).character; + } + int advance; + GLYPHENTRY ge = new GLYPHENTRY(); + ge.glyphIndex = font.charToGlyph(tags, c); + if (font.hasLayout()) { + int kerningAdjustment = 0; + if (nextChar != null) { + kerningAdjustment = font.getGlyphKerningAdjustment(tags, ge.glyphIndex, font.charToGlyph(tags, nextChar)); + kerningAdjustment /= font.getDivider(); + } + advance = (int) Math.round(font.getDivider() * Math.round((double) lastStyle.fontHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment) / (font.getDivider() * 1024.0))); + } else { + String fontName = FontTag.defaultFontName; + advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), (int) (lastStyle.fontHeight / SWF.unitDivisor), c, nextChar)); + } + ge.glyphAdvance = advance; + tr.glyphEntries.add(ge); } else { - String fontName = FontTag.defaultFontName; - advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), (int) (lastStyle.fontHeight / SWF.unitDivisor), c, nextChar)); + if (multiline) { + textRecords = new ArrayList<>(); + lastStyle = null; + tr = null; + paragraphs.add(textRecords); + } } - ge.glyphAdvance = advance; - glyphEntries.add(ge); - width += advance; } - if (tr != null && glyphEntries.size() > 0) { - tr.glyphEntries = glyphEntries.toArray(new GLYPHENTRY[glyphEntries.size()]); - textRecords.add(tr); - } - switch (align) { - case 1: // right - for (TEXTRECORD tr1 : textRecords) { - tr1.styleFlagsHasXOffset = true; - tr1.xOffset += bounds.getWidth() - width; + List allTextRecords = new ArrayList<>(); + int yOffset = 0; + for (List paragraph : paragraphs) { + yOffset += fontHeight; + int width = 0; + for (SameStyleTextRecord tr1 : paragraph) { + int trWidth = 0; + for (GLYPHENTRY ge : tr1.glyphEntries) { + trWidth += ge.glyphAdvance; } - break; - case 2: // center - for (TEXTRECORD tr1 : textRecords) { - tr1.styleFlagsHasXOffset = true; - tr1.xOffset = (bounds.getWidth() - width) / 2; + tr1.width = trWidth; + width += trWidth; + } + int alignOffset = 0; + switch (align) { + case 0: // left + alignOffset = 0; + break; + case 1: // right + alignOffset = bounds.getWidth() - width; + break; + case 2: // center + alignOffset = (bounds.getWidth() - width) / 2; + break; + case 3: // justify + // todo; + break; + } + for (SameStyleTextRecord tr1 : paragraph) { + tr1.xOffset = alignOffset; + alignOffset += tr1.width; + } + for (SameStyleTextRecord tr1 : paragraph) { + TEXTRECORD tr2 = new TEXTRECORD(); + tr2.styleFlagsHasFont = true; + tr2.fontId = fontId; + tr2.textHeight = fontHeight; + if (tr1.style.textColor != null) { + tr2.styleFlagsHasColor = true; + tr2.textColorA = tr1.style.textColor; } - break; - case 3: // justify - // todo; - break; + // always add xOffset, because no xOffset and 0 xOffset is diffrent in text rendering + tr2.styleFlagsHasXOffset = true; + tr2.xOffset = tr1.xOffset; + if (yOffset != 0) { + tr2.styleFlagsHasYOffset = true; + tr2.yOffset = yOffset; + } + tr2.glyphEntries = tr1.glyphEntries.toArray(new GLYPHENTRY[tr1.glyphEntries.size()]); + allTextRecords.add(tr2); + } } - staticTextToImage(swf, characters, textRecords, 2, image, getTextMatrix(), transformation, colorTransform); + + staticTextToImage(swf, characters, allTextRecords, 2, image, getTextMatrix(), transformation, colorTransform); } } @@ -853,4 +890,15 @@ public class DefineEditTextTag extends TextTag implements DrawableTag { public TextStyle style; } + + private class SameStyleTextRecord { + + public TextStyle style; + + public int xOffset; + + public int width; + + public List glyphEntries = new ArrayList<>(); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/ColorTransform.java b/trunk/src/com/jpexs/decompiler/flash/types/ColorTransform.java index bd4d02f31..46eec9471 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/ColorTransform.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/ColorTransform.java @@ -43,10 +43,16 @@ public class ColorTransform implements Serializable { } public RGB apply(RGB color) { + if (color == null) { + return null; + } return new RGBA(Filtering.colorEffect(color.toColor(), getRedAdd(), getGreenAdd(), getBlueAdd(), getAlphaAdd(), getRedMulti(), getGreenMulti(), getBlueMulti(), getAlphaMulti())); } public RGBA apply(RGBA color) { + if (color == null) { + return null; + } return new RGBA(Filtering.colorEffect(color.toColor(), getRedAdd(), getGreenAdd(), getBlueAdd(), getAlphaAdd(), getRedMulti(), getGreenMulti(), getBlueMulti(), getAlphaMulti())); }