chore: fix calculating text bounds on DefineEditText (#2383)

This commit is contained in:
Jindra Petřík
2026-04-06 17:13:04 +02:00
parent 8d7757a53e
commit c7e5aa9607
4 changed files with 64 additions and 31 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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<TEXTRECORD> textRecords, MATRIX textMatrix) {
public static ExportRectangle calculateTextBounds(SWF swf, TextTag tag, List<TEXTRECORD> 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;
}

View File

@@ -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;
}