From c7e5aa9607f2f664edde53976a6c3b04964b9dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Mon, 6 Apr 2026 17:13:04 +0200 Subject: [PATCH] chore: fix calculating text bounds on DefineEditText (#2383) --- .../flash/tags/DefineEditTextTag.java | 6 +- .../flash/tags/base/StaticTextTag.java | 2 +- .../decompiler/flash/tags/base/TextTag.java | 78 +++++++++++++------ .../tags/converters/TextTypeConverter.java | 9 ++- 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 07e2fc4c9..a9ccad1b9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -213,7 +213,7 @@ public class DefineEditTextTag extends TextTag { */ public DefineEditTextTag(SWFInputStream sis, ByteArrayRange data) throws IOException { super(sis.getSwf(), ID, NAME, data); - readData(sis, data, 0, false, false, false); + readData(sis, data, 0, false, false, false); } @Override @@ -924,7 +924,7 @@ public class DefineEditTextTag extends TextTag { String text = initialText.replace("\\", "\\\\").replace("[", "\\[").replace("]", "\\]"); writer.hilightSpecial(text, HighlightSpecialType.TEXT); } - writer.finishHilights(); + writer.finishHilights(); return new HighlightedText(writer); } @@ -1642,7 +1642,7 @@ public class DefineEditTextTag extends TextTag { @Override public ExportRectangle calculateTextBounds() { - return null; + return calculateTextBounds(swf, this, getTextRecords(swf, new HashMap<>()), new MATRIX()); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java index 99957b654..c6e13ba9f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java @@ -248,7 +248,7 @@ public abstract class StaticTextTag extends TextTag { @Override public ExportRectangle calculateTextBounds() { - return calculateTextBounds(swf, textRecords, getTextMatrix()); + return calculateTextBounds(swf, this, textRecords, getTextMatrix()); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java index 4dd40bc1d..b4d5835be 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java @@ -30,6 +30,7 @@ import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; import com.jpexs.decompiler.flash.helpers.HighlightedText; import com.jpexs.decompiler.flash.importers.TextImportResizeTextBoundsMode; +import com.jpexs.decompiler.flash.tags.DefineEditTextTag; import com.jpexs.decompiler.flash.tags.text.JustifyAlignGlyphEntry; import com.jpexs.decompiler.flash.tags.text.TextAlign; import com.jpexs.decompiler.flash.tags.text.TextParseException; @@ -836,11 +837,12 @@ public abstract class TextTag extends DrawableTag { /** * Calculates text bounds. * @param swf SWF + * @param tag Text tag * @param textRecords Text records * @param textMatrix Text matrix * @return Text bounds */ - public static ExportRectangle calculateTextBounds(SWF swf, List textRecords, MATRIX textMatrix) { + public static ExportRectangle calculateTextBounds(SWF swf, TextTag tag, List textRecords, MATRIX textMatrix) { FontTag font = null; int textHeight = 12; int x = 0; @@ -861,39 +863,65 @@ public abstract class TextTag extends DrawableTag { } double rat = textHeight / 1024.0 / (font == null ? 1 : font.getDivider()); - - for (GLYPHENTRY entry : rec.glyphEntries) { + + int leading = 0; + + if (font.hasLayout()) { + leading = font.getLeading(); + } + if (tag instanceof DefineEditTextTag) { + DefineEditTextTag det = (DefineEditTextTag) tag; + if (det.hasLayout) { + leading = (int) Math.round(det.leading / rat); + } + } + for (GLYPHENTRY entry : rec.glyphEntries) { Matrix mat = new Matrix(); - mat = mat.concatenate(new Matrix(textMatrix)); - Matrix matTr = Matrix.getTranslateInstance(x, y); - mat = mat.concatenate(matTr); - mat = mat.concatenate(Matrix.getScaleInstance(rat)); + mat = mat.preConcatenate(new Matrix(textMatrix)); + mat = mat.preConcatenate(Matrix.getScaleInstance(rat)); + mat = mat.preConcatenate(Matrix.getTranslateInstance(x, y)); + if (entry.glyphIndex != -1 && glyphs != null) { - // shapeNum: 1 - SHAPE shape = glyphs.get(entry.glyphIndex); - RECT glyphBounds = shape.getBounds(1); - int glyphWidth = glyphBounds.getWidth(); - int glyphHeight = glyphBounds.getHeight(); - glyphBounds.Xmin -= glyphWidth / 2; - glyphBounds.Ymin -= glyphHeight / 2; - glyphBounds.Xmax += glyphWidth; - glyphBounds.Ymax += glyphHeight; - if (glyphBounds.Xmax > glyphBounds.Xmin && glyphBounds.Ymax > glyphBounds.Ymin) { - ExportRectangle rect = mat.transform(new ExportRectangle(glyphBounds)); + SHAPE shape = glyphs.get(entry.glyphIndex); + + ExportRectangle glyphBounds = new ExportRectangle(shape.getBounds(1)); // shapeNum: 1 + + if (font.hasLayout()) { + glyphBounds = new ExportRectangle(0, -font.getAscent(), entry.glyphAdvance / rat, font.getDescent() + leading); + } else { + double glyphWidth = glyphBounds.getWidth(); + double glyphHeight = glyphBounds.getHeight(); + glyphBounds.xMin -= glyphWidth / 2; + glyphBounds.yMin -= glyphHeight / 2; + glyphBounds.xMax += glyphWidth; + glyphBounds.yMax += glyphHeight; + } + if (glyphBounds.xMax > glyphBounds.xMin && glyphBounds.yMax > glyphBounds.yMin) { + ExportRectangle rect = mat.transform(glyphBounds); + if (result == null) { - result = rect; - } else { - result.xMin = Math.min(result.xMin, rect.xMin); - result.yMin = Math.min(result.yMin, rect.yMin); - result.xMax = Math.max(result.xMax, rect.xMax); - result.yMax = Math.max(result.yMax, rect.yMax); + result = new ExportRectangle(Double.MAX_VALUE, Double.MAX_VALUE, -Double.MAX_VALUE, -Double.MAX_VALUE); } + + result.xMin = Math.min(result.xMin, Math.round(rect.xMin)); + result.yMin = Math.min(result.yMin, Math.round(rect.yMin)); + result.xMax = Math.max(result.xMax, Math.round(rect.xMax)); + result.yMax = Math.max(result.yMax, Math.round(rect.yMax)); } x += entry.glyphAdvance; - } + } } } + if (result != null) { + if (tag instanceof DefineEditTextTag) { + //Probably space for the border rect + result.xMin -= 2 * SWF.unitDivisor; + result.yMin -= 2 * SWF.unitDivisor; + result.xMax += 2 * SWF.unitDivisor; + result.yMax += 2 * SWF.unitDivisor; + } + } return result; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/converters/TextTypeConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/converters/TextTypeConverter.java index ebac5777c..3ac288466 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/converters/TextTypeConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/converters/TextTypeConverter.java @@ -1,6 +1,7 @@ package com.jpexs.decompiler.flash.tags.converters; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; import com.jpexs.decompiler.flash.tags.DefineEditTextTag; import com.jpexs.decompiler.flash.tags.DefineText2Tag; import com.jpexs.decompiler.flash.tags.DefineTextTag; @@ -109,8 +110,9 @@ public class TextTypeConverter { } } ret.textRecords = records; - ret.textBounds = tag.getBounds(); - ret.textMatrix = new MATRIX(); + ret.textMatrix = new MATRIX(); + ExportRectangle bounds = ret.calculateTextBounds(); + ret.textBounds = new RECT((int) Math.round(bounds.xMin), (int) Math.round(bounds.xMax), (int) Math.round(bounds.yMin), (int) Math.round(bounds.yMax)); return ret; } @@ -223,6 +225,9 @@ public class TextTypeConverter { det.html = true; det.hasText = true; det.initialText = writer.toString(); + + ExportRectangle bounds = det.calculateTextBounds(); + det.bounds = new RECT((int) Math.round(bounds.xMin), (int) Math.round(bounds.xMax), (int) Math.round(bounds.yMin), (int) Math.round(bounds.yMax)); return det; }